amsn-0.98.9/0000755000175000017500000000000011757711723012404 5ustar billiobbilliobamsn-0.98.9/langlist0000644000175000017500000001714211456526346014152 0ustar billiobbilliob al albanian (shqip) 1.11 iso8859-1 ar Arabic (عربي) 1.0 utf-8 ast Asturian 1.3 utf-8 eu Basque (euskera) 1.37 iso8859-1 bn Bengali (বাংলা) 1.3 utf-8 bs Bosnian (Bosanski) 1.3 utf-8 bg Bulgarian 1.1 cp1251 ca Catalan-Valencian (Català-Valencià) 1.123 iso8859-1 cs Cesky 1.13 iso8859-2 zh-CN Chinese - Simplified (简体中文) 1.2 gb18030 zh-TW Chinese - Taiwanese (繁體中文) 1.12 utf-8 da Danish (dansk) 1.46 iso8859-1 nl Dutch (Nederlands) 1.137 iso8859-1 ei Eivissenc 1.1 iso8859-1 en English 1.372 iso8859-1 eo Esperanto 1.7 utf-8 ee Estonian (eesti keel) 1.41 utf-8 fi Finnish (suomi) 1.10 iso8859-1 fr French - France (français) 1.172 iso8859-1 fr_CA French - Canadian 1.8 iso8859-1 fri Frisian (Frysk) 1.17 iso8859-1 fur Friulan (Furlan) 1.4 iso8859-1 glg Galician (Galego) 1.6 iso8859-1 de German (Deutsch) 1.52 iso8859-15 el Greek (ελληνικά) 1.16 utf-8 gr2 Greeklish 1.8 iso8859-1 hu Hungarian (magyar) 1.23 utf-8 id Indonesian (Bahasa Indonesia) 1.50 iso8859-1 is Icelandic (Íslenska) 1.10 iso8859-1 it Italian (italiano) 1.69 iso8859-1 ja Japanese (日本語) 1.2 utf-8 ko Korean (한국어) 1.0 utf-8 ku Kurdish (Kurdî) 1.0 utf-8 lt Lithuanian (lietuvių) 1.0 utf-8 mk Macedonian (Македонски) 1.14 utf-8 mn Mongolian (Монгол) 1.9 utf-8 no Norwegian (Norsk) 1.52 iso8859-1 oc Occitan 1.0 utf-8 pl Polish (polski) 1.7 iso8859-2 pt Portuguese - Portugal (português) 1.63 utf-8 pt_BR Portuguese - Brazil 1.36 iso8859-1 ro Romanian (Limba Română) 1.38 iso8859-2 ru Russian (Русский язык) 1.20 utf-8 sk Slovak (slovenčina) 1.11 iso8859-1 sl Slovenian (slovenščina) 1.43 iso8859-2 af South African 1.6 iso8859-1 es Spanish (Español) 1.252 utf-8 sr Serbian (Српски) 1.12 iso8859-5 sv Swedish (svenska) 1.18 iso8859-1 swa Swahili (Kiswahili) 1.19 iso8859-1 ta Tamil (தமிழ்) 1.5 iso8859-1 th Thai (ไทย) 1.0 utf-8 tr Turkish (Türkçe) 1.62 iso8859-9 ca_VC Valencian-Catalan (Valencià - Català) 1.2 iso8859-1 cy Welsh (Cymraeg) 1.11 utf-8 mt Maltese 0.1 utf-8 vn Vietnamese (tiếng Việt) 0.1 utf-8 amsn-0.98.9/remote.tcl0000644000175000017500000002265211012706230014367 0ustar billiobbilliob######################################################### ### remote.tcl v 1.0 2003/05/22 KaKaRoTo ######################################################### ::Version::setSubversionId {$Id: remote.tcl 9886 2008-05-15 01:06:32Z kakaroto $} if { $initialize_amsn == 1 } { global remote_port remote_auth remote_sock_lock remote_sock set remote_port 0 set remote_auth 0 set remote_sock_lock 0 set remote_sock 0 set remote_authtimer 0 } proc remote_check_online { } { if { [::MSN::myStatusIs] != "FLN" } { write_remote "[trans connected]..." return } else { after 1000 "remote_check_online" } } proc remote_touchauthtimer {} { global remote_authtimer set remote_authtimer 0 } namespace eval ::remote { # connect # connects you to your account # proc connect { } { if { [catch { ::MSN::connect } res] } { write_remote "[trans connecterror]" } else { write_remote "[trans connecting] ..." after 1000 "remote_check_online" } } # logout # logs you out from the current session # proc logout { } { write_remote "[trans logout]" preLogout "::MSN::logout" 1 } # help # prints the help message from the remote.help file # proc help { } { set fd [open "remote.help" r] set printhelp [read $fd] close $fd write_remote "$printhelp" } # online # Shows list of users connected # proc online { } { foreach username [::MSN::getList FL] { set state_code [::abook::getVolatileData $username state] if { $state_code !="FLN" } { write_remote "$username - [::abook::getNick $username] --- [trans status] : [trans [::MSN::stateToDescription $state_code]]" } } } proc status { } { set nick [::abook::getPersonal MFN] write_remote "[trans nick]: $nick" if {[ ::config::getKey protocol] >= 11 } { set psm [::abook::getPersonal PSM] write_remote "[trans PSM]: $psm" } getstate } proc getstate { } { set my_state [::MSN::stateToDescription [::MSN::myStatusIs]] write_remote "Your state is currently on : $my_state" } proc setstate { {state ""} } { if { "$state" == "" } { write_remote "Possible status are :" write_remote " online, away, busy, noactivity, brb, onphone, lunch, appearoffline" return } set state [string tolower $state] if { "$state" == "online" } { ChCustomState NLN } elseif { "$state" == "away" } { ChCustomState AWY } elseif { "$state" == "busy" } { ChCustomState BSY } elseif { "$state" == "noactivity" } { ChCustomState IDL } elseif { "$state" == "brb" } { ChCustomState BRB } elseif { "$state" == "onphone" } { ChCustomState PHN } elseif { "$state" == "lunch" } { ChCustomState LUN } elseif { "$state" == "appearoffline" } { ChCustomState HDN } else { write_remote "Invalid state" error return } write_remote "State changed" } proc listcustomstates { } { set numstates [StateList size] if {$numstates > 0} { write_remote "ID\tState name" for { set stateid 0 } { $stateid < $numstates } { incr stateid } { set state [StateList get $stateid] write_remote "$stateid\t [lindex $state 0]" } } else { write_remote "No custom states defined" } } proc setcustomstate { state } { set numstates [StateList size] if { [string is digit $state] != 1 || $state < 0 || $state >= $numstates } { write_remote "Invalid state" } else { ChCustomState $state } } proc setpsm { args } { set psm [string map { \\\; \; \\\" \" \\\[ \[ \\\] \] \\\: \: \\\\ \\ \\\* \* \\\? \?} [join $args]] ::MSN::changePSM "$psm" write_remote "PSM set to : $psm" } proc setnick { args } { set nickname [string map { \\\; \; \\\" \" \\\[ \[ \\\] \] \\\: \: \\\\ \\ \\\* \* \\\? \?} [join $args]] if {$nickname != ""} { ::MSN::changeName "$nickname" write_remote "New nick set to : $nickname" } else { write_remote "New nick not entered" } } proc amsn_close { } { exit } proc whois { user } { set found 0 foreach username [::MSN::getList FL] { if { "[::abook::getNick $username]" == "$user" } { write_remote "$user is : $username" set found 1 break } } if { $found == 0 } { write_remote "$user was not found in your contact list..." error } } proc whatis { user } { set found 0 if { [string match "*@*" $user] == 0 } { set user [split $user "@"] set user "[lindex $user 0]@hotmail.com" set user [string tolower $user] } foreach username [::MSN::getList FL] { if { "$username" == "$user" } { write_remote "$user is known as : [::abook::getNick $user]" set found 1 break } } if { $found == 0 } { write_remote "$user was not found in your contact list..." error } } # msg { args } # sends a message to a user # proc msg { args } { global userchatto if { [info exists userchatto] } { set user "$userchatto" set message [string map { \\\; \; \\\" \" \\\[ \[ \\\] \] \\\: \: \\\\ \\ \\\* \* \\\? \?} [join $args]] } else { # This is to skip all the spaces that could be put before the user, like for example "msg user1 my msg". # with the [split] we would get {msg {} {} {} {} {} {} user1 my msg} set idx 0 set user {} while { [string length $user] <= 0 } { set user [lindex $args $idx] incr idx } set message [string map { \\\; \; \\\" \" \\\[ \[ \\\] \] \\\: \: \\\\ \\ \\\* \* \\\? \?} [join [lrange $args $idx end]]] } set message [string map { \{ "" \} ""} $message] if { [string match "*@*" $user] == 0 } { set user [split $user "@"] set user "[lindex $user 0]@hotmail.com" } set lowuser [string tolower $user] set win_name [::ChatWindow::For $lowuser] if { $win_name == 0 } { ::amsn::chatUser "$user" while { [set win_name [::ChatWindow::For $lowuser]] == 0 } { } } #set input "${win_name}.f.bottom.in.input" set input [text ${win_name}.tmp] $input insert end "${message}" ::amsn::MessageSend $win_name $input destroy $input } proc chatto { user } { global userchatto if { [string match "*@*" $user] == 0 } { set user [split $user "@"] set user "[lindex $user 0]@hotmail.com" } set userchatto "$user" } proc endchat { } { global userchatto if { [info exists userchatto] } { unset userchatto } } } proc write_remote { dataout {colour "normal"} } { global remote_sock #set dataout [string map [list "\n" " $colour\n"] $dataout] catch {puts $remote_sock [list $dataout $colour]} } proc read_remote { command sock } { global remote_auth remote_sock if { ![::config::getKey enableremote]} { close $sock return } if { "$remote_sock" != "$sock" } { set remote_temp_sock $remote_sock init_remote $sock if { $remote_auth == 1 } { write_remote "Remote controlling is already active" init_remote $remote_temp_sock return 0 } } if {$command != ""} { #AIM-FIX: Make command a real quoted list, or it will raise #errors when containing braces set command [split $command] if { $remote_auth == 0 } { authenticate "$command" "$sock" } elseif { [catch {eval "::remote::$command" } res] } { write_remote "[trans syntaxerror] : $res" error } } } proc md5keygen { } { set key [expr rand()] set key [expr {$key * 1000000}] return "$key" } proc authenticate { command sock } { global remotemd5key remote_auth remote_sock_lock remote_authtimer global userchatto if {$remote_authtimer} { after cancel [list remote_touchauthtimer] after 3000 [list remote_touchauthtimer] write_remote "wait" close $sock return } if { $command == "auth" } { set remotemd5key "[md5keygen]" write_remote "auth $remotemd5key" } elseif { [lindex $command 0] == "auth2" && [info exists remotemd5key] } { if { "[lindex $command 1]" == "[::md5::hmac $remotemd5key [list [::config::getKey remotepassword]]]" } { set remote_auth 1 set remote_sock_lock $sock catch { unset userchatto } write_remote "Authentication successfull" } else { set remote_authtimer 1 after 3000 [list remote_touchauthtimer] write_remote "Authentication failed" } unset remotemd5key } else { write_remote "[trans syntaxerror] : $command" error } } proc init_remote { sock } { global remote_sock set remote_sock $sock } proc close_remote { sock } { global remote_sock_lock remote_auth if { $remote_sock_lock == $sock } { set remote_auth 0 } } proc init_remote_DS { } { catch {socket -server new_remote_DS 63251} } proc new_remote_DS { sock addr port } { fileevent $sock readable "remote_DS_Hdl $sock" fconfigure $sock -buffering line } proc remote_DS_Hdl { sock } { set email [gets $sock] if {[eof $sock]} { catch {close $sock} } else { grep $email $sock } } proc grep { pattern sock } { global HOME2 set filename "[file join $HOME2 profiles]" if { [string match "*@*" $pattern] == 0 } { set pattern [split $pattern "@"] set pattern "[lindex $pattern 0]@hotmail.com" } if {([file readable "$filename"] != 0) && ([file isfile "$filename"] != 0)} { set file_id [open "$filename" r] gets $file_id tmp_data if {$tmp_data != "amsn_profiles_version 1"} { ;# config version not supported! puts $sock "versionerror" close $file_id return 0 } # Now add profiles from file to list while {[gets $file_id tmp_data] != "-1"} { set temp_data [split $tmp_data] if { [lindex $temp_data 0] == "$pattern" } { close $file_id puts $sock "[lindex $temp_data 1]" return 1 } } puts $sock "invalid" close $file_id return 0 } else { puts $sock "noexist" return 0 } } amsn-0.98.9/abook.tcl0000644000175000017500000021262311700163435014176 0ustar billiobbilliob# User Administration (Address Book data) # by: Alvaro Jose Iradier Muro # D�imo Emilio Grimaldo Tu�n #======================================================================= ::Version::setSubversionId {$Id: abook.tcl 12355 2012-01-01 23:07:09Z kakaroto $} ::snit::type Group { variable users {} option -name option -id method showInfo { } { status_log ---- status_log id:$options(-id) status_log name:$options(-name) status_log users:$users } method addUser { user } { llappend users $user } } namespace eval ::abook { #::abook namespace is used to store all information related to users #and contact lists. if { $initialize_amsn == 1 } { # # P R I V A T E # variable demographics; # Demographic Information about user #When set to 1, the information is in safe state and can be #saved to disk without breaking anything variable consistent 0 variable upnp # This list stores the names of the fields about the visual representation of the buddy. # When this fields gets changed, we fire an event to redraw that contact on our CL. variable VisualData [list nick abnick customnick customfnick cust_p4c_name customcolor customdp] global pgc pcc } ######################### # P U B L I C ######################### #An alias for "setContactData myself". Sets data for the "myself" user proc setPersonal { field value} { setContactData myself $field $value } #An alias for "getContactData myself". Gets data for the "myself" user proc getPersonal { field } { return [getContactData myself $field] } #TODO: Remove this proc getContact { email cdata } { upvar $cdata data set groupName [::groups::GetName [getContactData $email group]] set data(group) [urldecode $groupName] set data(handle) [urldecode [getVolatileData $email nick]] set data(PHH) [urldecode [getVolatileData $email PHH]] set data(PHW) [urldecode [getVolatileData $email PHW]] set data(PHM) [urldecode [getVolatileData $email PHM]] set data(MOB) [urldecode [getVolatileData $email MOB]] set data(available) "Y" } # Sends a message to the notification server with the # new set of phone numbers. Notice this can only be done # for the user and not for the buddies! # The value is urlencoded by this routine proc setPhone { item value } { switch $item { home { ::MSN::WriteSB ns PRP "PHH $value" } work { ::MSN::WriteSB ns PRP "PHW $value" } mobile { ::MSN::WriteSB ns PRP "PHM $value" } pager { ::MSN::WriteSB ns PRP "MOB $value" if { $value eq "Y" } { ::MSN::setClientCap paging } else { ::MSN::setClientCap paging 0 } ::MSN::changeStatus [::MSN::myStatusIs] } default { status_log "setPhone error, unknown $item $value\n" } } } # This information is sent to us during the initial connection # with the server. It comes in a MSG content "text/x-msmsgsprofile" # TODO: Change this to use setVolatileData to user myself proc setDemographics { cdata } { variable demographics upvar $cdata data array set demographics [array get data] set demographics(valid) Y after 0 {::abook::getIPConfig} } proc getDemographicField { field } { variable demographics if { [info exists demographics($field)]} { return $demographics($field) } else { return "" } } proc getDemographics { cdata } { variable demographics upvar $cdata d if {[info exists d(valid)]} { array set d [array get demographics] set d(valid) Y } else { set d(valid) N } } ################################################################################################################################ ################################################################################################################################ ################################################################################################################################ ############## MOVE ALL PROTOCOL/IP CHECK RELATED PROCEDURES OUT OF ABOOK!! ABOOK SHOULD CARE ONLY ABOUT ####################### ############## DATA STORAGE, NOT ABOUT SERVERS/IPS/CONNECTIONS OR WHATEVER !! ####################### proc OpenUPnPPort { port } { variable upnp if {![catch {package require gupnp}] } { proc ::gupnp::MappedExternalPort {protocol external_ip replaces_external_ip external_port local_ip local_port description} { status_log "UPnP MappedExternalPort ($description): $external_ip:$external_port --> $local_ip:$local_port ($protocol)" ::abook::MappedUPnpPort $external_ip $external_port $local_ip $local_port } } else { status_log "UPnP package unavailable" red return } # In case we already created a upnp port for this, then free it # We need a new object because if we changed network or we had upnp disabled # then we enabled it, it wouldn't work with an old upnp object, we must create # a new one CloseUPnPPort $port set local_ip [getLocalIP] if {$local_ip != "" } { set upnp($port) [::gupnp::New] status_log "Trying to open a UPnP port for $port with $upnp($port)" ::gupnp::AddPort $upnp($port) "TCP" $local_ip $port $port 0 "aMSN" } else { status_log "Can't open upnp port because we are not connected" } } proc CloseUPnPPort { port } { variable upnp if {[info exists upnp($port)] } { ::gupnp::RemovePort $upnp($port) "TCP" $port ::gupnp::Free $upnp($port) unset upnp($port) } } proc MappedUPnpPort {external_ip external_port local_ip local_port } { variable demographics set demographics(upnpnat) "true" set demographics(has_upnp) "true" } # This proc will configure all ip settings, get private ip, see if firewalled or not, and set netid proc getIPConfig { } { variable demographics status_log "Getting local IP\n" set demographics(localip) [getLocalIP] status_log "Finished\n" set demographics(upnpnat) "false" set demographics(has_upnp) "false" if { [getDemographicField localip] eq "" || [getDemographicField clientip] eq "" } { #Not connected set demographics(conntype) "" return } else { set demographics(conntype) [getConnectionType [getDemographicField localip] [getDemographicField clientip]] } if { $demographics(conntype) eq "Direct-Connect" || $demographics(conntype) eq "Firewall" } { set demographics(netid) 0 set demographics(upnpnat) "false" } else { set demographics(netid) [GetNetID [getDemographicField clientip]] # Used to test the upnp. if { [getFirewalled [::config::getKey initialftport]] eq "Direct-Connect" && [set demographics(upnpnat)] == "false"} { # If there is no upnp, but the connection succeeded, then we might have # opened our ports manually, in which case, consider us direct-connect set demographics(conntype) "Direct-Connect" } } set demographics(listening) [getListening [getDemographicField conntype]] } # This proc will get the localip (private ip, NAT or not) proc getLocalIP { } { set sk [ns cget -sock] if { $sk ne "" } { set ip "" catch { foreach ip [fconfigure $sk -sockname] {break} } return $ip } else { return "" } } # This will return the connection type : ip-restrict-nat, direct-connect or firewall proc getConnectionType { localip clientip } { if { $localip ne $clientip } { return "IP-Restrict-NAT" } else { return [getFirewalled [::config::getKey initialftport]] } } # This will create a server, and try to connect to it in order to see if firewalled or not proc getFirewalled { {port ""} } { global connection_success variable random_id set random_id [expr rand()] set random_id [expr {$random_id * 10000}] set random_id [expr {int($random_id)}] if { $port eq "" } { set port $::config(initialftport) } if { ![string is integer -strict $port] || $port < 0 || $port > 65535 } { status_log "Invalid port" red return "Firewall" } while { [catch {set sock [socket -server "abook::dummysocketserver" $port] } ] } { incr port } status_log "::abook::getFirewalled: Connecting to [getDemographicField clientip] port $port\n" blue OpenUPnPPort $port #Need this timeout thing to avoid the socket blocking... set connection_success -2 status_log "Connecting to http://firewall.amsn-project.net/check_connectivity.php?port=$port&id=$random_id" blue if { [catch { ::http::geturl "http://firewall.amsn-project.net/check_connectivity.php?port=$port&id=$random_id" -command "::abook::gotConnectivityReply" -timeout 9500 } res] } { after 500 [list set ::connection_success -1] status_log "::abook::getFirewalled failed: $res" red } after 6000 [list set ::connection_success -3] tkwait variable connection_success if { $connection_success == -1 } { status_log "::abook::getFirewalled: connection_success ($connection_success), trying old method\n" blue set connection_success -2 if {[catch {set clientsock [socket -async [getDemographicField clientip] $port]}] == 0} { fileevent $clientsock readable [list ::abook::connectionHandler $clientsock] after 1000 ::abook::connectionTimeout tkwait variable connection_success catch { close $clientsock } } } status_log "::abook::getFirewalled: connection_success ($connection_success)\n" blue catch {close $sock} CloseUPnPPort $port if { $connection_success == 1 } { return "Direct-Connect" } else { return "Firewall" } } proc gotConnectivityReply { token} { global connection_success if { [::http::status $token] ne "ok" || [::http::ncode $token ] != 200 } { set connection_success -1 status_log "::abook::gotConnectivityReply error : [http::status $token] - [::http::ncode $token]" green } ::http::cleanup $token } proc connectionTimeout {} { global connection_success status_log "::abook::connectionTimeout\n" if { $connection_success == -2 } { set connection_success -1 } else { set connection_success $connection_success } } proc connectionHandler { sock } { #CHECK FOR AN ERROR global connection_success after cancel ::abook::connectionTimeout fileevent $sock readable "" if { [fconfigure $sock -error] ne ""} { status_log "::abook::connectionHandler: connection failed\n" red set connection_success 0 } else { # TODO : We need to check here byte per byte because we might connect to an emule server for example which sends binary data # and the [gets] will be blocking until there is a newline in the data... which might never happen... # this will cause amsn to hang... gets $sock server_data if { [string first "AMSNPING" "$server_data"] == 0 } { status_log "::abook::connectionHandler: port in use by another application!\n" red set connection_success 0 } else { status_log "::abook::connectionHandler: connection succesful\n" green set connection_success 1 } } } proc getListening { conntype } { if {$conntype eq "Firewall" } { return "false" } elseif { $conntype eq "Direct-Connect" } { return "true" } else { return [abook::getDemographicField upnpnat] } } # This proc is a dummy socket server proc, because we need a command to be called which the client connects to the test server (if not firewalled) proc dummysocketserver { sock ip port } { global connection_success variable random_id if {[catch { #puts $sock "AMSNPING" if { [info exists random_id] } { puts $sock "AMSNPING${random_id}" } else { puts $sock "AMSNPING" } flush $sock close $sock set connection_success 1 status_log "::abook::dummysocketserver: Received connection on $sock" blue } res]} { status_log "::abook::dummysocketserver: Error writing to socket: $res\n" } } # This will transform the ip adress into a netID adress (which is the 32 bits unsigned integer represent the ip) proc GetNetID { ip } { set val 0 set inverted_ip "" foreach x [split $ip .] { set inverted_ip "${x} ${inverted_ip}" } foreach x $inverted_ip { set val [expr {($val << 8) | ($x & 0xff)}] } return [format %u $val] } ################################################################################################################################ ################################################################################################################################ ################################################################################################################################ #Clears all ::abook stored information proc clearData {} { variable users_data array unset users_data * variable users_volatile_data array unset users_volatile_data * unsetConsistent } #Sets some data to a user. #user_login: the user_login you want to set data to #field: the field you want to set #data: the data that will be contained in the given field proc setContactData { user_login field data } { global pgc variable users_data set field [string tolower $field] # There can't be double arrays, so users_data(user) is just a # list like {entry1 data1 entry2 data2 ...} if { [info exists users_data($user_login)] } { #We convert the list to an array, to make it easier array set user_data $users_data($user_login) } else { array set user_data [list] } # An event used by guicontactlist to know when a user changed his nick (or state) #if { [lsearch -exact $::abook::VisualData $field] > -1 } { # if { [info exists user_data($field)] && $user_data($field) ne $data } { # #puts stdout "ATTENTION! Visual Data has changed! Redraw CL! $field - $data" # ::Event::fireEvent contactDataChange abook $user_login # } elseif { ![info exists user_data($field)] && $data ne ""} { # #puts stdout "ATTENTION! Visual Data has changed! Redraw CL! $field - $data" # ::Event::fireEvent contactDataChange abook $user_login # } #} if { $data eq "" } { if { [info exists user_data($field)] } { unset user_data($field) } } else { set user_data($field) $data } if { $field eq "nick" || $field eq "abnick" || $field eq "mfn" || $field eq "psm" || $field eq "customnick" || $field eq "customfnick" } { set data [::smiley::parseMessageToList [list [ list "text" "$data" ]] 1] set evpar(variable) data set evpar(login) $user_login ::plugins::PostEvent parse_contact evpar ::abook::setVolatileData $user_login "parsed_$field" $data } set users_data($user_login) [array get user_data] #We make this to notify preferences > groups to be refreshed set pgc 1 } proc setContactForGuid { guid user_login } { variable guid_contact if { $user_login eq "" } { if { [info exists guid_contact($guid)] } { unset guid_contact($guid) } } else { set guid_contact($guid) $user_login } } proc getContactForGuid { guid } { variable guid_contact if { [info exists guid_contact($guid)] } { return $guid_contact($guid) } else { return "" } } proc setAtomicContactData { user_login fields_list data_list } { global pgc variable users_data set fields_list [string tolower $fields_list] if { [info exists users_data($user_login)] } { array set user_data $users_data($user_login) } else { array set user_data [list] } # This loop iterates over the lists of fields and data, so when it finds that one of # the fields has to do with visual information, it throws an event and breaks the loop foreach field $fields_list data $data_list { if { [lsearch -exact $::abook::VisualData $field] > -1 } { if { [info exists user_data($field)] && $user_data($field) ne $data } { #puts stdout "ATTENTION! Visual Data has changed! Redraw CL! $field - $data" ::Event::fireEvent contactDataChange abook $user_login break } elseif { ![info exists user_data($field)] && $data ne ""} { #puts stdout "ATTENTION! Visual Data has changed! Redraw CL! $field - $data" ::Event::fireEvent contactDataChange abook $user_login break } } } # This other loop iterates over the entire lists, replacing the value in user_data(array) # if needed. There are two different loops because this one cannot be broke. foreach field $fields_list data $data_list { if { $data eq "" } { if { [info exists user_data($field)] } { unset user_data($field) } } else { set user_data($field) $data } } set users_data($user_login) [array get user_data] set pgc 1 } #Sets some volatile data to a user. Volatile data won't be written to disk #user_login: the user_login you want to set data to #field: the field you want to set #data: the data that will be contained in the given field proc setVolatileData { user_login field data } { variable users_volatile_data set field [string tolower $field] if { [info exists users_volatile_data($user_login)] } { array set volatile_data $users_volatile_data($user_login) } else { array set volatile_data [list] } if { $data eq "" } { if { [info exists volatile_data($field)] } { unset volatile_data($field) } } else { set volatile_data($field) $data } if { $field eq "psm" } { set data [::smiley::parseMessageToList [list [ list "text" "$data" ]] 1] set evpar(variable) data set evpar(login) $user_login ::plugins::PostEvent parse_contact evpar set volatile_data(parsed_$field) $data } set users_volatile_data($user_login) [array get volatile_data] } #clears all volatile date of a user proc clearVolatileData { user_login } { variable users_volatile_data unset users_volatile_data($user_login) } #Returns some previously stored data from a user proc getContactData { user_login field {defaultval ""}} { variable users_data set field [string tolower $field] if { ![info exists users_data($user_login)] } { return $defaultval } array set user_data $users_data($user_login) if { ![info exists user_data($field)] } { return $defaultval } return $user_data($field) } #Returns some previously stored volatile data from a user proc getVolatileData { user_login field {defaultval ""}} { variable users_volatile_data set field [string tolower $field] if { ![info exists users_volatile_data($user_login)] } { return $defaultval } array set user_data $users_volatile_data($user_login) if { ![info exists user_data($field)] } { return $defaultval } return $user_data($field) } #Return a list of all stored contacts proc getAllContacts { } { variable users_data return [array names users_data] } proc setEndPoint {machineguid epname } { variable endpoints set endpoints($machineguid) $epname } proc getEndPoints { } { variable endpoints return [array names endpoints] } proc getEndPointName { machineguid } { variable endpoints if {[info exists endpoints($machineguid)] } { return [set endpoints($machineguid)] } else { return "" } } proc clearEndPoints { } { variable endpoints array unset endpoints } ########################################################################### # Auxiliary functions, macros, or shortcuts ########################################################################### proc getPassportfromContactguid { contactguid } { foreach contact [::abook::getAllContacts] { if { [::abook::getContactData $contact contactguid] eq $contactguid } { return $contact } } } proc lastSeen { } { foreach contact [::abook::getAllContacts] { set user_state_code [::abook::getVolatileData $contact state FLN] if {$user_state_code ne "FLN"} { ::abook::setContactData $contact last_seen [clock format [clock seconds] -format "%D - %H:%M:%S"] } } } proc CreateCopyMenu { w } { set menu $w.copy menu $menu -tearoff 0 -type normal $menu add command -label [trans copy] \ -command "::abook::copyFromText $w" return $menu } proc copyFromText { w } { set index [$w tag ranges sel] clipboard clear if { [llength $index] < 2 } { set index [list 0.0 end] } set dump [$w dump -text [lindex $index 0] [lindex $index 1]] foreach { text output index } $dump { clipboard append "$output" } } proc dateconvert {time} { set date [clock format [clock seconds] -format "%D"] if {$time eq ""} { return "" } else { set delm [string first " " $time] if { $delm == -1 } { set delm [string length $time]} if {![catch {clock scan [string range $time 0 $delm]}]} { #Checks if the time is today, and in this case puts today instead of the date if {[clock scan $date] == [clock scan [string range $time 0 $delm]]} { return "[trans today][string range $time $delm end]" #Checks if the time is yesterday, and in this case puts yesterday instead of the date } elseif { [expr { [clock scan $date] - [clock scan [string range $time 0 $delm]] }] == 86400} { return "[trans yesterday][string range $time $delm end]" } else { #set month [string range $time 0 1] #set day [string range $time 3 4] #set year [string range $time 6 7] #set end [string range $time 8 end] set dateoftime [string range $time 0 $delm] set timeTicks [clock scan $dateoftime] set month [clock format $timeTicks -format %m] set day [clock format $timeTicks -format %d] set year [clock format $timeTicks -format %Y] set end [string range $time $delm end] #Month/Day/Year if {[::config::getKey dateformat] eq "MDY"} { return $time #Day/Month/Year } elseif {[::config::getKey dateformat] eq "DMY"} { return "$day/$month/$year$end" #Year/Month/Day } elseif {[::config::getKey dateformat] eq "YMD"} { return "$year/$month/$day$end" } } } else { return $time } } } proc parseCurrentMedia {currentMedia} { if {$currentMedia eq ""} { return "" } set currentMedia [string map {"\\0" "\0"} $currentMedia] set infos [split $currentMedia "\0"] if {[lindex $infos 2] eq "0"} { return "" } if {[lindex $infos 1] eq "Music"} { set out [list [list "smiley" [::skin::loadPixmap note] "-"] [list "text" " "]] } else { set out [list [list "text" "- "]] } set pattern [lindex $infos 3] set nrParams [expr {[llength $infos] - 4}] set lstMap [list] for {set idx 0} {$idx < $nrParams} {incr idx} { lappend lstMap "\{$idx\}" lappend lstMap [lindex $infos [expr {$idx + 4}]] } lappend out [list "text" "[string map $lstMap $pattern]"] return $out } # Get PSM and currentMedia proc getpsmmedia { { user_login "" } { use_styled_psm 0}} { if { [::config::getKey protocol] < 11 } { return [list ]} set psmmedia [list ] if { $user_login eq "" } { set psm [::abook::getVolatileData myself parsed_psm] set currentMedia [::abook::parseCurrentMedia [::abook::getVolatileData myself currentMedia]] } else { set psm [::abook::getVolatileData $user_login parsed_psm] set currentMedia [::abook::parseCurrentMedia [::abook::getVolatileData $user_login currentMedia]] } if {$psm ne ""} { set psmmedia [concat $psmmedia $psm] } if {$currentMedia ne ""} { if { $psm ne ""} { lappend psmmedia [list "colour" "reset"] lappend psmmedia [list "font" "reset"] lappend psmmedia [list "text" " "] } set psmmedia [concat $psmmedia $currentMedia] } if { !$use_styled_psm } { set psmmedia [::abook::removeStyles $psmmedia] } return $psmmedia } #Returns the user nickname proc getNick { user_login {use_styled_nick 0}} { set nick [::abook::getVolatileData $user_login parsed_nick] if { $nick eq "" } { return [list [list "text" $user_login]] } if { !$use_styled_nick } { set nick [::abook::removeStyles $nick] } return $nick } #Parser to replace special characters and variables in the right way proc parseCustomNick { input nick user_login customnick {psm ""} } { #If there's no customnick set, default to user_login if { $customnick eq "" } { set customnick $user_login } #By default, quote backslashes, angle brackets and variables set input [string map { "\\" "\\\\" "\$" "\\\$" "\(" "\\\(" } $input] #Now, let's unquote the variables we want to replace set input [string map { "\\\$nick" "\${nick}" "\\\$user_login" "\${user_login}" "\\\$customnick" "\${customnick}" "\\\$psm" "\${psm}" } $input] #Return the custom nick, replacing backslashses and variables return [subst -nocommands $input] } #Parser to replace special characters and variables in the right way proc parseCustomNickStyled { input nick user_login customnick } { set psm [::abook::getpsmmedia $user_login 1] #If there's no customnick set, default to user_login if { [::abook::removeStyles $customnick] eq "" } { set customnick [list [list "text" "$user_login"]] } set user_login [list [list "text" "$user_login"]] set l $input set llength [llength $l] set listpos 0 set npos 0 #Keep searching until no matches while { $listpos < $llength } { if { ([lindex $l $listpos 0] ne "text") } { incr listpos continue } set txt [lindex $l $listpos 1] if { [set pos [string first "\$" $txt $npos]] == -1 } { set npos 0 incr listpos } else { #in case the $ isn't a matching $ we will search for the next in the same list item set npos [expr {$pos + 1}] foreach substitute { "\$nick" "\$user_login" "\$customnick" "\$psm" } { if { [string range $txt $pos [expr {$pos + [string length $substitute] - 1}]] eq $substitute } { set content [set [string range $substitute 1 end]] set p1 [string range $txt 0 [expr {$pos - 1}]] set p3 [string range $txt [expr {$pos + [string length $substitute]}] end] set l [lreplace $l $listpos $listpos] incr llength -1 if { $p1 ne "" } { set l [linsert $l $listpos [list text $p1]] incr llength 1 incr listpos 1 } foreach unit $content { set l [linsert $l $listpos $unit] incr listpos 1 incr llength 1 } if { $p3 ne "" } { set l [linsert $l $listpos [list text $p3]] incr llength 1 #We must parse p3 } #We will search from the begining of p3 set npos 0 break } } } } #Return the custom nick, replacing backslashses and variables return $l } #Returns the user nickname, or just email, or custom nick, #depending on configuration proc getDisplayNick { user_login {use_styled_nick 0}} { if { [::config::getKey emailsincontactlist] } { set out [list [list "text" $user_login]] } else { set nick [::abook::getNick $user_login 1] set customnick [::abook::getVolatileData $user_login parsed_customnick] set customnicktxt [::abook::removeStyles $customnick] set globalnicktxt [::abook::removeStyles $::globalnick] if { [::config::getKey globaloverride] == 0 } { if { $customnicktxt ne "" } { set out [parseCustomNickStyled $customnick $nick $user_login $customnick] } else { if { $globalnicktxt ne "" } { set out [parseCustomNickStyled $::globalnick $nick $user_login $customnick] } else { set out $nick } } } elseif { [::config::getKey globaloverride] == 1 } { if { $customnicktxt ne "" && $globalnicktxt eq "" } { set out [parseCustomNickStyled $customnick $nick $user_login $customnick] } elseif { $globalnicktxt ne "" } { set out [parseCustomNickStyled $::globalnick $nick $user_login $customnick] } else { set out $nick } } } if { !$use_styled_nick } { set out [::abook::removeStyles $out] } return $out } proc getKeepLogs { user_login } { if {[::abook::getContactData $user_login keeplogs] == 1 || ([::config::getKey keep_logs] && [::abook::getContactData $user_login keeplogs] != 0)} { return 1 } else { return 0 } } #Used to remove styles from the nickname/psm and returns full text proc removeStyles {list_styles} { set output "" foreach unit $list_styles { switch [lindex $unit 0] { "text" { # Store the text as a string append output [lindex $unit 1] } "smiley" { append output [lindex $unit 2] } "newline" { append output "\n" } "colour" - "font" - "bg" { } default { status_log "Unknown item in parsed nickname: $unit" } } } return $output } # Used to fetch the groups ID so that the caller can order by # group if needed. Returns -1 on error. # ::abook::getGroups my@passport.com : returns group ids proc getGroups {passport} { return [getContactData $passport group] } proc getGroupsname {passport} { set groups "" foreach gid [::abook::getGroups $passport] { set groups "$groups[::groups::GetName $gid], " } set groups [string range $groups 0 end-2] return $groups } proc addContactToGroup { email grId } { global pcc set groups [getContactData $email group] set idx [lsearch $groups $grId] if { $idx == -1 } { setContactData $email group [linsert $groups 0 $grId] } #we make this to notify preferences > groups to be refreshed set pcc 1 } proc emptyUserGroups { email } { global pcc setContactData $email group [list ] set pcc 1 } proc removeContactFromGroup { email grId } { global pcc set groups [getContactData $email group] set idx [lsearch $groups $grId] if { $idx != -1 } { #The last group -> we move to nogroup if { [llength $groups] == 1 } { setContactData $email group [lreplace $groups $idx $idx 0] } else { setContactData $email group [lreplace $groups $idx $idx] } } set pcc 1 } proc getLists {passport} { return [getContactData $passport lists] } proc addContactToList { email listId } { global pcc set lists [getContactData $email lists] set idx [lsearch $lists $listId] if { $idx == -1 } { setContactData $email lists [linsert $lists 0 $listId] } set pcc 1 } proc removeContactFromList { email listId } { global pcc set lists [getContactData $email lists] set idx [lsearch $lists $listId] if { $idx != -1 } { setContactData $email lists [lreplace $lists $idx $idx] } set pcc 1 } proc setConsistent {} { variable consistent set consistent 1 } proc unsetConsistent {} { variable consistent set consistent 0 } proc isConsistent {} { variable consistent return $consistent } #Save the contactlist to disk #filename - the filename to save to #type - the type to save as #possible types: csv, amsn proc saveToDisk { {filename ""} {type "amsn"} } { if { ![isConsistent] || ![LoginList lockexists "" [::config::getKey login]] } { return } global HOME variable users_data if { $filename eq "" } { set filename [file join $HOME abook.xml] } if {[catch { set file_id [open $filename w]} res ]} { status_log "::saveToDisk $res" msg_box "Can't save contact list, $res" return } fconfigure $file_id -encoding utf-8 if { [string equal $type "amsn"] } { puts $file_id "" puts $file_id "" foreach user [array names users_data] { puts $file_id "" array set temp_array $users_data($user) foreach field [array names temp_array] { puts -nonewline $file_id "\t<$field>" puts -nonewline $file_id "[::sxml::xmlreplace $temp_array($field)]" puts $file_id "" } puts $file_id "" array unset temp_array } puts $file_id "" } elseif { [string equal $type "csv"] } { puts $file_id "email,name" foreach contact [::abook::getAllContacts] { if { [string last "FL" [::abook::getContactData $contact lists]] != -1 } { array set temp_array $users_data($contact) if { [info exists temp_array([array names temp_array "nick"])] } { puts $file_id "$contact,$temp_array([array names temp_array "nick"])" } else { puts $file_id "$contact," } } } } elseif { [string equal $type "ctt"] } { puts $file_id "\n\n\t\n\t\t" foreach contact [::abook::getAllContacts] { if { [string last "FL" [::abook::getContactData $contact lists]] != -1 } { puts $file_id "\t\t\t$contact" } } puts $file_id "\t\t\n\t\n" } close $file_id } proc loadFromDisk { {filename ""} } { global HOME if { $filename eq "" } { set filename [file join $HOME abook.xml] } if {[file readable $filename] == 0} { return -1 } status_log "Loading address book data...\n" blue set abook_id [::sxml::init $filename] sxml::register_routine $abook_id "AMSN_AddressBook:contact" "::abook::loadXMLContact" set ret -1 clearData catch { set ret [sxml::parse $abook_id] } sxml::end $abook_id if { $ret < 0 } { clearData status_log "::abook::loadFromDisk Error\n" red return $ret } else { status_log "Address book data loaded...\n" green setConsistent return 0 } } proc loadXMLContact {cstack cdata saved_data cattr saved_attr args } { variable users_data upvar $saved_data sdata upvar $saved_attr sattr array set attr $cattr set parentlen [string length $cstack] foreach child [array names sattr] { if { $child eq "_dummy_" } { continue } set fieldname [string range $child [expr {$parentlen+1}] end] #Remove this. Only leave it for some days to remove old ::abook stored data if { $fieldname eq "field" } { continue } setContactData $attr(name) $fieldname $sdata($child) #To set up the reverse search array if { $fieldname eq "contactguid" } { setContactForGuid $sdata($child) $attr(name) } } return 0 } proc importContact { } { set filename [chooseFileDialog] if { $filename ne "" } { if { [string match -nocase "*.ctt" "$filename"] } { ::abook::importContactctt $filename } elseif { [string match -nocase "*.csv" "$filename"] } { ::abook::importContactcsv $filename } } } proc importContactcsv { filename } { set ImportedContact [list] set file_id [open $filename r] fconfigure $file_id -encoding utf-8 set content [read $file_id] close $file_id set lines [split $content "\n"] foreach line $lines { if { [string first "@" $line] != -1 } { set coma [string first "," $line] set contact [string range $line 0 [expr {$coma - 1}]] set ImportedContact [lappend ImportedContact $contact] } } ::abook::importContactList $ImportedContact } proc importContactctt { filename } { status_log "Salut\n" red set ImportedContact [list] set file_id [open $filename r] fconfigure $file_id -encoding utf-8 set content [read $file_id] close $file_id set lines [split $content "\n"] status_log "$lines" foreach line $lines { set id1 [string first "" $line] set id2 [string first "" $line] if { $id1 != -1 && $id2 != -1 } { incr id1 9 incr id2 -1 set contact [string range "$line" $id1 $id2] set ImportedContact [lappend ImportedContact $contact] } } ::abook::importContactList $ImportedContact } proc importContactList { ImportedContact } { foreach contact $ImportedContact { status_log "Importation of contacts : $contact\n" red ::MSN::addUser $contact } } } namespace eval ::abookGui { namespace export Init showEntry if { $initialize_amsn == 1 } { # # P R I V A T E # variable bgcol #ABC8CE; # Background color used in MSN Messenger } # # P R O T E C T E D # proc updatePhones { t h w m p} { set phome [urlencode [$t.$h get]] set pwork [urlencode [$t.$w get]] set pmobile [urlencode [$t.$m get]] ::abook::setPhone home $phome ::abook::setPhone work $pwork ::abook::setPhone mobile $pmobile ::abook::setPhone pager N } # # P U B L I C # proc Init {} { variable bgcol ::themes::AddClass ABook * {-background $bgcol} 90 ::themes::AddClass ABook Label {-background $bgcol} 90 ::themes::AddClass NoteBook * {-background $bgcol} 90 } proc userDPs_raise_cmd { nb email } { package require dpbrowser set nbUserDPs [$nb getframe userDPs] # set browser $nbUserDPs.otherdpscontainer.browser # set actions $nbUserDPs.otherdpscontainer.actions # # if { ![winfo exists $browser]} { # ::dpbrowser $browser -user $email -mode "selector" -width 6 -command [list\ # ::abookGui::activate_dpbrowser_actions $nbUserDPs.otherdpscontainer $email] # # pack $browser -side left -expand true -fill both\ # -before $nbUserDPs.otherdpscontainer.actions # } if { ![winfo exists $nbUserDPs.otherpics]} { ::dpbrowser $nbUserDPs.otherpics -width 7 -user $email -mode "properties" pack $nbUserDPs.otherpics -expand true -fill both } } # proc activate_dpbrowser_actions {widget email} { # # set browser $widget.browser # set actions $widget.actions # # set filepath [lindex [$browser getSelected] 1] # #activate the action buttons now an image is selected # if {$filepath ne ""} { # $actions.setasmine configure -state normal -command [list set_displaypic $filepath ] # $actions.setascustom configure -state normal -command [list ::abookGui::setCustomDp $email $filepath $widget ] # $actions.copyfileuri configure -state normal -command [list ::abookGui::copyDpToClipboard $filepath] # } else { # $actions.setasmine configure -state disabled # $actions.setascustom configure -state disabled # $actions.copyfileuri configure -state disabled # } # } #menu when right-clicking the user's dp on the first tab proc dp_mypicpopup_menu { X Y filename user} { #if user is self have another menu ? # Create pop-up menu if it doesn't yet exists set the_menu .userDPs_menu catch {destroy $the_menu} menu $the_menu -tearoff 0 -type normal $the_menu add command \ -label "[trans copytoclipboard [string tolower [trans filename]]]" \ -command [list ::abookGui::copyDpToClipboard $filename] $the_menu add command -label "[trans setasmydp]" \ -command [list set_displaypic $filename] $the_menu add command -label "[trans save]" \ -command [list saveFile $filename] tk_popup $the_menu $X $Y } proc showUserProperties { email } { global colorval_$email customdp_$email showcustomsmileys_$email autoacceptft_$email autoacceptwc_$email keeplogs_$email ignorecontact_$email HOME customdp_img_$email dontshowdp_$email set w ".user_[::md5::md5 $email]_prop" if { [winfo exists $w] } { raise $w return } toplevel $w wm title $w [trans userproperties $email] NoteBook $w.nb $w.nb insert 0 userdata -text [trans userdata] $w.nb insert 1 usersettings -text [trans usersettings] $w.nb insert 2 alarms -text [trans alarms] $w.nb insert 3 userDPs -text [trans userdps] \ -raisecmd [list ::abookGui::userDPs_raise_cmd $w.nb $email] ############## #Userdata page ############## set nbIdent [$w.nb getframe userdata] ScrolledWindow $nbIdent.sw set sw $nbIdent.sw ScrollableFrame $nbIdent.sw.sf -constrainedwidth 1 $nbIdent.sw setwidget $nbIdent.sw.sf set nbIdent [$nbIdent.sw.sf getframe] labelframe $nbIdent.fBasicInfo -relief groove -text [trans identity] label $nbIdent.fBasicInfo.displaypic -image [::skin::getDisplayPicture $email] -highlightthickness 2 -highlightbackground black -borderwidth 0 bind $nbIdent.fBasicInfo.displaypic <> \ [list ::abookGui::dp_mypicpopup_menu %X %Y\ [file join $HOME displaypic cache $email [filenoext [::abook::getContactData $email displaypicfile ""]].png] $email] set nick [::abook::getNick $email] set h [expr {[string length $nick]/50 +1}] text $nbIdent.fBasicInfo.h1 -font bigfont -bg [::skin::getKey extrastdwindowcolor] -height $h -wrap word -bd 0 $nbIdent.fBasicInfo.h1 delete 0.0 end $nbIdent.fBasicInfo.h1 insert 0.0 $nick $nbIdent.fBasicInfo.h1 configure -state disabled set h1copymenu [::abook::CreateCopyMenu $nbIdent.fBasicInfo.h1] bind $nbIdent.fBasicInfo.h1 <> "tk_popup $h1copymenu %X %Y" if { [::config::getKey protocol] >= 11 } { set psm [::abook::getpsmmedia $email] set h [expr {[string length $psm]/50 +1}] text $nbIdent.fBasicInfo.psm1 -font sitalf -bg [::skin::getKey extrastdwindowcolor] -height $h -wrap word -bd 0 $nbIdent.fBasicInfo.psm1 delete 0.0 end $nbIdent.fBasicInfo.psm1 insert 0.0 $psm $nbIdent.fBasicInfo.psm1 configure -state disabled set psm1copymenu [::abook::CreateCopyMenu $nbIdent.fBasicInfo.psm1] bind $nbIdent.fBasicInfo.psm1 <> "tk_popup $psm1copymenu %X %Y" } set h [expr {[string length $email]/50 +1}] text $nbIdent.fBasicInfo.e1 -font splainf -bg [::skin::getKey extrastdwindowcolor] -height $h -wrap word -bd 0 $nbIdent.fBasicInfo.e1 delete 0.0 end $nbIdent.fBasicInfo.e1 insert 0.0 $email $nbIdent.fBasicInfo.e1 configure -state disabled set e1copymenu [::abook::CreateCopyMenu $nbIdent.fBasicInfo.e1] bind $nbIdent.fBasicInfo.e1 <> "tk_popup $e1copymenu %X %Y" frame $nbIdent.fBasicInfo.fGroup label $nbIdent.fBasicInfo.fGroup.g -text "[trans group]:" -font splainf label $nbIdent.fBasicInfo.fGroup.g1 -text "[::abook::getGroupsname $email]" -font splainf -justify left -wraplength 300 pack $nbIdent.fBasicInfo.fGroup.g -side left pack $nbIdent.fBasicInfo.fGroup.g1 -side left grid $nbIdent.fBasicInfo.displaypic -row 0 -column 0 -sticky nwe -rowspan 4 -padx [list 0 8] grid $nbIdent.fBasicInfo.h1 -row 0 -column 1 -sticky w if { [::config::getKey protocol] >= 11 } { grid $nbIdent.fBasicInfo.psm1 -row 1 -column 1 -sticky w } grid $nbIdent.fBasicInfo.e1 -row 2 -column 1 -sticky w grid $nbIdent.fBasicInfo.fGroup -row 3 -column 1 -sticky w grid columnconfigure $nbIdent.fBasicInfo 1 -weight 1 labelframe $nbIdent.fPhone -text [trans phones] label $nbIdent.fPhone.phh -text "[trans home]:" label $nbIdent.fPhone.phh1 -font splainf -text [::abook::getContactData $email phh] \ -justify left -wraplength 300 label $nbIdent.fPhone.phw -text "[trans work]:" label $nbIdent.fPhone.phw1 -font splainf -text [::abook::getContactData $email phw] \ -justify left -wraplength 300 label $nbIdent.fPhone.phm -text "[trans mobile]:" label $nbIdent.fPhone.phm1 -font splainf -text [::abook::getContactData $email phm] \ -justify left -wraplength 300 label $nbIdent.fPhone.php -text "[trans pager]:" label $nbIdent.fPhone.php1 -font splainf -text [::abook::getContactData $email mob] \ -justify left -wraplength 300 grid $nbIdent.fPhone.phh -row 0 -column 0 -sticky e grid $nbIdent.fPhone.phh1 -row 0 -column 1 -sticky w grid $nbIdent.fPhone.phw -row 1 -column 0 -sticky e grid $nbIdent.fPhone.phw1 -row 1 -column 1 -sticky w grid $nbIdent.fPhone.phm -row 2 -column 0 -sticky e grid $nbIdent.fPhone.phm1 -row 2 -column 1 -sticky w grid $nbIdent.fPhone.php -row 3 -column 0 -sticky e grid $nbIdent.fPhone.php1 -row 3 -column 1 -sticky w grid columnconfigure $nbIdent.fPhone 1 -weight 1 labelframe $nbIdent.fStats -text [trans others] label $nbIdent.fStats.lastlogin -text "[trans lastlogin]:" label $nbIdent.fStats.lastlogin1 -text [::abook::dateconvert "[::abook::getContactData $email last_login]"] -font splainf label $nbIdent.fStats.lastlogout -text "[trans lastlogout]:" label $nbIdent.fStats.lastlogout1 -text [::abook::dateconvert "[::abook::getContactData $email last_logout]"] -font splainf label $nbIdent.fStats.lastseen -text "[trans lastseen]:" if { [::abook::getVolatileData $email state] eq "FLN" || ([lsearch [::abook::getContactData $email lists] "FL"] == -1 && [lsearch [::abook::getContactData $email lists] "EL"] != -1)} { label $nbIdent.fStats.lastseen1 -text [::abook::dateconvert "[::abook::getContactData $email last_seen]"] -font splainf } elseif { [::abook::getContactData $email last_seen] eq "" } { label $nbIdent.fStats.lastseen1 -text "" -font splainf } else { label $nbIdent.fStats.lastseen1 -text [trans online] -font splainf } label $nbIdent.fStats.lastmsgedme -text "[trans lastmsgedme]:" label $nbIdent.fStats.lastmsgedme1 -text [::abook::dateconvert "[::abook::getContactData $email last_msgedme]"] -font splainf #Client-name of the user (from Gaim, dMSN, etc) label $nbIdent.fStats.clientname -text "[trans clientname]:" label $nbIdent.fStats.clientname1 -text "[::abook::getContactData $email clientname] ([::abook::getContactData $email client])" -font splainf #Does the user record the conversation or not if { [::abook::getContactData $email chatlogging] eq "Y" } { set chatlogging [trans yes] } elseif { [::abook::getContactData $email chatlogging] eq "N" } { set chatlogging [trans no] } else { set chatlogging [trans unknown] } label $nbIdent.fStats.chatlogging -text "[trans logschats]:" label $nbIdent.fStats.chatlogging1 -text $chatlogging -font splainf grid $nbIdent.fStats.lastlogin -row 0 -column 0 -sticky e grid $nbIdent.fStats.lastlogin1 -row 0 -column 1 -sticky w grid $nbIdent.fStats.lastlogout -row 1 -column 0 -sticky e grid $nbIdent.fStats.lastlogout1 -row 1 -column 1 -sticky w grid $nbIdent.fStats.lastmsgedme -row 2 -column 0 -sticky e grid $nbIdent.fStats.lastmsgedme1 -row 2 -column 1 -sticky w grid $nbIdent.fStats.lastseen -row 3 -column 0 -sticky e grid $nbIdent.fStats.lastseen1 -row 3 -column 1 -sticky w grid $nbIdent.fStats.clientname -row 4 -column 0 -sticky e grid $nbIdent.fStats.clientname1 -row 4 -column 1 -sticky w grid $nbIdent.fStats.chatlogging -row 5 -column 0 -sticky e grid $nbIdent.fStats.chatlogging1 -row 5 -column 1 -sticky w grid columnconfigure $nbIdent.fStats 1 -weight 1 grid $nbIdent.fBasicInfo -row 0 -column 0 -sticky nwse -columnspan 2 -ipadx 4 -ipady 4 grid $nbIdent.fPhone -row 1 -column 0 -sticky nwse -padx [list 0 4] -pady [list 8 0] grid $nbIdent.fStats -row 1 -column 1 -sticky nwse -padx [list 4 0] -pady [list 8 0] grid columnconfigure $nbIdent { 0 1 } -weight 1 pack $sw -expand true -fill both ############## #User settings page ############# set nbSettings [$w.nb getframe usersettings] ScrolledWindow $nbSettings.sw set sw $nbSettings.sw ScrollableFrame $nbSettings.sw.sf -constrainedwidth 1 $nbSettings.sw setwidget $nbSettings.sw.sf set nbSettings [$nbSettings.sw.sf getframe] labelframe $nbSettings.fNick -relief groove -text [trans nick] label $nbSettings.fNick.customnickl -text "[trans customnick]:" frame $nbSettings.fNick.customnick entry $nbSettings.fNick.customnick.ent -font splainf menubutton $nbSettings.fNick.customnick.help -font sboldf -text "<-" -menu $nbSettings.fNick.customnick.help.menu menu $nbSettings.fNick.customnick.help.menu -tearoff 0 $nbSettings.fNick.customnick.help.menu add command -label [trans nick] -command "$nbSettings.fNick.customnick.ent insert insert \\\$nick" $nbSettings.fNick.customnick.help.menu add command -label [trans email] -command "$nbSettings.fNick.customnick.ent insert insert \\\$user_login" if { [::config::getKey protocol] >= 11 } { $nbSettings.fNick.customnick.help.menu add command -label [trans psm] -command "$nbSettings.fNick.customnick.ent insert insert \\\$psm" } $nbSettings.fNick.customnick.help.menu add separator $nbSettings.fNick.customnick.help.menu add command -label [trans delete] -command "$nbSettings.fNick.customnick.ent delete 0 end" $nbSettings.fNick.customnick.ent insert end [::abook::getContactData $email customnick] pack $nbSettings.fNick.customnick.ent -side left -expand true -fill x pack $nbSettings.fNick.customnick.help -side left label $nbSettings.fNick.customfnickl -text "[trans friendlyname]:" frame $nbSettings.fNick.customfnick entry $nbSettings.fNick.customfnick.ent -font splainf menubutton $nbSettings.fNick.customfnick.help -font sboldf -text "<-" -menu $nbSettings.fNick.customfnick.help.menu menu $nbSettings.fNick.customfnick.help.menu -tearoff 0 $nbSettings.fNick.customfnick.help.menu add command -label [trans nick] -command "$nbSettings.fNick.customfnick.ent insert insert \\\$nick" $nbSettings.fNick.customfnick.help.menu add command -label [trans email] -command "$nbSettings.fNick.customfnick.ent insert insert \\\$user_login" if { [::config::getKey protocol] >= 11 } { $nbSettings.fNick.customfnick.help.menu add command -label [trans psm] -command "$nbSettings.fNick.customfnick.ent insert insert \\\$psm" } $nbSettings.fNick.customfnick.help.menu add separator $nbSettings.fNick.customfnick.help.menu add command -label [trans delete] -command "$nbSettings.fNick.customfnick.ent delete 0 end" $nbSettings.fNick.customfnick.ent insert end [::abook::getContactData $email customfnick] pack $nbSettings.fNick.customfnick.ent -side left -expand true -fill x pack $nbSettings.fNick.customfnick.help -side left label $nbSettings.fNick.ycustomfnickl -text "[trans myfriendlyname]:" frame $nbSettings.fNick.ycustomfnick entry $nbSettings.fNick.ycustomfnick.ent -font splainf menubutton $nbSettings.fNick.ycustomfnick.help -font sboldf -text "<-" -menu $nbSettings.fNick.ycustomfnick.help.menu menu $nbSettings.fNick.ycustomfnick.help.menu -tearoff 0 $nbSettings.fNick.ycustomfnick.help.menu add command -label [trans nick] -command "$nbSettings.fNick.ycustomfnick.ent insert insert \\\$nick" $nbSettings.fNick.ycustomfnick.help.menu add command -label [trans email] -command "$nbSettings.fNick.ycustomfnick.ent insert insert \\\$user_login" if { [::config::getKey protocol] >= 11 } { $nbSettings.fNick.ycustomfnick.help.menu add command -label [trans psm] -command "$nbSettings.fNick.ycustomfnick.ent insert insert \\\$psm" } $nbSettings.fNick.ycustomfnick.help.menu add separator $nbSettings.fNick.ycustomfnick.help.menu add command -label [trans delete] -command "$nbSettings.fNick.ycustomfnick.ent delete 0 end" $nbSettings.fNick.ycustomfnick.ent insert end [::abook::getContactData $email cust_p4c_name] pack $nbSettings.fNick.ycustomfnick.ent -side left -expand true -fill x pack $nbSettings.fNick.ycustomfnick.help -side left # The custom color frame label $nbSettings.fNick.lColor -text "[trans customcolor]:" frame $nbSettings.fNick.fColor -relief flat set colorval_$email [::abook::getContactData $email customcolor] set showcustomsmileys_$email [::abook::getContactData $email showcustomsmileys] set autoacceptft_$email [::abook::getContactData $email autoacceptft] set autoacceptwc_$email [::abook::getContactData $email autoacceptwc] set ignorecontact_$email [::abook::getContactData $email ignored] set dontshowdp_$email [::abook::getContactData $email dontshowdp] set keeplogs_$email [::abook::getContactData $email keeplogs] frame $nbSettings.fNick.fColor.col -width 96 -bd 1 -relief flat -highlightbackground black -highlightcolor black if { [set colorval_$email] ne "" } { if { [string index [set colorval_$email] 0] eq "#" } { set colorval_$email [string range [set colorval_$email] 1 end] } set colorval_$email "#[string repeat 0 [expr {6-[string length [set colorval_$email]]}]][set colorval_$email]" #If the color is white we can't see the contact on the list : we ignore the custom color $nbSettings.fNick.fColor.col configure -background [set colorval_${email}] -highlightthickness 1 } else { $nbSettings.fNick.fColor.col configure -background [$nbSettings.fNick.fColor cget -background] -highlightthickness 0 } button $nbSettings.fNick.fColor.bset -text "[trans change]" -command "::abookGui::ChangeColor $email $nbSettings" button $nbSettings.fNick.fColor.brem -text "[trans delete]" -command "::abookGui::RemoveCustomColor $email $nbSettings" pack $nbSettings.fNick.fColor.col -side left -expand true -fill y -pady 5 -padx 8 pack $nbSettings.fNick.fColor.bset -side left -padx 3 -pady 2 pack $nbSettings.fNick.fColor.brem -side left -padx 3 -pady 2 # The custom display pic frame label $nbSettings.fNick.lDispl -text "[trans customdp]:" frame $nbSettings.fNick.fDispl -relief flat set customdp_$email [::abook::getContactData $email customdp ""] if {[set customdp_$email] ne "" && [file readable [set customdp_$email]]} { image create photo customdp_img_$email -file [set customdp_$email] label $nbSettings.fNick.fDispl.dp -height 96 -width 96 -image customdp_img_$email -borderwidth 0 -relief flat } else { label $nbSettings.fNick.fDispl.dp -height 96 -width 96 -image [::skin::loadPixmap nullimage] -borderwidth 0 -relief flat } button $nbSettings.fNick.fDispl.bset -text "[trans change]" -command "::abookGui::ChangeCustomDp $email $nbSettings" button $nbSettings.fNick.fDispl.brem -text "[trans delete]" -command "::abookGui::RemoveCustomDp $email $nbSettings" pack $nbSettings.fNick.fDispl.dp -side left -pady 5 -padx 8 pack $nbSettings.fNick.fDispl.bset -side left -padx 3 -pady 2 pack $nbSettings.fNick.fDispl.brem -side left -padx 3 -pady 2 grid $nbSettings.fNick.customnickl -row 0 -column 0 -sticky e grid $nbSettings.fNick.customnick -row 0 -column 1 -sticky we grid $nbSettings.fNick.customfnickl -row 1 -column 0 -sticky e grid $nbSettings.fNick.customfnick -row 1 -column 1 -sticky we grid $nbSettings.fNick.ycustomfnickl -row 2 -column 0 -sticky e grid $nbSettings.fNick.ycustomfnick -row 2 -column 1 -sticky we grid $nbSettings.fNick.lColor -row 3 -column 0 -sticky e grid $nbSettings.fNick.fColor -row 3 -column 1 -sticky w grid $nbSettings.fNick.lDispl -row 4 -column 0 -sticky e grid $nbSettings.fNick.fDispl -row 4 -column 1 -sticky w grid columnconfigure $nbSettings.fNick 1 -weight 1 labelframe $nbSettings.fChat -relief groove -text [trans chat] checkbutton $nbSettings.fChat.showcustomsmileys -variable showcustomsmileys_$email -text "[trans custshowcustomsmileys]" -anchor w checkbutton $nbSettings.fChat.ignoreuser -variable ignorecontact_$email -text "[trans ignorecontact]" -anchor w checkbutton $nbSettings.fChat.dontshowdp -variable dontshowdp_$email -text "[trans dontshowdp]" -anchor w checkbutton $nbSettings.fChat.autoacceptft -variable autoacceptft_$email -text "[trans autoacceptft]" -anchor w checkbutton $nbSettings.fChat.autoacceptwc -variable autoacceptwc_$email -text "[trans autoacceptwc]" -anchor w checkbutton $nbSettings.fChat.keeplogs -variable keeplogs_$email -text "[trans keeplog]" -anchor w pack $nbSettings.fChat.showcustomsmileys -side top -fill x pack $nbSettings.fChat.ignoreuser -side top -fill x pack $nbSettings.fChat.dontshowdp -side top -fill x pack $nbSettings.fChat.autoacceptft -side top -fill x pack $nbSettings.fChat.autoacceptwc -side top -fill x pack $nbSettings.fChat.keeplogs -side top -fill x labelframe $nbSettings.fGroup -relief groove -text [trans groups] ::groups::Groupmanager $email $nbSettings.fGroup labelframe $nbSettings.fNotify -relief groove -text [trans notifywin] label $nbSettings.fNotify.default -font sboldf -text "*" -justify center label $nbSettings.fNotify.yes -font sboldf -text [trans yes] -justify center label $nbSettings.fNotify.no -font sboldf -text [trans no] -justify center #Set default values set ::notifyonline($email) [::abook::getContactData $email notifyonline ""] set ::notifyoffline($email) [::abook::getContactData $email notifyoffline ""] set ::notifystatus($email) [::abook::getContactData $email notifystatus ""] set ::notifymsg($email) [::abook::getContactData $email notifymsg ""] #Add the checkboxes AddOption $nbSettings.fNotify notifyonline notifyonline($email) [trans custnotifyonline] 1 AddOption $nbSettings.fNotify notifyoffline notifyoffline($email) [trans custnotifyoffline] 2 AddOption $nbSettings.fNotify notifystatus notifystatus($email) [trans custnotifystatus] 3 AddOption $nbSettings.fNotify notifymsg notifymsg($email) [trans custnotifymsg] 4 grid $nbSettings.fNotify.default -row 0 -column 0 -sticky we -padx 5 grid $nbSettings.fNotify.yes -row 0 -column 1 -sticky we -padx 5 grid $nbSettings.fNotify.no -row 0 -column 2 -sticky we -padx 5 grid columnconfigure $nbSettings.fNotify 3 -weight 1 grid $nbSettings.fNick -row 0 -column 0 -sticky nwse -columnspan 2 -pady [list 0 4] grid $nbSettings.fChat -row 1 -column 0 -sticky nwse -padx [list 0 4] -pady 4 grid $nbSettings.fGroup -row 1 -column 1 -sticky nwse -padx [list 4 0] -pady 4 grid $nbSettings.fNotify -row 2 -column 0 -sticky nwse -columnspan 2 -pady [list 4 0] grid columnconfigure $nbSettings { 0 1 } -weight 1 pack $sw -expand true -fill both ############## #Alarms frame ############## set nbAlarm [$w.nb getframe alarms] ScrolledWindow $nbAlarm.sw pack $nbAlarm.sw -expand true -fill both ScrollableFrame $nbAlarm.sw.sf $nbAlarm.sw setwidget $nbAlarm.sw.sf set nbAlarm [$nbAlarm.sw.sf getframe] ::alarms::configDialog $email $nbAlarm ############## #UserDPs page ############## set nbUserDPs [$w.nb getframe userDPs] # User's current display picture # label $nbUserDPs.titlepic1 -text "[trans curdisplaypic]" -font bboldunderf # label $nbUserDPs.displaypic -image [::skin::getDisplayPicture $email] # bind $nbUserDPs.displaypic <> \ [list ::abookGui::dp_mypicpopup_menu %X %Y\ [file join $HOME displaypic cache $email [filenoext [::abook::getContactData $email displaypicfile ""]].png] $email] # Other display pictures of user label $nbUserDPs.titlepic2 -text "[trans otherdisplaypic]" # frame $nbUserDPs.otherdpscontainer # set actions $nbUserDPs.otherdpscontainer.actions # #$nbUserDPs.otherdpscontainer.browser is created in userDPs_raise_cmd # # frame $actions # label $actions.titlepic1 -text "[trans curdisplaypic]" -font bboldunderf -anchor n # label $actions.displaypic -image [::skin::getDisplayPicture $email] -anchor n # # button $actions.setasmine -text "[trans setasmydp]" -state disabled -justify left # button $actions.setascustom -text "[trans setascustom]" -state disabled # if {[::abook::getContactData $email customdp ""] ne ""} { # button $actions.removecustom -text "[trans removecustom]" -state normal -command [list ::abookGui::unsetCustomDp $email $w] # } else { # button $actions.removecustom -text "[trans removecustom]" -state disabled # } # button $actions.copyfileuri -text "[trans copytoclipboard [string tolower [trans filename]]]" -state disabled # pack $actions.titlepic1 $actions.displaypic -fill x # pack $actions.setasmine $actions.setascustom $actions.removecustom $actions.copyfileuri -anchor w -fill x # pack $actions -side left -fill y #Other display pictures get loaded when the dp tab is raised #See proc userDPs_raise_cmd # pack $nbUserDPs.titlepic1 -anchor w -padx 5 -pady 5 # pack $nbUserDPs.displaypic -anchor w -padx 7 -pady 5 pack $nbUserDPs.titlepic2 -anchor w -padx 5 -pady 5 # pack $nbUserDPs.otherdpscontainer -anchor w -padx 5 -pady 5 -fill both -expand true ########## #Common ########## $w.nb compute_size [$w.nb getframe userdata].sw.sf compute_size [$w.nb getframe usersettings].sw.sf compute_size [$w.nb getframe alarms].sw.sf compute_size $w.nb compute_size $w.nb raise userdata frame $w.buttons button $w.buttons.ok -text [trans accept] -command [list ::abookGui::PropOk $email $w] button $w.buttons.cancel -text [trans cancel] -command [list ::abookGui::PropCancel $email $w] pack $w.buttons.ok $w.buttons.cancel -side right -padx 5 -pady 3 pack $w.buttons -fill x -side bottom pack $w.nb -expand true -fill both -side bottom -padx 3 -pady 3 #pack $w.nb #Ask to save or not to save when we close the user properties window on Mac OS X #Request from users with 800X600 screen (they can't see accept/cancel button) if { [OnMac] } { wm protocol $w WM_DELETE_WINDOW "[list ::abookGui::closeProperties $email $w]" bind $w <> "[list ::abookGui::closeProperties $email $w]" } else { bind $w <> "[list ::abookGui::PropCancel $email $w]" } bind $w [list ::abookGui::PropDestroyed $email $w %W] moveinscreen $w 30 } proc showUserAlarmSettings { email } { showUserProperties $email .user_[::md5::md5 $email]_prop.nb raise alarms } proc showCustomNickScreen { email } { set w ".user_[::md5::md5 $email]_cnick" if { [winfo exists $w] } { raise $w return } toplevel $w wm title $w "[trans customnick]: $email" label $w.customnickl -text "[trans customnick]:" frame $w.customnick entry $w.customnick.ent -font splainf menubutton $w.customnick.help -font sboldf -text "<-" -menu $w.customnick.help.menu menu $w.customnick.help.menu -tearoff 0 $w.customnick.help.menu add command -label [trans nick] -command "$w.customnick.ent insert insert \\\$nick" $w.customnick.help.menu add command -label [trans email] -command "$w.customnick.ent insert insert \\\$user_login" $w.customnick.help.menu add separator $w.customnick.help.menu add command -label [trans delete] -command "$w.customnick.ent delete 0 end" $w.customnick.ent insert end [::abook::getContactData $email customnick] pack $w.customnick.ent -side left -expand true -fill x pack $w.customnick.help -side left label $w.customfnickl -text "[trans friendlyname]:" frame $w.customfnick entry $w.customfnick.ent -font splainf menubutton $w.customfnick.help -font sboldf -text "<-" -menu $w.customfnick.help.menu menu $w.customfnick.help.menu -tearoff 0 $w.customfnick.help.menu add command -label [trans nick] -command "$w.customfnick.ent insert insert \\\$nick" $w.customfnick.help.menu add command -label [trans email] -command "$w.customfnick.ent insert insert \\\$user_login" $w.customfnick.help.menu add separator $w.customfnick.help.menu add command -label [trans delete] -command "$w.customfnick.ent delete 0 end" $w.customfnick.ent insert end [::abook::getContactData $email customfnick] pack $w.customfnick.ent -side left -expand true -fill x pack $w.customfnick.help -side left grid $w.customnickl -row 0 -column 0 -sticky ne grid $w.customnick -row 0 -column 1 -sticky we -padx 6 grid $w.customfnickl -row 1 -column 0 -sticky ne grid $w.customfnick -row 1 -column 1 -sticky we -padx 6 grid columnconfigure $w 1 -weight 1 } #Ask the user if he wants to save or not the user properties window proc closeProperties {email w} { #Ask the user yes/no if he wants to save, parent=window to attach the question, title= totally useless on Mac set answer [::amsn::messageBox "[trans save] ?" yesno question "[trans save] ?"] #When the user answer yes, save preferences and close the window if {$answer eq "yes"} { ::abookGui::PropOk $email $w #When the user do not answer yes (no), then Restore previous preferences and close the window } else { ::abookGui::PropCancel $email $w } } proc PropDestroyed { email w win } { global colorval_$email showcustomsmileys_$email autoacceptft_$email autoacceptwc_$email ignorecontact_$email dontshowdp_$email keeplogs_$email if { $w eq $win } { #Clean temporal variables unset ::notifyonline($email) unset ::notifyoffline($email) unset ::notifystatus($email) unset ::notifymsg($email) catch {unset colorval_$email} catch {unset showcustomsmileys_$email} catch {unset autoacceptft_$email} catch {unset autoacceptwc_$email} catch {unset ignorecontact_$email} catch {unset dontshowdp_$email} catch {unset keeplogs_$email} } } proc AddOption { nbNotify name var text row} { radiobutton $nbNotify.${name}_default -value "" -variable $var radiobutton $nbNotify.${name}_yes -value 1 -variable $var radiobutton $nbNotify.${name}_no -value 0 -variable $var label $nbNotify.${name} -font splainf -text $text -justify left grid $nbNotify.${name}_default -row $row -column 0 -sticky we grid $nbNotify.${name}_yes -row $row -column 1 -sticky we grid $nbNotify.${name}_no -row $row -column 2 -sticky we grid $nbNotify.${name} -row $row -column 3 -sticky w } proc ChangeColor { email w } { global colorval_$email set color [SelectColor $w.customcolordialog -type dialog -title "[trans customcolor]" -parent $w] if { $color eq "" } { return } set colorval_$email $color $w.fNick.fColor.col configure -background [set colorval_${email}] -highlightthickness 1 } proc RemoveCustomColor { email w } { global colorval_$email set colorval_$email "" $w.fNick.fColor.col configure -background [$w.fNick.fColor cget -background] -highlightthickness 0 } # proc setCustomDp { email path widget } { # # Backup old custom dp # set old_customdp [::abook::getContactData $email customdp ""] # # Store custom display information options # ::abook::setAtomicContactData $email customdp $path # # Update display picture # if {$path ne $old_customdp} { # ::skin::getDisplayPicture $email 1 # ::skin::getLittleDisplayPicture $email 1 # $widget.actions.displaypic configure -image [::skin::getDisplayPicture $email] # } # if {$old_customdp eq ""} { # $widget.actions.removecustom configure -state normal -command [list ::abookGui::unsetCustomDp $email $widget] # } # } # proc unsetCustomDp { email widget } { # # Backup old custom dp # set old_customdp [::abook::getContactData $email customdp ""] # # Store custom display information options # ::abook::setAtomicContactData $email customdp "" # # Update display picture # if {$old_customdp ne ""} { # ::skin::getDisplayPicture $email 1 # ::skin::getLittleDisplayPicture $email 1 # $widget.actions.displaypic configure -image [::skin::getDisplayPicture $email] # } # $widget.actions.removecustom configure -state disabled # } proc copyDpToClipboard { file } { clipboard clear clipboard append $file } # These procedures change the custom DP. They need to be launched from within the properties screen, # as the actual change is done through the PropOk procedure proc ChangeCustomDp { email w } { global customdp_$email set customdp_$email [::abook::getContactData $email customdp ""] dpBrowser $email tkwait window .dpbrowser if {[file readable [set customdp_$email]]} { catch {image delete customdp_img_$email} image create photo customdp_img_$email -file [set customdp_$email] $w.fNick.fDispl.dp configure -image customdp_img_$email } else { status_log "Can not open file [set customdp_$email]" red } } proc RemoveCustomDp { email w } { global customdp_$email set customdp_$email "" $w.fNick.fDispl.dp configure -image [::skin::loadPixmap nullimage] } proc SetGlobalNick { } { if {[winfo exists .globalnick]} { return } toplevel .globalnick wm title .globalnick "[trans globalnicktitle]" frame .globalnick.frm -bd 1 label .globalnick.frm.lbl -text "[trans globalnick]" -font sboldf -justify left -wraplength 400 entry .globalnick.frm.nick -width 50 menubutton .globalnick.frm.help -bd 1 -text "<-" -menu .globalnick.frm.help.menu menu .globalnick.frm.help.menu -tearoff 0 .globalnick.frm.help.menu add command -label [trans nick] -command ".globalnick.frm.nick insert insert \\\$nick" .globalnick.frm.help.menu add command -label [trans email] -command ".globalnick.frm.nick insert insert \\\$user_login" .globalnick.frm.help.menu add command -label [trans psm] -command ".globalnick.frm.nick insert insert \\\$psm" .globalnick.frm.help.menu add command -label [trans customnick] -command ".globalnick.frm.nick insert insert \\\$customnick" .globalnick.frm.help.menu add separator .globalnick.frm.help.menu add command -label [trans delete] -command ".globalnick.frm.nick delete 0 end" pack .globalnick.frm.lbl -pady 2 -side top pack .globalnick.frm.nick -pady 2 -side left pack .globalnick.frm.help -padx 5 -side left bind .globalnick.frm.nick [list .globalnick.btn.ok invoke] frame .globalnick.btn -bg [::skin::getKey extrastdwindowcolor] button .globalnick.btn.ok -text "[trans ok]" \ -command { set nick [.globalnick.frm.nick get] set data [::smiley::parseMessageToList [list [ list "text" $nick ]] 1] set evpar(variable) data set evpar(login) "" ::plugins::PostEvent parse_contact evpar set ::globalnick $data ::config::setKey globalnick $nick; ::MSN::contactListChanged; ::Event::fireEvent changedNickDisplay gui destroy .globalnick } button .globalnick.btn.cancel -text "[trans cancel]" \ -command {destroy .globalnick} bind .globalnick <> [list .globalnick.btn.cancel invoke] pack .globalnick.btn.ok .globalnick.btn.cancel -side right -padx 5 pack .globalnick.frm -side top -pady 3 -padx 5 pack .globalnick.btn -side top -anchor e -pady 3 .globalnick.frm.nick insert end [::config::getKey globalnick] } proc PropOk { email w } { global colorval_$email customdp_$email showcustomsmileys_$email autoacceptft_$email autoacceptwc_$email ignorecontact_$email dontshowdp_$email keeplogs_$email if {[::alarms::SaveAlarm $email] != 0 } { return } set nbSettings [$w.nb getframe usersettings] set nbSettings [$nbSettings.sw.sf getframe] # Backup old custom dp set old_customdp [::abook::getContactData $email customdp ""] # Store custom display information options ::abook::setAtomicContactData $email [list cust_p4c_name customcolor customdp showcustomsmileys autoacceptft autoacceptwc ignored dontshowdp keeplogs] \ [list [$nbSettings.fNick.ycustomfnick.ent get] [set colorval_$email] [set customdp_$email] [set showcustomsmileys_$email] [set autoacceptft_$email] [set autoacceptwc_$email] [set ignorecontact_$email] [set dontshowdp_$email] [set keeplogs_$email]] ::abook::setContactData $email customnick [$nbSettings.fNick.customnick.ent get] ::abook::setContactData $email customfnick [$nbSettings.fNick.customfnick.ent get] # Update display picture if {[set customdp_$email] ne $old_customdp} { ::skin::getDisplayPicture $email 1 } # Store groups ::groups::GroupmanagerOk $email # Store custom notification options ::abook::setAtomicContactData $email [list notifyonline notifyoffline notifystatus notifymsg] \ [list [set ::notifyonline($email)] [set ::notifyoffline($email)] [set ::notifystatus($email)] [set ::notifymsg($email)]] catch {image delete customdp_img_$email} destroy $w ::MSN::contactListChanged ::Event::fireEvent contactDataChange gui $email ::abook::saveToDisk } proc PropCancel { email w } { ::groups::GroupmanagerClose $email catch {image delete customdp_img_$email} destroy $w } } amsn-0.98.9/progressbar.tcl0000644000175000017500000000502510567435163015442 0ustar billiobbilliob#From Donald K. Fellows's Megawidget and Dialog Stuff #http://www.cs.man.ac.uk/~fellowsd/tcl/mwidx.html ::Version::setSubversionId {$Id: progressbar.tcl 8064 2007-02-23 00:50:59Z lephilousophe $} if { $initialize_amsn == 1 } { option add *Progress.undoneForeground black widgetDefault option add *Progress.undoneBackground white widgetDefault option add *Progress.doneForeground white widgetDefault option add *Progress.doneBackground green4 widgetDefault option add *Progress.borderWidth 1 widgetDefault option add *Progress.relief sunken widgetDefault } namespace eval dkfprogress { namespace export Progress SetProgress proc Progress {w args} { uplevel 1 [list frame $w -class Progress] $args foreach {val} { undoneForeground doneForeground undoneBackground doneBackground } { set class [string toupper [string index $val 0]\ ][string range $val 1 end] set $val [option get $w $val $class] } set varname [namespace current]::progressPercent($w) frame $w.l -borderwidth 0 -background $undoneBackground label $w.l.l -textvariable $varname -borderwidth 0 \ -foreground black -background $undoneBackground $w.l configure -height [expr {int([winfo reqheight $w.l.l]+2)}] frame $w.l.fill -background $doneBackground label $w.l.fill.l -textvariable $varname -borderwidth 0 \ -foreground black -background $doneBackground bind $w.l [namespace code [list ProgressConf $w "%w"]] pack $w.l -fill both -expand 1 place $w.l.l -relx 0.5 -rely 0.5 -anchor center place $w.l.fill -x 0 -y 0 -relheight 1 -relwidth 0 place $w.l.fill.l -x 0 -rely 0.5 -anchor center SetProgress $w 0 return $w } proc ProgressConf {w width} { place conf $w.l.fill.l -x [expr {int($width/2)}] } proc SetProgress {win value {range 100}} { if {[winfo exists $win]} { set progress [expr {int(double($value)/ (double($range)/100.0))}] set relwidth [expr {double($value)/double($range)}] variable progressPercent place conf $win.l.fill -relwidth $relwidth set progressPercent($win) "${progress}%" if {[expr $relwidth < 0.5]} { set R e1 binary scan [binary format i [expr {int(2*$relwidth*225)}]] H2 G } else { set G e1 binary scan [binary format i [expr {int(2*(1.0 - $relwidth)*225)}]] H2 R } set B 00 $win.l.fill configure -background \#${R}${G}${B} $win.l.fill.l configure -background \#${R}${G}${B} } } } if { $initialize_amsn == 1 } { namespace import dkfprogress::Progress dkfprogress::SetProgress } amsn-0.98.9/FAQ.html0000644000175000017500000020621010734014202013660 0ustar billiobbilliob Frequently Asked Questions - AMSN

Frequently Asked Questions

The latest version of this FAQ can be found at http://amsn-project.net/faq.php

FAQ 2.1.0


Contents

What is aMSN?

What is aMSN?

aMSN is a Microsoft Messenger clone. It allows you to keep in touch with your friends and exchange instant messages and files.

Back to top

What do I need to run aMSN?

  • Windows and Mac OS X. aMSN will run right out of the box if you download the official packages, which can be found at http://amsn.sourceforge.net/download.php.
  • Linux. You will need Tcl 8.4 / Tk 8.4 or above in order to run aMSN. These two packages (Tcl & Tk) are usually installed by default on most distributions. These can also be installed as a dependency if your packaging system supports it (rpm, deb, etc.). If for some reason your distribution does not currently provide you with Tcl 8.4 or Tk 8.4, you may download them and follow the installation instructions at http://tcl.tk.

Back to top

Where can I get aMSN ?

You can download the packages of aMSN at http://amsn.sourceforge.net/download.php.

For Linux users : You can also get aMSN using your distribution's package management system (apt-get install amsn for debian/ubuntu for example).

Back to top

Troubleshooting

Why are arabic fonts displayed from left to right instead of right to left?

  • Windows: Go to 'Control Panel' → 'Regional and Language Options' → Languages tab, and enable the option "Install files for complex scripts and right-to-left languages"
  • Linux: Installing the Arabic locale should solve this issue.

Back to top

I have enabled the traydock icon, but when I minimize aMSN, it is still shown in both the taskbar and the tray. How can I make it display in the tray only?

The first time you will close aMSN with the 'X' button in the main window's border. It should ask you if you want to quit or minimize it to tray. You must choose the 'Minimize to Tray' option if you want it to disappear from the taskbar.

Alternatively, you can also click the "Minimize to Tray" option from the Account menu.


Back to top

When I close aMSN's window, it quits instead of minimizing to tray

The first time you will close aMSN with the 'X' button in the main window's border. It should ask you if you want to quit or minimize it to tray. You must choose the 'Minimize to Tray' option if you want it to minimize to the tray.

If you chose 'Quit' and enabled the "Remember my choice" option, it will always quit and will not ask you again. If you want to change this behavior and want it to ask you again so you can change your choice, you will have to do the following procedure :

Press Ctrl-Shift-C from aMsn's main window, a new window titled "Console" will appear in which you can type commands. Type the following and press enter :

  ::config::setKey closingdocks 0

You can now close this new Console window and the next time you close aMSN's main window, it will ask you again to make a choice.


Back to top

I don't see the traydock even if I enabled it, what's the problem?

  • Linux: Make sure the file msn/utils/linux/traydock/libtray.so exists. If it does not exist, make sure you download an official package of aMSN at: http://amsn-project.net/download.php

If you compiled aMSN yourself, please make sure you have the X11 development packages installed and follow this page to compile aMSN correctly.

NOTE: There is no traydock icon on Mac OS X

Back to top


Does aMSN run on 64-bit systems?

Yes, many users have been able to run aMSN on 64-bit architectures. However, you will have to compile tcltls by yourself. There isn't a package for x84_64 on the aMSN site so you need to download it from: [1]

Back to top

When notify window pops up, the windows taskbar partially hides it, can I fix this?

Yes, you can move the notify window X pixels to the left and Y pixels to the top. You can customize this by modifying the "X Offset" and "Y Offset" values in (menu) 'Account' → 'Preferences' → 'Advanced' → “Offset the position of the notification pop-up.” and clicking “Save” to save your modifications.

Back to top

Can I see who blocked me?

No, this feature is no longer available because the block detection bug that was happening in the Microsoft servers has now been fixed.

There is NO safe way to know if someone blocked you

Back to top

My jpeg webcam does not currently work, will my jpeg webcam work in the future (example: D-link dsb-c310)?

JPEG webcams support is currently supported since the 0.97 version of aMSN.

If you are using a version prior to 0.97, please update to the latest version of aMSN.

Back to top

Why can't I receive acceptable quality images from my contacts using aMSN?

If the image is of a poor quality, it's probably because the other user's webcam is of poor quality. aMSN's quality of the webcam is the same as the official msn client.

Back to top


I can't read Chinese or Japanese with aMSN, even after changing the text encoding. Where can I find help?

Please read the documentation about getting SCIM to work with aMSN.

Back to top

How do I capture bug report information from a segmentation fault? (LINUX)

Make sure amsn was compiled with debugging symbols, if you installed it using a binary package, you should probably download from source and recompile it. To enable debugging symbols, configure it with : ./configure --enable-debug If you're unable to compile it, then you can still send us information without the debugging symbols. Once it is compiled/installed, go to the directory where you have installed aMSN (example: /usr/share/amsn or /home/yourusername/amsn-0.95/) type:

 $ gdb --args wish amsn
 (gdb) run
 [then when it segfaults, type]
 (gdb) bt
 (gdb) bt full

You will then receive the bug report information. Please report this information to the forums: http://amsn-project.net/forums
MAKE SURE THAT YOU SEARCH THE FORUMS FIRST TO SEE IF IT WAS ALREADY REPORTED

Back to top

I want to report a bug, how do I open the status log and the protocol debugger?

Open your contact list and press the following key combinations :

status log: ctrl + s (Command-S on Mac OS X) protocol debug: ctrl + d (Command-D on Mac OS X)

Back to top

When I double click "amsn" file from a graphical file browser, like Konqueror or Nautilus, it opens a text editor instead of running aMSN. What shall I do (Linux)?

aMSN is written in Tcl/Tk, an interpreted language, so the "amsn" file is just a text file with the program code. The file manager might think it's a text file, so it will launch the text editor.

In Konqueror (KDE) or Nautilus (Gnome), running aMSN can be done by right-clicking the “amsn” file and choosing "Open with..." Konqueror) or "Launch with..." (Gnome), depending on the file browser.

Type "wish". This launches the "amsn" script.

Screenshot 4.5

If you are told the the "wish" command doesn't exist, you need to install Tcl/Tk.

Back to top

Sometimes aMSN "hangs", why is this?

When aMSN hangs it's usually a problem with the sound configuration. Perhaps you're playing a sound but the sound card is blocked, and the play command stops until the sound card is available. Try disabling sound or changing the sound command configuration.

If aMSN still hangs, and you are using a 2.6.x kernel, try running aMSN with:

  export LD_ASSUME_KERNEL=2.2.5 && amsn

This command will tell the dynamic linker to use the old thread model. For more information on this issue, see: http://people.redhat.com/drepper/assumekernel.html

If you are on Mac OS X it often happens when you receive a smiley on a chatwindow, it's a known issue.

Back to top

I try to run amsn but I get this error:

  bash: ./amsn: bad interpreter: No such file or directory

You need to install the tcl/tk packages, because you need the wish interpreter. If you think you have it, try typing:

  wish /usr/share/amsn/amsn

instead of:

  amsn

If this works, edit /usr/share/amsn/amsn and change the first line to :

  #!/usr/bin/wish

where /usr/bin/wish would be the location of the wish interpreter. You can find out the location of the 'wish' interpreter by typing :

  which wish

Back to top

Can I use aMSN behind a proxy server?

Yes, we provide support for HTTP and SOCKS5 proxies.

Back to top



I'm using aMSN behind a firewall, or using IP-Masquerade. Sending files won't work, can I fix it?

In this case, the firewall may be blocking incoming connections. File transfers work this way: When you want to send someone a file, you send an invitation with your IP address and a port number. Then the remote client must connect to your IP:port to start the transfer.

The used port is usually 6891, 6892 and so on (first transfer is on port 6891,but if you start a new file transfer while the first one hasn't finished yet, then it will use 6892, and so on).

If you are using a firewall, you must make sure that it allows incoming connections to port 6891 (and next ones if you want to be able to make more than one transfer at the same time).

If you are behind a router, enable port forwarding for ports 6891 to 6900 to your PC's internal IP address.

You can change the port value from the "Connection" tab of the Preferences window.

Back to top


With version 0.94 I could see when someone opened a conversation window with me, but since version 0.95 this doesn't happen anymore, why?

Users with MSN7 and later versions of MSN will automatically "open a conversation window" with you as soon as you (or they) connect. It is done automatically because they try to download your display picture. So, as soon as someone connects, the screen was flooded with windows from people just trying to download the display picture. This was annoying, so the feature was removed.

Note also that since Windows Live Messenger 8.0, the user would not join the chat until he sends the first message, so this is a second reason why it is not possible anymore.

Back to top

I liked the XXXX skin when using the previous version, but it seems to be incompatible with the latest version... when will it be ?

We don't know yet, check on the skin website or email the author of the skin to obtain more information or to ask him to update his skin to work better with the new version.

Back to top

As soon as I try to log on or change aMSN's language, it crashes with the following message: X Error of failed request: BadValue (integer parameter out of range for operation), Major opcode of failed request: 45 (X_OpenFont)

First of all, it may be a font problem: try making aMSN run with a different font (under Account -> Preferences -> Appearance).

Second, you may need to run aMSN using a different encoding (under Account -> Preferences -> Appearance again, utf-8 is a safe choice).

Third, try clearing your font cache with the command:

  fc-cache -fv

Then, make sure your locale (your LC_ALL or LC_CTYPE environment variable) is installed on your system:

  set | grep LC_ 

and make sure the corresponding directories (after the = ) exist on /usr/lib/locale . If they don't, install them according to your distribution.

Finally, if none of the above works, try disabling some FontPath's from /etc/X11/XF86Config or /etc/X11/Xorg.conf until you find out which font path contains problematic fonts, and recreate the fonts.cache , fonts.dir and fonts.scale in that directory.

Back to top

I try to run aMSN and it gives this error: Error in startup script: time value too large/small to represent while executing [...] procedure "ConvertLocalToUTC".

Make you sure the file /etc/localtime exists. If it doesn't, link it to /usr/share/zoneinfo/YOUR/TIME/ZONE and retry starting aMSN. To create the file under Linux : ln -s /usr/share/zoneinfo/YOUR/TIME/ZONE /etc/localtime

Back to top

Using aMSN

What are the keyboard shortcuts ?

For and up to date list of keyboard shortcuts, please read the Shortcuts page.

Back to top

What does the special icon on the right of the buddies mean?

The icon img/notinlist.png in the buddy list means that the corresponding contact do not have you in his list.

Back to top

Can I copy a contact address to the clipboard?

Yes, right click on that contact name on the contact list, then choose "Properties". In the new window, you can copy the email/nickname/personal message of the user.

Can I copy or open a URL address in a contact's nickname/personal message?

Yes, right click on that contact name on the contact list, then in the pop-up menu, You will have the choice to copy or open any URL in the contact's nickname or personal message.

Back to top

How can I set my personal message like in MSN7 ?

The Personal Message (PSM) is the text appearing under your nick. This feature is now available since aMSN 0.96.

To set your PSM, you need to click on the "Account" menu then "Change nick ...", there will be a field to change the PSM.

Back to top

How can I access the history of the messages I sent in my chat windows?

If you want to access previous messages you sent in your chat windows you only need to use the Control key with the arrows. It works the same way as in a shell so Ctrl-Up(Command-Up on MacOSX) gives you the previous message sent and Ctrl-Down(Command-Down on Mac OS X), the next one.

See the Shortcuts page for a list of all keyboard shortcuts.

Back to top

In the preferences' privacy tab, what do those four lists mean?

There are four lists, known as:

Allow List (AL), Block List (BL), Forward or Contact List (FL) and Reverse List (RL).

AL : This list contains the emails of people who are allowed to see you when you get online and they can also chat with you.

BL : This is the block list, which means it contains the list of people you are blocking. So this means they can't see you when you are online, and they can't chat with you.

FL : This list contains all contacts that are shown on your contact list.

RL : This is the reverse list, it contains the email addresses of people who have you in their list.


Back to top

In the preferences' privacy tab, what do the different colors in the contacts mean?

You should notice the colors in the list headers:

  • Allow List: green foreground
  • Block List: red foreground
  • Forward List: red background
  • Reverse List: yellow background

A contact in any list will take a different color depending the lists that contact is contained on:

  • If it's in Allow list, it will have green foreground.
  • If it's in Block list, it will have red foreground.
  • If it's in Forward and Reverse lists, it will have white background.
  • If it's in Forward list, but not in Reverse list, it will have red background.
  • If it's in Reverse list, but not in Forward list, it will have yellow background.
  • If it's not in Forward or Reverse list, it will have a black background.

Let's be a bit more specific:

  • Green font: the contact is able to contact you.
  • Red font: the contact is NOT able to contact you (BLOCKED).
  • White background: the contact has you in their contacts list and they are in yours.
  • Yellow background: the contact has you in their contacts list, but you no longer have them in yours.
  • Red background: the contact is in your contacts list, but you are not in theirs.
  • Black background: the contact has deleted you from their contacts list and you have deleted them from yours.

Back to top

I want to add my own custom smileys, how can I do it?

You may add custom smileys (also known as emoticons) by following these steps :

  • Open a chat window of any contact
  • Click the “Insert Emoticon” button found on the chat window (Screenshot 5.1)

Screenshot 5.1

  • Click the “Add new custom smiley” button (Screenshot 5.2)

Screenshot 5.2

  • Type a Description for your emoticon in the “Description” text box (Screenshot 5.3)

Screenshot 5.3

  • Type the Text triggers for your emoticon in the “Text triggers” text box. Text triggers are triggers which display an icon when they are typed and Enter is pressed. (Screenshot 5.3)
example: (test)

When (test) is typed in the chat window and Enter is pressed, the emoticon associated with the (test) Text trigger will be displayed.


  • Browse for the new emoticon that you would like to use by clicking the Browse button located to the right of the Smiley filename text box and select the image or emoticon that you would like to use. Click “Open”. (Screenshot 5.4)

Screenshot 5.4

If your image is larger than normal emoticons, you will see a message box saying “The smiley you choose is bigger than normal size. Do you want to resize it?” If you want your image or emoticon resized so that you can use it as an emoticon, simply click “Yes”

By clicking “Yes” your image may be scaled down and display incorrectly.

  • Click the “Insert Emoticon” button found on the chat window. You will now see your custom emoticon added to the emoticon chooser. (Screenshot 5.6)

Screenshot 5.6

Back to top

Nicknames are now truncated. Is it possible to revert back to full nicknames?

Yes. To have nicknames displayed in their full length on the contact list, in the alerts and the chat window, go to 'Tools' → 'Preferences' → 'Advanced Tab', and uncheck the selection which reads, Truncate nicknames longer than window width in window titles and contact list.” (Screenshot 5.7)

Screenshot 5.7

The same can be done for nicknames inside the chat window conversations by disabling the option “Truncate nicknames longer than window width inside conversations.”(Screenshot 5.7)

Back to top


How can I browse through my webcam logs and convert the .cam (cam recordings) to a movie file such as .mpeg?

The file format of those .cam files are a direct dump of the data received on the socket, which means it's in the MS proprietary format. For this reason, no player can play those files, only amsn.

Actually there's a tool to do it released by Hyriand (linux only). See http://amsn-project.net/forums/viewtopic.php?t=2954

Back to top


How can I make my webcam work?

If your webcam will not work with aMSN, please make sure your webcam is plugged in, turned on, and ready to be used.

Other applications that can be used to test if your webcam is working correctly on Linux:

XawTv

GnomeMeeting

V4L

On Mac you can try the macam project if you do not have an Apple iSight


Back to top

Where are the "stolen" display pictures saved?

  • Windows : C:\Documents andSettings\MyWindowsUsername\amsn\youremail_profile\displaypic\cache
  • Linux : /home/yourusername/.amsn/yourusername@youremail.com/displaypic/cache
  • Mac OS X: Home / Library / Application Support / your_email_profile / displaypic / cache

You can also access all the previous display pictures of a user from :

  • The contact's properties page
  • The "Change Display picture" window

Back to top

How can I change the directory where the profiles information are saved ?

There is no option to do this, you have to modify the code of aMSN, but it is not complicated. In the aMSN folder, look for a amsn (/usr/share/amsn/amsn) file and open it for editing with your favorite text editor. Search for the following code :

  } elseif {$tcl_platform(platform) == "windows"} {
    if {[info exists env(USERPROFILE)]} {
       set HOME "[file join $env(USERPROFILE) amsn]"
       set files_dir "[file join $env(USERPROFILE) amsn_received]"
    } else {
     set HOME "[file join [pwd] amsn_config]"
     set files_dir "[file join [pwd] amsn_received]"
    }

change it to

  } elseif {$tcl_platform(platform) == "windows"} {
     set HOME "[file join [pwd] amsn_config]"
     set files_dir "[file join [pwd] amsn_received]"</nowiki>

in order to save the files in the directory where aMSN is launched.

Back to top

Running on Linux

How can I use anti-aliased fonts in aMSN?

Use a distro that has tcl/tk 8.5 or higher, or take a look at: Enabling_antialiasing That page will provide you information on how to re-compile Tk with anti-alias support.

Back to top

How do I create a shortcut to aMSN on my desktop on Linux?

  • KDE
    • Right-click on the K-menu and a Panel Menu will appear as seen in the screenshot below:

Image:screenshot-4-5.jpg

    • Click Add Non-KDE Application
    • A Non-KDE Application Configuration dialog box will be displayed
    • Enter the text as shown below:

Image:screenshot-4-6.jpg

    • Click “OK” and an aMSN icon will be added to your kicker menu :
    • If you want to change the icon or other configurations, simply right-click the new aMSN button, and a menu will be displayed. Click “Configure aMSN Button...” and the Non-KDE Application Configuration will be displayed.

Image:screenshot-4-7.jpg


Back to top

How do I open file-transfer ports in SUSE Linux?

(Guide thanks to John Hillier)

  • Open 'YaST' -> 'Security and Users' -> 'Firewall' -> 'Firewall Configuration'.
  • Click on "Expert" in 'Additional Services' and add port 6891.

Back to top


My aMSN sound notifications are not being played until I stop playing my music. How can I fix this so I can hear both at the same time?

  • KDE: You can configure XMMS, amaroK, etc. to play sound through arts, and use artsplay as sound play command for aMSN which is able to mix sounds.
  • Gnome: You can use esdplay and configure XMMS for playing through ESD.

Back to top

When I try running aMSN, I get an error "unknown color Black". How can I fix it ?

This problem is not coming from aMSN, it's an Xorg faulty installation. You probably have a bad Xorg configuration for the file rgb.txt (especially with some versions of Xgl).

If you are using xgl, you most probably have the file rgb.txt in /etc/X11 . Xgl in Ubuntu Dapper is usually misconfigured and looks for the file in /usr/share/X11 . Make a symlink to it in /usr/share/X11 and restart your X server.

If you are not using xgl, open your /etc/X11/xorg.conf and look for a line that says:


  Section "Files"
       RgbPath      "/etc/X11/rgb"


If the RgbPath line does not exist at all, add it under the section "Files". Then make sure the file exists in the directory defined in RgbPath (/etc/X11/ in this case). You may need to copy it from another location in your computer, or you can download it from http://amsn.sourceforge.net/rgb.txt . You must also restart your X server for the changes to take effect. PLEASE NOTE: the line in xorg.conf must NOT contain the extension of the file!!!

Back to top

TLS does not seem to work and I have tcl/tk 8.5. How can I fix it ?

TLS 1.5 is broken, in order to fix it, you have to find out where your copy of TLS is with :

 locate tls.tcl

or if you do not use locate :

 find / -name tls.tcl

Those commands should give you something like /usr/lib/tls1.50/tls.tcl. In the same directory, you should find a file named pkgIndex.tcl. Edit this file with your favorite editor (vi, emacs, nano/pico, etc..) :

 vi /usr/lib/tls1.50/pkgIndex.tcl

and change the line :

 package ifneeded tls 1.5

by

 package ifneeded tls 1.50

TLS should now work well. If it not the case, please let us know on the forums

Back to top

aMSN does not seem to work correctly with some files, especially files containing the character ` (back quote). How to fix it ?

aMSN cannot handle files containing the character `(back quote) in their path. A way to resolve this issue is to mount the partition containing the file with this caracter with the 'utf8' option. Refer to the man page of your version of mount to find the right option for your file system.

Back to top

Running on Windows

How can I prevent/make aMSN from loading on windows start ?

You can do that by clicking on the checkbox 'load aMSN at Windows start' in Account -> Preferences -> Session

Back to top

Whenever I go to preferences->session, the 'load amsn at windows start' is disabled, even if it does load at windows start !

We cannot detect if aMSN loads at Windows start so the checkbox is disabled. However, the change is taken in consideration if you modified the value and then press the "Save"' button.

Back to top

Running on Mac OS X

I have a question about Mac OS X, where can I go to find answers?

You can get answers to questions about Mac OS X on the aMSN Mac Forum found at: http://forums.cocoaforge.com/viewforum.php?f=14

Why do some characters in the aMSN contact list appear as squares?

These are Unicode characters. Unicode support has been added for Mac OS X since version 0.96 of aMSN.

Why can't I use the shortcut Command-Space to switch keyboard layouts?

This seems to be an issue with the Tcl/Tk frameworks that aMSN depends on. It is currently being looked into.

How do I sign into more than one account with Mac aMSN?

You need to duplicate the aMSN application, and then run both copies. The easiest way to do this, is to find the application in Finder, and press Command-D to duplicate the application.

aMSN is incredibly slow on my new Intel Mac, what can I do to speed it up?

aMSN 0.96 is the first Universal binary version of aMSN, please update to at least that version. You can further speed up aMSN by turning off smileys in the contact list (the option is in aMSN's preferences under the Appearence tab), and also by colapsing your offline group.

Webcam doesn't work on my Intel Mac!

Update to the latest aMSN version (0.97 or higher), and you will then be able to use webcam!

How do I update aMSN to the latest development version on a Mac?

Up to date instructions on how to do this can be found at the SVN wiki page.

I want to delete aMSN but I cannot empty the Trash!

You may be getting erros like "libtls.dylib is in use". To delete the files, you need to restart your computer, and then you will be able to delete the files.

Where are aMSN's preferences files stored on a Mac?

They're stored at: Your Home Folder -> Library -> Application Support -> amsn .

Back to top

Other Questions

I noticed aMSN is opening some ports over port 60000. Is it normal? Is it a backdoor? Why does this happen?

This is normal. aMSN uses sockets as a locking system to avoid two aMSN instances use the same profile at once (which could cause trouble). This is the better platform independent locking system we found.

If you check ~/.amsn/profiles, you can see what port is used for each profile.

Back to top

What is the Audio and Video Assistant?

The Audio and Video Assistant is an easy way to configure and fine-tune your webcam as well as your audio input (microphone). The Audio and Video Assistant provides options to maximize the quality of your webcam broadcast.

The Audio and Video Assistant can be started from within a chat window by clicking 'Edit' → 'Edit audio and video settings'. The Configure Webcam dialog will then be shown. You may change your video settings by clicking “Change video settings” button.

You can also start the assistant using the Ctrl-N shortcut from the main window. Refer to the Shortcuts page for an up to date list of keyboard shortcuts.

Back to top

How do I remove aMSN completely?

After uninstalling aMSN, your profiles (per account settings, log files, etc..) are still stored on your system. You may remove them by following these simple procedures :

  • Linux:
 rm -rf ~/.amsn
  • Windows:

Delete C:\Documents and Settings\$USER\amsn where $USER is your username.

  • Mac OS X

Remove the aMSN application. Remove this folder : Home / Library / Application Support / aMSN

Back to top

The mail traydock icon in the system tray continues to show up, how do I get rid of it?

You must read your unread mails to make the traydock icon disappear.

Back to top

I enabled the logging of conversations on aMSN, but I cannot find the logfiles. Where are they stored?

In order for logging to be enabled, you must first create a profile. This can be done at the aMSN login-screen by enabling the "Remember me" option.


You will then find the log here here:

  • Linux: ~/.amsn/your_email_profile/logs
  • Windows: %USERPROFILE%\amsn\your_email_profile\logs Where %USERPROFILE% is usually

C:\Documents and Settings\%user% where %user% is the username of your Windows account.

  • Mac OS X: /Home / Library / Application Support / aMSN / your_email_profile / logs

Back to top

Can I disable custom and/or animated smileys?

Choose the Preferences option from the Account menu, then click on the tab that says Appearance. Here you can set the various options regarding Emotions Icons and Smileys.

Back to top

Why doesn't aMSN support audio / Why did aMSN drop linphone support?

  • The support of Linphone in aMSN has been dropped some time ago because it was not complete and difficult to maintain. Moreover, the only person able to make it work and to resume its development is no more active in the aMSN's development, so the support has just been dropped.
  • Now aMSN supports webcam session (not videconference), this support is complete and stable and easier to maintain.
  • About Audio support, it is delayed for a next release. Farsight project, developped by Burgerman will give audio support to aMSN, we are just waiting for a stable version.

Back to top

I have another question, can you help me?

Yes, we can. But before asking questions, search this wiki for your question. If you couldn't find it, then take a look at the aMSN forums found at: http://amsn-project.net/forums

Make sure you SEARCH before posting

Most likely your question has already been answered. You can also view more information at aMSN's sourceforge project page, which is located at: http://sourceforge.net/projects/amsn

Before submitting a bug report or asking for support, please document the following information:


  • aMSN version :
  • Tcl and Tk version :
  • Kernel version :
  • Distribution :
  • System architecture (32-bit, PPC, 64-bit, etc.) :
  • Stack trace of the submitted error (if applicable) :
  • Last error messages in debug windows (Ctrl+D and Ctrl+S in contact list) :
  • Possible ways to replicate the bug :

Here's an example of a user's documentation :

  • aMSN version : 0.96
  • Tcl and Tk version : 8.4.16
  • Kernel version : Linux 2.6.12-8-386 (Found by typing: uname -s -r in an xterm)
  • Distribution : Debian
  • System architecture (32-bit, PPC, 64-bit, etc.) : 32-bit
  • Stack trace of the submitted error (if applicable) : NA (not applicable)
  • Last error messages in debug windows (Ctrl+D and Ctrl+S in contact list) :
  • Possible ways to replicate the bug : Open a chat window and send a custom emoticon which is animated to an msn 7.5 user.

Send this information with your bug report so that we may further investigate the issue.


If you still have a question that has not been covered in this FAQ, you can visit the aMSN forum at: http://amsn-project.net/forums or contact us on IRC (Internet Relay Chat) at :

server: irc.freenode.net channel: #amsn


There is a bot on the channel that is able to give you some indications if you use the following commands :

  • amsn install
  • amsn version
  • amsn download
  • amsn tcl/tk version
  • amsn libstd
  • amsn svn

... and some others

In case you have some trouble to connect to our IRC channel because of network policies, you can try this http://cgiirc.blitzed.org/

Back to top

Enjoy using aMSN!

amsn-0.98.9/FAQ0000644000175000017500000010641010734014202012716 0ustar billiobbilliobFrequently Asked Questions The latest version of this FAQ can be found at http://amsn-project.net/faq.php FAQ 2.1.0 Contents 1 What is aMSN? 1.1 What is aMSN? 1.2 What do I need to run aMSN? 2 Where can I get aMSN ? 3 Troubleshooting 3.1 Why are arabic fonts displayed from left to right instead of right to left? 3.2 I have enabled the traydock icon, but when I minimize aMSN, it is still shown in both the taskbar and the tray. How can I make it display in the tray only? 3.3 When I close aMSN's window, it quits instead of minimizing to tray 3.4 I don't see the traydock even if I enabled it, what's the problem? 3.5 Does aMSN run on 64-bit systems? 3.6 When notify window pops up, the windows taskbar partially hides it, can I fix this? 3.7 Can I see who blocked me? 3.8 My jpeg webcam does not currently work, will my jpeg webcam work in the future (example: D-link dsb-c310)? 3.9 Why can't I receive acceptable quality images from my contacts using aMSN? 3.10 I can't read Chinese or Japanese with aMSN, even after changing the text encoding. Where can I find help? 3.11 How do I capture bug report information from a segmentation fault? (LINUX) 3.12 I want to report a bug, how do I open the status log and the protocol debugger? 3.13 When I double click "amsn" file from a graphical file browser, like Konqueror or Nautilus, it opens a text editor instead of running aMSN. What shall I do (Linux)? 3.14 Sometimes aMSN "hangs", why is this? 3.15 I try to run amsn but I get this error: 3.16 Can I use aMSN behind a proxy server? 3.17 I'm using aMSN behind a firewall, or using IP-Masquerade. Sending files won't work, can I fix it? 3.18 With version 0.94 I could see when someone opened a conversation window with me, but since version 0.95 this doesn't happen anymore, why? 3.19 I liked the XXXX skin when using the previous version, but it seems to be incompatible with the latest version... when will it be ? 3.20 As soon as I try to log on or change aMSN's language, it crashes with the following message: X Error of failed request: BadValue (integer parameter out of range for operation), Major opcode of failed request: 45 (X_OpenFont) 3.21 I try to run aMSN and it gives this error: Error in startup script: time value too large/small to represent while executing [...] procedure "ConvertLocalToUTC". 4 Using aMSN 4.1 What are the keyboard shortcuts ? 4.2 What does the special icon on the right of the buddies mean? 4.3 Can I copy a contact address to the clipboard? 4.4 Can I copy or open a URL address in a contact's nickname/personal message? 4.5 How can I set my personal message like in MSN7 ? 4.6 How can I access the history of the messages I sent in my chat windows? 4.7 In the preferences' privacy tab, what do those four lists mean? 4.8 In the preferences' privacy tab, what do the different colors in the contacts mean? 4.9 I want to add my own custom smileys, how can I do it? 4.10 Nicknames are now truncated. Is it possible to revert back to full nicknames? 4.11 How can I browse through my webcam logs and convert the .cam (cam recordings) to a movie file such as .mpeg? 4.12 How can I make my webcam work? 4.13 Where are the "stolen" display pictures saved? 4.14 How can I change the directory where the profiles information are saved ? 5 Running on Linux 5.1 How can I use anti-aliased fonts in aMSN? 5.2 How do I create a shortcut to aMSN on my desktop on Linux? 5.3 How do I open file-transfer ports in SUSE Linux? 5.4 My aMSN sound notifications are not being played until I stop playing my music. How can I fix this so I can hear both at the same time? 5.5 When I try running aMSN, I get an error "unknown color Black". How can I fix it ? 5.6 TLS does not seem to work and I have tcl/tk 8.5. How can I fix it ? 5.7 aMSN does not seem to work correctly with some files, especially files containing the character ` (back quote). How to fix it ? 6 Running on Windows 6.1 How can I prevent/make aMSN from loading on windows start ? 6.2 Whenever I go to preferences->session, the 'load amsn at windows start' is disabled, even if it does load at windows start ! 7 Running on Mac OS X 7.1 I have a question about Mac OS X, where can I go to find answers? 7.2 Why do some characters in the aMSN contact list appear as squares? 7.3 Why can't I use the shortcut Command-Space to switch keyboard layouts? 7.4 How do I sign into more than one account with Mac aMSN? 7.5 aMSN is incredibly slow on my new Intel Mac, what can I do to speed it up? 7.6 Webcam doesn't work on my Intel Mac! 7.7 How do I update aMSN to the latest development version on a Mac? 7.8 I want to delete aMSN but I cannot empty the Trash! 7.9 Where are aMSN's preferences files stored on a Mac? 8 Other Questions 8.1 I noticed aMSN is opening some ports over port 60000. Is it normal? Is it a backdoor? Why does this happen? 8.2 What is the Audio and Video Assistant? 8.3 How do I remove aMSN completely? 8.4 The mail traydock icon in the system tray continues to show up, how do I get rid of it? 8.5 I enabled the logging of conversations on aMSN, but I cannot find the logfiles. Where are they stored? 8.6 Can I disable custom and/or animated smileys? 8.7 Why doesn't aMSN support audio / Why did aMSN drop linphone support? 8.8 I have another question, can you help me? === What is aMSN? === == What is aMSN? == aMSN is a Microsoft Messenger clone. It allows you to keep in touch with your friends and exchange instant messages and files. == What do I need to run aMSN? == Windows and Mac OS X. aMSN will run right out of the box if you download the official packages, which can be found at http://amsn.sourceforge.net/download.php. Linux. You will need Tcl 8.4 / Tk 8.4 or above in order to run aMSN. These two packages (Tcl & Tk) are usually installed by default on most distributions. These can also be installed as a dependency if your packaging system supports it (rpm, deb, etc.). If for some reason your distribution does not currently provide you with Tcl 8.4 or Tk 8.4, you may download them and follow the installation instructions at http://tcl.tk. == Where can I get aMSN ? == You can download the packages of aMSN at http://amsn.sourceforge.net/download.php. For Linux users : You can also get aMSN using your distribution's package management system (apt-get install amsn for debian/ubuntu for example). === Troubleshooting === == Why are arabic fonts displayed from left to right instead of right to left? == Windows: Go to 'Control Panel' ? 'Regional and Language Options' ? Languages tab, and enable the option "Install files for complex scripts and right-to-left languages" Linux: Installing the Arabic locale should solve this issue. == I have enabled the traydock icon, but when I minimize aMSN, it is still shown in both the taskbar and the tray. How can I make it display in the tray only? == The first time you will close aMSN with the 'X' button in the main window's border. It should ask you if you want to quit or minimize it to tray. You must choose the 'Minimize to Tray' option if you want it to disappear from the taskbar. Alternatively, you can also click the "Minimize to Tray" option from the Account menu. == When I close aMSN's window, it quits instead of minimizing to tray == The first time you will close aMSN with the 'X' button in the main window's border. It should ask you if you want to quit or minimize it to tray. You must choose the 'Minimize to Tray' option if you want it to minimize to the tray. If you chose 'Quit' and enabled the "Remember my choice" option, it will always quit and will not ask you again. If you want to change this behavior and want it to ask you again so you can change your choice, you will have to do the following procedure : Press Ctrl-Shift-C from aMsn's main window, a new window titled "Console" will appear in which you can type commands. Type the following and press enter : ::config::setKey closingdocks 0 You can now close this new Console window and the next time you close aMSN's main window, it will ask you again to make a choice. == I don't see the traydock even if I enabled it, what's the problem? == Linux: Make sure the file msn/utils/linux/traydock/libtray.so exists. If it does not exist, make sure you download an official package of aMSN at: http://amsn-project.net/download.php If you compiled aMSN yourself, please make sure you have the X11 development packages installed and follow this page to compile aMSN correctly : http://amsn-project.net/wiki/Compiling_aMSN NOTE: There is no traydock icon on Mac OS X == Does aMSN run on 64-bit systems? == Yes, many users have been able to run aMSN on 64-bit architectures. However, you will have to compile tcltls by yourself. There isn't a package for x84_64 on the aMSN site so you need to download it from: [1] == When notify window pops up, the windows taskbar partially hides it, can I fix this? == Yes, you can move the notify window X pixels to the left and Y pixels to the top. You can customize this by modifying the "X Offset" and "Y Offset" values in (menu) 'Account' ? 'Preferences' ? 'Advanced' ? Offset the position of the notification pop-up. and clicking Save to save your modifications. == Can I see who blocked me? == No, this feature is no longer available because the block detection bug that was happening in the Microsoft servers has now been fixed. There is NO safe way to know if someone blocked you == My jpeg webcam does not currently work, will my jpeg webcam work in the future (example: D-link dsb-c310)? == JPEG webcams support is currently supported since the 0.97 version of aMSN. If you are using a version prior to 0.97, please update to the latest version of aMSN. == Why can't I receive acceptable quality images from my contacts using aMSN? == If the image is of a poor quality, it's probably because the other user's webcam is of poor quality. aMSN's quality of the webcam is the same as the official msn client. == I can't read Chinese or Japanese with aMSN, even after changing the text encoding. Where can I find help? == Please read the documentation about getting SCIM to work with aMSN (http://amsn-project.net/wiki/SCIM_Input ) == How do I capture bug report information from a segmentation fault? (LINUX) == Make sure amsn was compiled with debugging symbols, if you installed it using a binary package, you should probably download from source and recompile it. To enable debugging symbols, configure it with : ./configure --enable-debug If you're unable to compile it, then you can still send us information without the debugging symbols. Once it is compiled/installed, go to the directory where you have installed aMSN (example: /usr/share/amsn or /home/yourusername/amsn-0.95/) type: $ gdb --args wish amsn (gdb) run [then when it segfaults, type] (gdb) bt (gdb) bt full You will then receive the bug report information. Please report this information to the forums: http://amsn-project.net/forums MAKE SURE THAT YOU SEARCH THE FORUMS FIRST TO SEE IF IT WAS ALREADY REPORTED == I want to report a bug, how do I open the status log and the protocol debugger? == Open your contact list and press the following key combinations : status log: ctrl + s (Command-S on Mac OS X) protocol debug: ctrl + d (Command-D on Mac OS X) == When I double click "amsn" file from a graphical file browser, like Konqueror or Nautilus, it opens a text editor instead of running aMSN. What shall I do (Linux)? == aMSN is written in Tcl/Tk, an interpreted language, so the "amsn" file is just a text file with the program code. The file manager might think it's a text file, so it will launch the text editor. In Konqueror (KDE) or Nautilus (Gnome), running aMSN can be done by right-clicking the amsn file and choosing "Open with..." Konqueror) or "Launch with..." (Gnome), depending on the file browser. Type "wish". This launches the "amsn" script. If you are told the the "wish" command doesn't exist, you need to install Tcl/Tk. == Sometimes aMSN "hangs", why is this? == When aMSN hangs it's usually a problem with the sound configuration. Perhaps you're playing a sound but the sound card is blocked, and the play command stops until the sound card is available. Try disabling sound or changing the sound command configuration. If aMSN still hangs, and you are using a 2.6.x kernel, try running aMSN with: export LD_ASSUME_KERNEL=2.2.5 && amsn This command will tell the dynamic linker to use the old thread model. For more information on this issue, see: http://people.redhat.com/drepper/assumekernel.html If you are on Mac OS X it often happens when you receive a smiley on a chatwindow, it's a known issue. == I try to run amsn but I get this error: == bash: ./amsn: bad interpreter: No such file or directory You need to install the tcl/tk packages, because you need the wish interpreter. If you think you have it, try typing: wish /usr/share/amsn/amsn instead of: amsn If this works, edit /usr/share/amsn/amsn and change the first line to : #!/usr/bin/wish where /usr/bin/wish would be the location of the wish interpreter. You can find out the location of the 'wish' interpreter by typing : which wish == Can I use aMSN behind a proxy server? == Yes, we provide support for HTTP and SOCKS5 proxies. == I'm using aMSN behind a firewall, or using IP-Masquerade. Sending files won't work, can I fix it? == In this case, the firewall may be blocking incoming connections. File transfers work this way: When you want to send someone a file, you send an invitation with your IP address and a port number. Then the remote client must connect to your IP:port to start the transfer. The used port is usually 6891, 6892 and so on (first transfer is on port 6891,but if you start a new file transfer while the first one hasn't finished yet, then it will use 6892, and so on). If you are using a firewall, you must make sure that it allows incoming connections to port 6891 (and next ones if you want to be able to make more than one transfer at the same time). If you are behind a router, enable port forwarding for ports 6891 to 6900 to your PC's internal IP address. You can change the port value from the "Connection" tab of the Preferences window. == With version 0.94 I could see when someone opened a conversation window with me, but since version 0.95 this doesn't happen anymore, why? == Users with MSN7 and later versions of MSN will automatically "open a conversation window" with you as soon as you (or they) connect. It is done automatically because they try to download your display picture. So, as soon as someone connects, the screen was flooded with windows from people just trying to download the display picture. This was annoying, so the feature was removed. Note also that since Windows Live Messenger 8.0, the user would not join the chat until he sends the first message, so this is a second reason why it is not possible anymore. == I liked the XXXX skin when using the previous version, but it seems to be incompatible with the latest version... when will it be ? == We don't know yet, check on the skin website or email the author of the skin to obtain more information or to ask him to update his skin to work better with the new version. == As soon as I try to log on or change aMSN's language, it crashes with the following message: X Error of failed request: BadValue (integer parameter out of range for operation), Major opcode of failed request: 45 (X_OpenFont) == First of all, it may be a font problem: try making aMSN run with a different font (under Account -> Preferences -> Appearance). Second, you may need to run aMSN using a different encoding (under Account -> Preferences -> Appearance again, utf-8 is a safe choice). Third, try clearing your font cache with the command: fc-cache -fv Then, make sure your locale (your LC_ALL or LC_CTYPE environment variable) is installed on your system: set | grep LC_ and make sure the corresponding directories (after the = ) exist on /usr/lib/locale . If they don't, install them according to your distribution. Finally, if none of the above works, try disabling some FontPath's from /etc/X11/XF86Config or /etc/X11/Xorg.conf until you find out which font path contains problematic fonts, and recreate the fonts.cache , fonts.dir and fonts.scale in that directory. == I try to run aMSN and it gives this error: Error in startup script: time value too large/small to represent while executing [...] procedure "ConvertLocalToUTC". == Make you sure the file /etc/localtime exists. If it doesn't, link it to /usr/share/zoneinfo/YOUR/TIME/ZONE and retry starting aMSN. To create the file under Linux : ln -s /usr/share/zoneinfo/YOUR/TIME/ZONE /etc/localtime === Using aMSN === == What are the keyboard shortcuts ? == For and up to date list of keyboard shortcuts, please read the http://amsn-project.net/wiki/Shortcuts page. == What does the special icon on the right of the buddies mean? == The icon [white X on red round background] in the buddy list means that the corresponding contact do not have you in his list. == Can I copy a contact address to the clipboard? == Yes, right click on that contact name on the contact list, then choose "Properties". In the new window, you can copy the email/nickname/personal message of the user. == Can I copy or open a URL address in a contact's nickname/personal message? == Yes, right click on that contact name on the contact list, then in the pop-up menu, You will have the choice to copy or open any URL in the contact's nickname or personal message. == How can I set my personal message like in MSN7 ? == The Personal Message (PSM) is the text appearing under your nick. This feature is now available since aMSN 0.96. To set your PSM, you need to click on the "Account" menu then "Change nick ...", there will be a field to change the PSM. == How can I access the history of the messages I sent in my chat windows? == If you want to access previous messages you sent in your chat windows you only need to use the Control key with the arrows. It works the same way as in a shell so Ctrl-Up(Command-Up on MacOSX) gives you the previous message sent and Ctrl-Down(Command-Down on Mac OS X), the next one. See the http://amsn-project.net/wiki/Shortcuts page for a list of all keyboard shortcuts. == In the preferences' privacy tab, what do those four lists mean? == There are four lists, known as: Allow List (AL), Block List (BL), Forward or Contact List (FL) and Reverse List (RL). AL : This list contains the emails of people who are allowed to see you when you get online and they can also chat with you. BL : This is the block list, which means it contains the list of people you are blocking. So this means they can't see you when you are online, and they can't chat with you. FL : This list contains all contacts that are shown on your contact list. RL : This is the reverse list, it contains the email addresses of people who have you in their list. == In the preferences' privacy tab, what do the different colors in the contacts mean? == You should notice the colors in the list headers: Allow List: green foreground Block List: red foreground Forward List: red background Reverse List: yellow background A contact in any list will take a different color depending the lists that contact is contained on: If it's in Allow list, it will have green foreground. If it's in Block list, it will have red foreground. If it's in Forward and Reverse lists, it will have white background. If it's in Forward list, but not in Reverse list, it will have red background. If it's in Reverse list, but not in Forward list, it will have yellow background. If it's not in Forward or Reverse list, it will have a black background. Let's be a bit more specific: Green font: the contact is able to contact you. Red font: the contact is NOT able to contact you (BLOCKED). White background: the contact has you in their contacts list and they are in yours. Yellow background: the contact has you in their contacts list, but you no longer have them in yours. Red background: the contact is in your contacts list, but you are not in theirs. Black background: the contact has deleted you from their contacts list and you have deleted them from yours. == I want to add my own custom smileys, how can I do it? == You may add custom smileys (also known as emoticons) by following these steps : Open a chat window of any contact Click the Insert Emoticon button found on the chat window (Screenshot 5.1) Click the Add new custom smiley button (Screenshot 5.2) Type a Description for your emoticon in the Description text box (Screenshot 5.3) Type the Text triggers for your emoticon in the Text triggers text box. Text triggers are triggers which display an icon when they are typed and Enter is pressed. (Screenshot 5.3) example: (test) When (test) is typed in the chat window and Enter is pressed, the emoticon associated with the (test) Text trigger will be displayed. Browse for the new emoticon that you would like to use by clicking the Browse button located to the right of the Smiley filename text box and select the image or emoticon that you would like to use. Click Open. (Screenshot 5.4) If your image is larger than normal emoticons, you will see a message box saying The smiley you choose is bigger than normal size. Do you want to resize it? If you want your image or emoticon resized so that you can use it as an emoticon, simply click Yes (Screenshot 5.5) By clicking Yes your image may be scaled down and display incorrectly. Click the Insert Emoticon button found on the chat window. You will now see your custom emoticon added to the emoticon chooser. (Screenshot 5.6) == Nicknames are now truncated. Is it possible to revert back to full nicknames? == Yes. To have nicknames displayed in their full length on the contact list, in the alerts and the chat window, go to 'Tools' ? 'Preferences' ? 'Advanced Tab', and uncheck the selection which reads, Truncate nicknames longer than window width in window titles and contact list. (Screenshot 5.7) The same can be done for nicknames inside the chat window conversations by disabling the option Truncate nicknames longer than window width inside conversations.(Screenshot 5.7) == How can I browse through my webcam logs and convert the .cam (cam recordings) to a movie file such as .mpeg? == The file format of those .cam files are a direct dump of the data received on the socket, which means it's in the MS proprietary format. For this reason, no player can play those files, only amsn. Actually there's a tool to do it released by Hyriand (linux only). See http://amsn-project.net/forums/viewtopic.php?t=2954 == How can I make my webcam work? == If your webcam will not work with aMSN, please make sure your webcam is plugged in, turned on, and ready to be used. Other applications that can be used to test if your webcam is working correctly on Linux: XawTv GnomeMeeting V4L On Mac you can try the macam project if you do not have an Apple iSight == Where are the "stolen" display pictures saved? == Windows : C:\Documents andSettings\MyWindowsUsername\amsn\youremail_profile\displaypic\cache Linux : /home/yourusername/.amsn/yourusername@youremail.com/displaypic/cache Mac OS X: Home / Library / Application Support / your_email_profile / displaypic / cache You can also access all the previous display pictures of a user from : The contact's properties page The "Change Display picture" window == How can I change the directory where the profiles information are saved ? == There is no option to do this, you have to modify the code of aMSN, but it is not complicated. In the aMSN folder, look for a amsn (/usr/share/amsn/amsn) file and open it for editing with your favorite text editor. Search for the following code : } elseif {$tcl_platform(platform) == "windows"} { if {[info exists env(USERPROFILE)]} { set HOME "[file join $env(USERPROFILE) amsn]" set files_dir "[file join $env(USERPROFILE) amsn_received]" } else { set HOME "[file join [pwd] amsn_config]" set files_dir "[file join [pwd] amsn_received]" } change it to } elseif {$tcl_platform(platform) == "windows"} { set HOME "[file join [pwd] amsn_config]" set files_dir "[file join [pwd] amsn_received]" in order to save the files in the directory where aMSN is launched. === Running on Linux === == How can I use anti-aliased fonts in aMSN? == Use a distro that has tcl/tk 8.5 or higher, or take a look at: http://amsn-project.net/wiki/Enabling_antialiasing That page will provide you information on how to re-compile Tk with anti-alias support. == How do I create a shortcut to aMSN on my desktop on Linux? == KDE Right-click on the K-menu and a Panel Menu will appear as seen in the screenshot below: Click Add Non-KDE Application A Non-KDE Application Configuration dialog box will be displayed Enter the text as shown below: Click OK and an aMSN icon will be added to your kicker menu : If you want to change the icon or other configurations, simply right-click the new aMSN button, and a menu will be displayed. Click Configure aMSN Button... and the Non-KDE Application Configuration will be displayed. == How do I open file-transfer ports in SUSE Linux?== (Guide thanks to John Hillier) Open 'YaST' -> 'Security and Users' -> 'Firewall' -> 'Firewall Configuration'. Click on "Expert" in 'Additional Services' and add port 6891. My aMSN sound notifications are not being played until I stop playing my music. How can I fix this so I can hear both at the same time? KDE: You can configure XMMS, amaroK, etc. to play sound through arts, and use artsplay as sound play command for aMSN which is able to mix sounds. Gnome: You can use esdplay and configure XMMS for playing through ESD. == When I try running aMSN, I get an error "unknown color Black". How can I fix it ?== This problem is not coming from aMSN, it's an Xorg faulty installation. You probably have a bad Xorg configuration for the file rgb.txt (especially with some versions of Xgl). If you are using xgl, you most probably have the file rgb.txt in /etc/X11 . Xgl in Ubuntu Dapper is usually misconfigured and looks for the file in /usr/share/X11 . Make a symlink to it in /usr/share/X11 and restart your X server. If you are not using xgl, open your /etc/X11/xorg.conf and look for a line that says: Section "Files" RgbPath "/etc/X11/rgb" If the RgbPath line does not exist at all, add it under the section "Files". Then make sure the file exists in the directory defined in RgbPath (/etc/X11/ in this case). You may need to copy it from another location in your computer, or you can download it from http://amsn.sourceforge.net/rgb.txt . You must also restart your X server for the changes to take effect. PLEASE NOTE: the line in xorg.conf must NOT contain the extension of the file!!! TLS does not seem to work and I have tcl/tk 8.5. How can I fix it ? TLS 1.5 is broken, in order to fix it, you have to find out where your copy of TLS is with : locate tls.tcl or if you do not use locate : find / -name tls.tcl Those commands should give you something like /usr/lib/tls1.50/tls.tcl. In the same directory, you should find a file named pkgIndex.tcl. Edit this file with your favorite editor (vi, emacs, nano/pico, etc..) : vi /usr/lib/tls1.50/pkgIndex.tcl and change the line : package ifneeded tls 1.5 by package ifneeded tls 1.50 TLS should now work well. If it not the case, please let us know on the forums == aMSN does not seem to work correctly with some files, especially files containing the character ` (back quote). How to fix it ? == aMSN cannot handle files containing the character `(back quote) in their path. A way to resolve this issue is to mount the partition containing the file with this caracter with the 'utf8' option. Refer to the man page of your version of mount to find the right option for your file system. === Running on Windows === == How can I prevent/make aMSN from loading on windows start ? == You can do that by clicking on the checkbox 'load aMSN at Windows start' in Account -> Preferences -> Session == Whenever I go to preferences->session, the 'load amsn at windows start' is disabled, even if it does load at windows start ! == We cannot detect if aMSN loads at Windows start so the checkbox is disabled. However, the change is taken in consideration if you modified the value and then press the "Save"' button. === Running on Mac OS X === == I have a question about Mac OS X, where can I go to find answers? == You can get answers to questions about Mac OS X on the aMSN Mac Forum found at: http://forums.cocoaforge.com/viewforum.php?f=14 == Why do some characters in the aMSN contact list appear as squares? == These are Unicode characters. Unicode support has been added for Mac OS X since version 0.96 of aMSN. == Why can't I use the shortcut Command-Space to switch keyboard layouts? == This seems to be an issue with the Tcl/Tk frameworks that aMSN depends on. It is currently being looked into. == How do I sign into more than one account with Mac aMSN? == You need to duplicate the aMSN application, and then run both copies. The easiest way to do this, is to find the application in Finder, and press Command-D to duplicate the application. == aMSN is incredibly slow on my new Intel Mac, what can I do to speed it up? == aMSN 0.96 is the first Universal binary version of aMSN, please update to at least that version. You can further speed up aMSN by turning off smileys in the contact list (the option is in aMSN's preferences under the Appearence tab), and also by colapsing your offline group. == Webcam doesn't work on my Intel Mac! == Update to the latest aMSN version (0.97 or higher), and you will then be able to use webcam! == How do I update aMSN to the latest development version on a Mac? == Up to date instructions on how to do this can be found at the http://amsn-project.net/wiki/SVN wiki page. == I want to delete aMSN but I cannot empty the Trash! == You may be getting erros like "libtls.dylib is in use". To delete the files, you need to restart your computer, and then you will be able to delete the files. == Where are aMSN's preferences files stored on a Mac? == They're stored at: Your Home Folder -> Library -> Application Support -> amsn . === Other Questions === == I noticed aMSN is opening some ports over port 60000. Is it normal? Is it a backdoor? Why does this happen? == This is normal. aMSN uses sockets as a locking system to avoid two aMSN instances use the same profile at once (which could cause trouble). This is the better platform independent locking system we found. If you check ~/.amsn/profiles, you can see what port is used for each profile. == What is the Audio and Video Assistant? == The Audio and Video Assistant is an easy way to configure and fine-tune your webcam as well as your audio input (microphone). The Audio and Video Assistant provides options to maximize the quality of your webcam broadcast. The Audio and Video Assistant can be started from within a chat window by clicking 'Edit' ? 'Edit audio and video settings'. The Configure Webcam dialog will then be shown. You may change your video settings by clicking Change video settings button. You can also start the assistant using the Ctrl-N shortcut from the main window. Refer to the http://amsn-project.net/wiki/Shortcuts page for an up to date list of keyboard shortcuts. == How do I remove aMSN completely? == After uninstalling aMSN, your profiles (per account settings, log files, etc..) are still stored on your system. You may remove them by following these simple procedures : Linux: rm -rf ~/.amsn Windows: Delete C:\Documents and Settings\$USER\amsn where $USER is your username. Mac OS X Remove the aMSN application. Remove this folder : Home / Library / Application Support / aMSN == The mail traydock icon in the system tray continues to show up, how do I get rid of it? == You must read your unread mails to make the traydock icon disappear. == I enabled the logging of conversations on aMSN, but I cannot find the logfiles. Where are they stored? == In order for logging to be enabled, you must first create a profile. This can be done at the aMSN login-screen by enabling the "Remember me" option. You will then find the log here here: Linux: ~/.amsn/your_email_profile/logs Windows: %USERPROFILE%\amsn\your_email_profile\logs Where %USERPROFILE% is usually C:\Documents and Settings\%user% where %user% is the username of your Windows account. Mac OS X: /Home / Library / Application Support / aMSN / your_email_profile / logs == Can I disable custom and/or animated smileys? == Choose the Preferences option from the Account menu, then click on the tab that says Appearance. Here you can set the various options regarding Emotions Icons and Smileys. Why doesn't aMSN support audio / Why did aMSN drop linphone support? The support of Linphone in aMSN has been dropped some time ago because it was not complete and difficult to maintain. Moreover, the only person able to make it work and to resume its development is no more active in the aMSN's development, so the support has just been dropped. Now aMSN supports webcam session (not videconference), this support is complete and stable and easier to maintain. About Audio support, it is delayed for a next release. Farsight project, developped by Burgerman will give audio support to aMSN, we are just waiting for a stable version. == I have another question, can you help me? == Yes, we can. But before asking questions, search this wiki for your question. If you couldn't find it, then take a look at the aMSN forums found at: http://amsn-project.net/forums Make sure you SEARCH before posting Most likely your question has already been answered. You can also view more information at aMSN's sourceforge project page, which is located at: http://sourceforge.net/projects/amsn Before submitting a bug report or asking for support, please document the following information: aMSN version : Tcl and Tk version : Kernel version : Distribution : System architecture (32-bit, PPC, 64-bit, etc.) : Stack trace of the submitted error (if applicable) : Last error messages in debug windows (Ctrl+D and Ctrl+S in contact list) : Possible ways to replicate the bug : Here's an example of a user's documentation : aMSN version : 0.96 Tcl and Tk version : 8.4.16 Kernel version : Linux 2.6.12-8-386 (Found by typing: uname -s -r in an xterm) Distribution : Debian System architecture (32-bit, PPC, 64-bit, etc.) : 32-bit Stack trace of the submitted error (if applicable) : NA (not applicable) Last error messages in debug windows (Ctrl+D and Ctrl+S in contact list) : Possible ways to replicate the bug : Open a chat window and send a custom emoticon which is animated to an msn 7.5 user. Send this information with your bug report so that we may further investigate the issue. If you still have a question that has not been covered in this FAQ, you can visit the aMSN forum at: http://amsn-project.net/forums or contact us on IRC (Internet Relay Chat) at : server: irc.freenode.net channel: #amsn There is a bot on the channel that is able to give you some indications if you use the following commands : amsn install amsn version amsn download amsn tcl/tk version amsn libstd amsn svn ... and some others In case you have some trouble to connect to our IRC channel because of network policies, you can try this http://cgiirc.blitzed.org/ Enjoy using aMSN!amsn-0.98.9/TODO0000644000175000017500000001352311757234003013067 0ustar billiobbilliobAMSN TO-DO List ============ Check our Wiki page TO-DO list: http://amsn.sourceforge.net/wiki DONE We must finish MSNP2P (Sending files through MSNP2P and do transfer dialogs) DONE We must send to waste all MSNP7 code - We should do a GUI cleanup (alarms...) DONE We must do proxy's work... DONE It doesn't update with the new people that enters the chat... it doesn't give you a chance to talk to certain people... DONE In logging/preferences, look at disabled items (add features or remove this items from GUI) BugList / TODO list Hey maybe we should restart using this thing...? (23/11/03) >Ok here is a new version of the TODO list (04/01/03) >>It's big, it's bad! It's the all mighty bug/todo list! >>Here are the stuff we wanna implement and bugs we want to fix... >>Feel free to tell us about any options that aren't here that would interest you... >>Feel free to inform us of any bugs that aren't here (we just ordered 4 boxes of ZAP!) Contact amsn-devel@lists.sourceforge.net ********************************************************* ***Bug Fixes and TODO before next release (priority 1)*** ********************************************************* - Have a correct msnp2pv2 implementation. - Make sure everything is installed correctly and FAQ and HELP are in the amsn directory. - Make good RPMs, for Redhat, Suse, Mandrake, etc. DONE Improve font selection (unify with color selection) - When selecting a new color for the font in a chat, don't change only the color of the text send but the color of the text being written too (for all window). - When queue is cleared, NAK every message in queue - Check for connection state, make sure amsn disconnects if connection goes down. -> add timeouts to changestates and keepalive - When we get a NAK from a message, try to enqueue it again, as probably it will success. DONE Fix focus and children things with list window. (For example add_user from chat window), and dialogs in general. DONE Check functionality of all proxies with new MSNP9 protocol (socks, not keep-alive http proxies) DONE Get rid of all MSNP7 code.. it sure is useless now DONE We sometimes get double pasting, just bind our paste procedure to the <> event, instead of to ************************************************ ***Existing Feature Improvements (priority 2)*** ************************************************ ** General issues ** DONE Option to display or not the chat button bar - Add option to modify keepalive interval (in seconds) DONE Make a Pure PNG Reader (will be used for buddy icons + filetransfer previews, and maybe other stuff) DONE In the Privacy tab, if 2 users have exactly the same nickname in a listbox, we can control only the first user (we can't delete the second user with that nick from the list ...) - Improve truncation to check picture widths, instead of using fixed values DONE Load AMSN faster (load pictures on demand -> GetImage wrapper? Maybe use GetSkinFile?) DONE Get rid of global variables list_al, list_bl, make use of ::abook:: namespace (avatars, custom nicknames, etc) - Clean ugly GUI code (long window names xx.xx.xxx.xx, use -Class instead of repeated options all the time) ** Remote Control issues ** - If text sent over socket contains the color word, it disappears from the text (change the string map call) - make it possible to send more than one space between each words in messages ** Dock Issues ** - New message alert ** File Transfer issues ** - File Transfer AUTH protocol fix - Display link to received file and click to open - Send files through server with MSNP2P if behind NAT ** Alarm system improvements and bugs ** DONE JPG Support (use same as for MSN6 Pictures) ** Logging system improvements and bugs ** - Use XML instead of custom syntax to speed up things - Add date limit or file size limit for log files - Add option for partial logging of only certain users - Save to LOG (if logging disabled, allows to log certain conversations only) - Compress log files with optimal algorithm for text files - Logging syntax options (timestamps, email or nics, etc) DONE Display by day/month/year - Display last X lines of the log in the window when opening a chat window with someone ** WindowsXP issues ** DONE Problem with URLs DONE Problem with sound - Selections don't appear - Ugly program icons (WISH icon, not ours) DONE Fonts dialog all messed up DONE Alarms options (paths) aren't saved correctly if they contain spaces - ImageMagick is never detected since there is a convert.exe program in the System32 DIR and exec looks for that one first - Browser problems in windows when URL contains weird characters ** MSNP2P Stuff ** - Do checksum checking, understand error message, send error messages, etc... ********************************* ***Extra Features (priority 3)*** ********************************* - Have status always on top of contact list DONE Finish the plugins system - Menu accelerators - Be able to change their font in chat (same as you, or different) DONE Autoconnect (when connection detected) - Notebook like chat windows (as an option) - Resume File Transfers - Socks5 Proxy Support with UserName/Password - Better management of special characters and \n in nicks - Make video/audio conferencing work with GbnomeMeeting, check for embedding possibilities **************************************** ***Eye Candy and Gadgets (priority 4)*** **************************************** - Background image - Make games work (should be rather simple, some special parameters passed to the browser I'm guessing) - Make notify window size configurable - Transparent background message windows (is it possible now with 8.4?) - AutoUpgrade AMSN - Direct connection between amsn clients, without sb, real time chat - Balloons in privacy lists (show email) - GUI for translations, automatic updates from amsn GUI (no website) - Have support for multiple sessions (tabs for each session) amsn-0.98.9/maemo.diff0000644000175000017500000000260611275402630014325 0ustar billiobbilliobIndex: debian/control.in =================================================================== --- debian/control.in (revision 10906) +++ debian/control.in (working copy) @@ -1,5 +1,5 @@ Source: amsn -Section: x11 +Section: user/x11 Priority: optional Maintainer: Theodore Karkoulis Build-Depends: debhelper (>> 4.0.0), tcl#TCL_VERSION#-dev, tk#TK_VERSION#-dev, libpng12-dev, libjpeg62-dev Index: configure.ac =================================================================== --- configure.ac (revision 10906) +++ configure.ac (working copy) @@ -357,7 +357,7 @@ dnl do some OS specific stuff here dnl Check for libstdc++ -AC_CHECK_LIB(stdc++,main,CXX_LIB="-lstdc++", AC_MSG_ERROR(stdc++ library not found) ) +#AC_CHECK_LIB(stdc++,main,CXX_LIB="-lstdc++", AC_MSG_ERROR(stdc++ library not found) ) AC_SUBST(CXX_LIB) AC_SUBST(LDLIBS) Index: amsn =================================================================== --- amsn (revision 10906) +++ amsn (working copy) @@ -1,6 +1,5 @@ -#!/bin/sh -# \ -exec wish $0 $@ +#!/usr/bin/wish +# ### ### Index: utils/linux/capture/capture.c =================================================================== --- utils/linux/capture/capture.c (revision 10906) +++ utils/linux/capture/capture.c (working copy) @@ -1032,6 +1032,8 @@ ng_debug = 0; # endif ng_init(); + + yuv2rgb_init(); // End of Initialisation return TCL_OK; amsn-0.98.9/socks.tcl0000644000175000017500000002022411101035551014207 0ustar billiobbilliob############################################################################## # Socks5 Client Library v1.1 # (C)2000 Kerem 'Waster_' HADIMLI # # How to use: # 1) Create your socket connected to the Socks server. # 2) Call socks:init procedure with these 6 parameters: # 1- Socket ID : The socket identifier that's connected to the socks5 server. # 2- Server hostname : The main (not socks) server you want to connect # 3- Server port : The port you want to connect on the main server # 4- Authentication : If you want username/password authentication enabled, set this to 1, otherwise 0. # 5- Username : Username to use on Socks Server if authentication is enabled. NULL if authentication is not enabled. # 6- Password : Password to use on Socks Server if authentication is enabled. NULL if authentication is not enabled. # 3) It'll return you a string starting with: # a- "OK" if successful, now you can send/receive any data from the socket. # b- "ERROR:$explanation" if unsuccessful, $explanation is the explanation like "Host not found". The socket will be automatically closed on an error. # # # Notes: # - This library enters tkwait ::Socks5::loop (see Tk man pages), and returns only # when SOCKS initialization is complete. # - This library uses a global array: socks_idlist. Make sure your program # doesn't use that. # - NEVER use file IDs instead of socket IDs! # - NEVER bind the socket (fileevent) before calling socks:init procedure. ############################################################################## # # Author contact information: # E-mail : waster@iname.com # ICQ# : 27216346 # Jabber : waster@jabber.org (New IM System - http://www.jabber.org) # ############################################################################## # $Id: socks.tcl 10641 2008-10-26 09:42:01Z tomhennigan $ #set socks_idlist(stat,$sck) ... #set socks_idlist(data,$sck) ... namespace eval ::Socks5 { proc Init {sck addr port auth user pass} { variable socks_idlist # if { [catch {fconfigure $sck}] != 0 } {return "ERROR:Connection closed with Socks Server!"} ;# Socket doesn't exist set ver "\x05" ;#Socks version status_log "SOCKS : $sck $addr\n" set addr [split $addr " "] ;# Remove port from address set addr [lindex $addr 0] status_log "SOCKS : $addr\n" if {$auth==0} { set method "\x00" set nmethods "\x01" } elseif {$auth==1} { set method "\x00\x02" set nmethods "\x02" } else { status_log "ERROR: $auth" return "ERROR:" } set nomatchingmethod "\xFF" ;#No matching methods set cmd_connect "\x01" ;#Connect command set rsv "\x00" ;#Reserved set atyp "\x03" ;#Address Type (domain) set dlen "[binary format c [string length $addr]]" ;#Domain length (binary 1 byte) set port [binary format S $port] ;#Network byte-ordered port (2 binary-bytes) set authver "\x01" ;#User/Pass auth. version set ulen "[binary format c [string length $user]]" ;#Username length (binary 1 byte) set plen "[binary format c [string length $pass]]" ;#Password length (binary 1 byte) set a "" set socks_idlist(stat,$sck) 0 set socks_idlist(data,$sck) "" status_log "doing fconfigure now in socks5\n" fconfigure $sck -translation {binary binary} -blocking 0 status_log "writing to socket in socks5 writing : $ver$nmethods$method\n" puts -nonewline $sck "$ver$nmethods$method" if { [catch { flush $sck }] } { catch {close $sck} status_log "ERROR:Couldn't flush Socks Server after writing!" return "ERROR:Couldn't flush Socks Server after writing!" } status_log "doing fileevent now in socks5\n" fileevent $sck readable "::Socks5::Readable $sck" status_log "going into tkwait\n" tkwait variable ::Socks5::socks_idlist(stat,$sck) set a $socks_idlist(data,$sck) if {[eof $sck]} { catch {close $sck} status_log "ERROR:Connection closed with Socks Server!" return "ERROR:Connection closed with Socks Server!" } set serv_ver "" set method $nomatchingmethod binary scan $a "cc" serv_ver smethod if {$serv_ver!=5} { catch {close $sck} status_log "ERROR:Socks Server isn't version 5!" return "ERROR:Socks Server isn't version 5!" } if {$smethod==0} { } elseif {$smethod==2} { ;#User/Pass authorization required if {$auth==0} { catch {close $sck} status_log "ERROR:Method not supported by Socks Server!" return "ERROR:Method not supported by Socks Server!" } puts -nonewline $sck "$authver$ulen$user$plen$pass" flush $sck tkwait variable ::Socks5::socks_idlist(stat,$sck) set a $socks_idlist(data,$sck) if {[eof $sck]} { catch {close $sck} status_log "ERROR:Connection closed with Socks Server!" return "ERROR:Connection closed with Socks Server!" } set auth_ver "" set status "\x00" binary scan $a "cc" auth_ver status if {$auth_ver!=1} { catch {close $sck} status_log "ERROR:Socks Server's authentication isn't supported!" return "ERROR:Socks Server's authentication isn't supported!" } if {$status!=0} { catch {close $sck} status_log "ERROR:Wrong username or password!" return "ERROR:Wrong username or password!" } } else { fileevent $sck readable {} unset socks_idlist(stat,$sck) unset socks_idlist(data,$sck) catch {close $sck} status_log "ERROR:Method not supported by Socks Server!" return "ERROR:Method not supported by Socks Server!" } # # We send request4connect # status_log "second write\n" puts -nonewline $sck "$ver$cmd_connect$rsv$atyp$dlen$addr$port" flush $sck tkwait variable ::Socks5::socks_idlist(stat,$sck) set a $socks_idlist(data,$sck) if {[eof $sck]} { catch {close $sck} status_log "ERROR:Connection closed with Socks Server!" return "ERROR:Connection closed with Socks Server!" } fileevent $sck readable {} unset socks_idlist(stat,$sck) unset socks_idlist(data,$sck) set serv_ver "" set rep "" binary scan $a cc serv_ver rep if {$serv_ver!=5} { catch {close $sck} status_log "ERROR:Socks Server isn't version 5!" return "ERROR:Socks Server isn't version 5!" } if {$rep==0} { fconfigure $sck -translation {auto auto} status_log "SOCKS: OK" return "OK" } elseif {$rep==1} { catch {close $sck} status_log "ERROR:Socks server responded:\nGeneral SOCKS server failure" return "ERROR:Socks server responded:\nGeneral SOCKS server failure" } elseif {$rep==2} { catch {close $sck} status_log "ERROR:Socks server responded:\nConnection not allowed by ruleset" return "ERROR:Socks server responded:\nConnection not allowed by ruleset" } elseif {$rep==3} { catch {close $sck} status_log "ERROR:Socks server responded:\nNetwork unreachable" return "ERROR:Socks server responded:\nNetwork unreachable" } elseif {$rep==4} { catch {close $sck} status_log "ERROR:Socks server responded:\nHost unreachable" return "ERROR:Socks server responded:\nHost unreachable" } elseif {$rep==5} { catch {close $sck} status_log "ERROR:Socks server responded:\nConnection refused" return "ERROR:Socks server responded:\nConnection refused" } elseif {$rep==6} { catch {close $sck} status_log "ERROR:Socks server responded:\nTTL expired" return "ERROR:Socks server responded:\nTTL expired" } elseif {$rep==7} { catch {close $sck} status_log "ERROR:Socks server responded:\nCommand not supported" return "ERROR:Socks server responded:\nCommand not supported" } elseif {$rep==8} { catch {close $sck} status_log "ERROR:Socks server responded:\nAddress type not supported" return "ERROR:Socks server responded:\nAddress type not supported" } else { catch {close $sck} status_log "ERROR:Socks server responded:\nUnknown Error" return "ERROR:Socks server responded:\nUnknown Error" } status_log "finished sock5 init" } # # Change the variable value, so 'tkwait' loop will end in socks:init procedure. # proc Readable {sck} { variable socks_idlist if { [catch {set socks_idlist(data,$sck) [read $sck]} res] } { status_log "Error when reading from sock server : $res" } incr socks_idlist(stat,$sck) } } amsn-0.98.9/ca-certs/0000755000175000017500000000000011757711634014106 5ustar billiobbilliobamsn-0.98.9/ca-certs/VeriSign_International_Server_Class_3_CA.pem0000644000175000017500000000237511346125707024467 0ustar billiobbilliob-----BEGIN CERTIFICATE----- MIIDgzCCAuygAwIBAgIQRvzrurTQLw+SYJgjP5MHjzANBgkqhkiG9w0BAQUFADBf MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsT LkNsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw HhcNOTcwNDE3MDAwMDAwWhcNMTYxMDI0MjM1OTU5WjCBujEfMB0GA1UEChMWVmVy aVNpZ24gVHJ1c3QgTmV0d29yazEXMBUGA1UECxMOVmVyaVNpZ24sIEluYy4xMzAx BgNVBAsTKlZlcmlTaWduIEludGVybmF0aW9uYWwgU2VydmVyIENBIC0gQ2xhc3Mg MzFJMEcGA1UECxNAd3d3LnZlcmlzaWduLmNvbS9DUFMgSW5jb3JwLmJ5IFJlZi4g TElBQklMSVRZIExURC4oYyk5NyBWZXJpU2lnbjCBnzANBgkqhkiG9w0BAQEFAAOB jQAwgYkCgYEA2IKA6NYZAn0fhRg5JaJlK+G/1AXTvOY2O6rwTGxbtueqPHNFVbLx veqXQu2aNAoV1Klc9UAl3dkHwTKydWzEyruj/lYncUOqY/UwPpMo5frxCTvzt01O OfdcSVq4wR3Tsor+cDCVQsv+K1GLWjw6+SJPkLICp1OcTzTnqwSye28CAwEAAaOB 4zCB4DAPBgNVHRMECDAGAQH/AgEAMEQGA1UdIAQ9MDswOQYLYIZIAYb4RQEHAQEw KjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL0NQUzA0BgNV HSUELTArBggrBgEFBQcDAQYIKwYBBQUHAwIGCWCGSAGG+EIEAQYKYIZIAYb4RQEI ATALBgNVHQ8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgEGMDEGA1UdHwQqMCgwJqAk oCKGIGh0dHA6Ly9jcmwudmVyaXNpZ24uY29tL3BjYTMuY3JsMA0GCSqGSIb3DQEB BQUAA4GBAECOSZeWinPdjk3vPmG3yqBirfQOCrt1PeJu2CzHv/S5jDabyqLQnHJG OfamggNlEcS8vy2m9dk7CrWY+rN4uR7yK0xi1f2yeh3fM/1z+aXYLYwq6tH8sCi2 6UlIE0uDihtIeyT3ON5vQVS4q1drBt/HotSp9vE2YoCI8ot11oBx -----END CERTIFICATE----- amsn-0.98.9/ca-certs/README0000644000175000017500000000030511346410561014751 0ustar billiobbilliobafter adding a certfile here, you need to run the command: $ c_rehash . This will create the correct symlink. If you want to see more info from a cert, just run: openssl x509 -in {certfile} -text amsn-0.98.9/ca-certs/75ced341.00000777000175000017500000000000011757711634023713 2Microsoft_Internet_Authority.pemustar billiobbilliobamsn-0.98.9/ca-certs/6e7f22c1.00000777000175000017500000000000011757711634025321 2VeriSign_Class3_Extended_Validation_CA.pemustar billiobbilliobamsn-0.98.9/ca-certs/37621ded.00000777000175000017500000000000011757711634025703 2VeriSign_International_Server_Class_3_CA.pemustar billiobbilliobamsn-0.98.9/ca-certs/VeriSign_Class3_Extended_Validation_CA.pem0000644000175000017500000000413011346125707024074 0ustar billiobbilliob-----BEGIN CERTIFICATE----- MIIF5DCCBMygAwIBAgIQW3dZxheE4V7HJ8AylSkoazANBgkqhkiG9w0BAQUFADCB yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMTYxMTA3MjM1OTU5WjCBujEL MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2UgYXQg aHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL3JwYSAoYykwNjE0MDIGA1UEAxMrVmVy aVNpZ24gQ2xhc3MgMyBFeHRlbmRlZCBWYWxpZGF0aW9uIFNTTCBDQTCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBAJjboFXrnP0XeeOabhQdsVuYI4cWbod2 nLU4O7WgerQHYwkZ5iqISKnnnbYwWgiXDOyq5BZpcmIjmvt6VCiYxQwtt9citsj5 OBfH3doxRpqUFI6e7nigtyLUSVSXTeV0W5K87Gws3+fBthsaVWtmCAN/Ra+aM/EQ wGyZSpIkMQht3QI+YXZ4eLbtfjeubPOJ4bfh3BXMt1afgKCxBX9ONxX/ty8ejwY4 P1C3aSijtWZfNhpSSENmUt+ikk/TGGC+4+peGXEFv54cbGhyJW+ze3PJbb0S/5tB Ml706H7FC6NMZNFOvCYIZfsZl1h44TO/7Wg+sSdFb8Di7Jdp91zT91ECAwEAAaOC AdIwggHOMB0GA1UdDgQWBBT8ilC6nrklWntVhU+VAGOP6VhrQzASBgNVHRMBAf8E CDAGAQH/AgEAMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRw czovL3d3dy52ZXJpc2lnbi5jb20vY3BzMD0GA1UdHwQ2MDQwMqAwoC6GLGh0dHA6 Ly9FVlNlY3VyZS1jcmwudmVyaXNpZ24uY29tL3BjYTMtZzUuY3JsMA4GA1UdDwEB /wQEAwIBBjARBglghkgBhvhCAQEEBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZ MFcwVRYJaW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7 GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwKQYDVR0R BCIwIKQeMBwxGjAYBgNVBAMTEUNsYXNzM0NBMjA0OC0xLTQ3MD0GCCsGAQUFBwEB BDEwLzAtBggrBgEFBQcwAYYhaHR0cDovL0VWU2VjdXJlLW9jc3AudmVyaXNpZ24u Y29tMB8GA1UdIwQYMBaAFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqGSIb3DQEB BQUAA4IBAQCWovp/5j3t1CvOtxU/wHIDX4u6FpAl98KD2Md1NGNoElMMU4l7yVYJ p8M2RE4O0GJis4b66KGbNGeNUyIXPv2s7mcuQ+JdfzOE8qJwwG6Cl8A0/SXGI3/t 5rDFV0OEst4t8dD2SB8UcVeyrDHhlyQjyRNddOVG7wl8nuGZMQoIeRuPcZ8XZsg4 z+6Ml7YGuXNG5NOUweVgtSV1LdlpMezNlsOjdv3odESsErlNv1HoudRETifLriDR fip8tmNHnna6l9AW5wtsbfdDbzMLKTB3+p359U64drPNGLT5IO892+bKrZvQTtKH qQ2mRHNQ3XBb7a1+Srwi1agm5MKFIA3Z -----END CERTIFICATE----- amsn-0.98.9/ca-certs/Microsoft_Secure_Server_Authority.pem0000644000175000017500000000423211346121634023450 0ustar billiobbilliob-----BEGIN CERTIFICATE----- MIIGEzCCA/ugAwIBAgIKYRZtLwAEAAAAIDANBgkqhkiG9w0BAQUFADAnMSUwIwYD VQQDExxNaWNyb3NvZnQgSW50ZXJuZXQgQXV0aG9yaXR5MB4XDTA4MDQwOTIxMzc1 NFoXDTExMDIxOTE4MjQ1M1owgYsxEzARBgoJkiaJk/IsZAEZFgNjb20xGTAXBgoJ kiaJk/IsZAEZFgltaWNyb3NvZnQxFDASBgoJkiaJk/IsZAEZFgRjb3JwMRcwFQYK CZImiZPyLGQBGRYHcmVkbW9uZDEqMCgGA1UEAxMhTWljcm9zb2Z0IFNlY3VyZSBT ZXJ2ZXIgQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA kYTz6fKXvrdfIr5o3Ue4CRIzhTE+8JE4hrLTQki3emjYn/CfHRPb7hmMiOZmWBdE DUEymyXOyZ7Sy2tC6WaBC4onVYotPoSsaOZJv6EJeHPk64RiWTfX+XqufRndYOEC DUmotYQNPV/8InioIBf9+gOSsAMdmyGZF6C1PkJqvPZTRxNv6hxuMMb6uOQIPoFX /ceQvAOZcJx2qGsAVKsJHylYkC0GgVyFVhOI0vcZZBcP5T+NtOmyjVBWdxS413HL D+8w+3wG0bOP8EyOeRnuf0KLXGBangte0ZFIRd28GXpo5UrcA/r5000e2RTHmhC4 8YPMIoi+q9XZoF5R0Z069QIDAQABo4IB2jCCAdYwEgYDVR0TAQH/BAgwBgEB/wIB ADAdBgNVHQ4EFgQUFFXEOeA9LtFVLkiWsNh+FCIGk7wwCwYDVR0PBAQDAgGGMBIG CSsGAQQBgjcVAQQFAgMFAAUwIwYJKwYBBAGCNxUCBBYEFM7FoL4P/nlmdZEP8PeS WzWYqBWzMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMB8GA1UdIwQYMBaAFMbb u8DYIBmS8WD8iPFYf7wbTo8aMIGjBgNVHR8EgZswgZgwgZWggZKggY+GNmh0dHA6 Ly9tc2NybC5taWNyb3NvZnQuY29tL3BraS9tc2NvcnAvY3JsL21zd3d3KDQpLmNy bIY0aHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9tc2NvcnAvY3JsL21zd3d3 KDQpLmNybIYfaHR0cDovL2NvcnBwa2kvY3JsL21zd3d3KDQpLmNybDB5BggrBgEF BQcBAQRtMGswPAYIKwYBBQUHMAKGMGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9w a2kvbXNjb3JwL21zd3d3KDQpLmNydDArBggrBgEFBQcwAoYfaHR0cDovL2NvcnBw a2kvYWlhL21zd3d3KDQpLmNydDANBgkqhkiG9w0BAQUFAAOCAgEAempuzk/VLM4N H9TAbFtCjKc95iGmyx2bHbEk9m2cbGxXjBre+N4cJoIYYmhLrZ6L712ov1NjM73b m8fb2Fy8Yw8Cmwc8VtarPZT2yzGr8MhNUDVuZswaKfjCY3H7RYv/XKc7AOMd25WP /M0WTT4Bna6hl9dUaDGwv5SZFFIJ17FLo4FR2H7IkOOI/WcUPAHeDXUewp4qRPE/ 560xZrLSeNH2lKnOAwwXxwnXSo5WOF5AQXh1nRdbBV9Nu7yI6jH1QV6fKf6oFU2Y IOjpnJ0FihVB6XoZ0wNOUMzPEEQcTfIoVoc+t0iK02wcmTLgBgbYU703dHvvPTcn IfdI2mscx8l9MjUOdklIIve0FhCxRPqHpEeKjM95gllbXmWgQxAXiog+A62fEo5d M7nfeEyiweSlhj1cv+2dyhzyS5saKYkk3ocCnOMCyD0M+4gJx4n4b/zT3rcujyN+ 7m20PbBTjcdTT1+AxOs75rON2hhKUqqrk2MDCpnEJsNK4TuRyDUtm9r+AxaZ4XRK MT8InY1Xl9hzrIK6MVERYH46kxg6odwpzJ8Urn4dREBiMy6Gzq8mtyXvpYEcmeGL zz1aT7qNNbQ0qqbPb6RpOMHlUWOIhVWJC71T5WK1pynAc3P9zOm8BkUYvIyJvCbR bufCGVng4FAtVZ1advxSVRoa4GyuFZ8= -----END CERTIFICATE----- amsn-0.98.9/ca-certs/GTE_CyberTrust_Global_Root.pem0000644000175000017500000000155411346410561021673 0ustar billiobbilliob-----BEGIN CERTIFICATE----- MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgw FgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRy dXN0IFNvbHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3Qg R2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1 MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYD VQQLEx5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMT GkdURSBDeWJlclRydXN0IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUA A4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4usJTQGz0O9pTAipTHBsiQl8i4 ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcqlHHK6XALn ZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8F LztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh3 46B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq 81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0PlZPvy5TYnh+d XIVtx6quTx8itc2VrbqnzPmrC3p/ -----END CERTIFICATE----- amsn-0.98.9/ca-certs/Microsoft_Internet_Authority.pem0000644000175000017500000000342111346121634022463 0ustar billiobbilliob-----BEGIN CERTIFICATE----- MIIFCjCCBHOgAwIBAgIEBycWdTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJV UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds b2JhbCBSb290MB4XDTA4MDIxOTE4MjcwMloXDTExMDIxOTE4MjQ1M1owJzElMCMG A1UEAxMcTWljcm9zb2Z0IEludGVybmV0IEF1dGhvcml0eTCCAiIwDQYJKoZIhvcN AQEBBQADggIPADCCAgoCggIBAKiloatvDehDG/rQriel2AC9qmSJdvjKb2fmJf30 K7SaC3zQu8kGQxENUEFsHsH0jmBejJ9vvn9tHZ8hGL+kORvWUVBskdMzP65rC0V0 VeVgUYzPZ7MvrLfhh9+v3yJ7qRuf1aNgmzJg5t1AA91X+aRrFT4lRzl9BFWhQ1VS XaD7l6qoiyhD8FbrdLRAe61swsRmzWeXoy6NJpOBsGXaCSG1Jooylro+zkWxt97c NkNf/wYqoYcIXo02YpFbwreveejW9a0Lh/1z9+e9aiMtC5QnPT57GTqNINt5R0rp Iz4g3GJhmjXVoVF/tev5DMJuhRgPoz0W0aA3UnSmTWh2RFvgqawLqSRrKUhVjySi /m5s62uG5xxIftO7/6ljzS061CFoV/RBl/I3WghYp04sr4cSXWa/rL449YhBT8BJ jltefWCYAOcT1nA4oFXwXbl1qCUIkZ0bqwju2FGW5vl2qh6vmzcQjc3XxD0m2UqC yJNFa9SUgVXtUCqeOI+KqgLW01tpqZteG10byWKmppTVAvdPwHoGE0bl6wBwXldE f7Pn4lqu6Yp4bedP3Qv1sfp2H7D98cxSwYRt3UcXN2kjTPv+pby2fEHm9GWf3iE/ 7OtzUI7LYhP7+rGyuCYTtZKH1jDWHrTZBpnAPmrAQQHCI8/4TjF9ZQ1mqRi6x9I9 9XGfAgMBAAGjggFvMIIBazASBgNVHRMBAf8ECDAGAQH/AgEBMFMGA1UdIARMMEow SAYJKwYBBAGxPgEAMDswOQYIKwYBBQUHAgEWLWh0dHA6Ly9jeWJlcnRydXN0Lm9t bmlyb290LmNvbS9yZXBvc2l0b3J5LmNmbTAOBgNVHQ8BAf8EBAMCAYYwgYkGA1Ud IwSBgTB/oXmkdzB1MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0 aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAh BgNVBAMTGkdURSBDeWJlclRydXN0IEdsb2JhbCBSb290ggIBpTBFBgNVHR8EPjA8 MDqgOKA2hjRodHRwOi8vd3d3LnB1YmxpYy10cnVzdC5jb20vY2dpLWJpbi9DUkwv MjAxOC9jZHAuY3JsMB0GA1UdDgQWBBTG27vA2CAZkvFg/IjxWH+8G06PGjANBgkq hkiG9w0BAQUFAAOBgQBnSDXCyiqGmHTAEJOtZYVm/IbzGtzCY423NF6/yuccYZkm spJnDoh8nq3nx3P2KBEyPAqoQ1MEFC+ByQjV4AAQ9dMQALUGNRfHhFUhBeeIybYd bzvKOxSlIYSwO2T56+oXyDlkbQWKmHec5qzCE0lwGHslsRU/CHwhuFu2nH+CxQ== -----END CERTIFICATE----- amsn-0.98.9/ca-certs/874806e2.00000777000175000017500000000000011757711634024547 2Microsoft_Secure_Server_Authority.pemustar billiobbilliobamsn-0.98.9/ca-certs/c692a373.00000777000175000017500000000000011757711634023040 2GTE_CyberTrust_Global_Root.pemustar billiobbilliobamsn-0.98.9/utils/0000755000175000017500000000000011757711634013545 5ustar billiobbilliobamsn-0.98.9/utils/snit/0000755000175000017500000000000011757711634014522 5ustar billiobbilliobamsn-0.98.9/utils/snit/snit.tcl0000644000175000017500000000207211020317540016161 0ustar billiobbilliob#----------------------------------------------------------------------- # TITLE: # snit.tcl # # AUTHOR: # Will Duquette # # DESCRIPTION: # Snit's Not Incr Tcl, a simple object system in Pure Tcl. # # Snit 1.x Loader # # Copyright (C) 2003-2006 by William H. Duquette # This code is licensed as described in license.txt. # #----------------------------------------------------------------------- package require Tcl 8.3 # Define the snit namespace and save the library directory namespace eval ::snit:: { set library [file dirname [info script]] } # Select the implementation based on the version of the Tcl core # executing this code. For 8.3 we use a backport emulating various # 8.4 features if {[package vsatisfies [package provide Tcl] 8.4]} { source [file join $::snit::library main1.tcl] } else { source [file join $::snit::library main1_83.tcl] source [file join $::snit::library snit_tcl83_utils.tcl] } # Load the library of Snit validation types. source [file join $::snit::library validate.tcl] package provide snit 1.3.1 amsn-0.98.9/utils/snit/snit_tcl83_utils.tcl0000644000175000017500000001432411020317540020421 0ustar billiobbilliob#-------------------------------------------------------------------------- # TITLE: # snit_tcl83_utils.tcl # # AUTHOR: # Kenneth Green, 28 Aug 2004 # # DESCRIPTION: # Utilities to support the back-port of snit from Tcl 8.4 to 8.3 # #-------------------------------------------------------------------------- # Copyright # # Copyright (c) 2005 Kenneth Green # Modified by Andreas Kupries. # All rights reserved. This code is licensed as described in license.txt. #-------------------------------------------------------------------------- # This code is freely distributable, but is provided as-is with # no warranty expressed or implied. #-------------------------------------------------------------------------- # Acknowledgements # The changes described in this file are made to the awesome 'snit' # library as provided by William H. Duquette under the terms # defined in the associated 'license.txt'. #----------------------------------------------------------------------- #----------------------------------------------------------------------- # Namespace namespace eval ::snit83 {} #----------------------------------------------------------------------- # Some Snit83 variables namespace eval ::snit83 { variable cmdTraceTable array set cmdTraceTable {} namespace eval private {} } #----------------------------------------------------------------------- # Initialisation # # Override Tcl functions so we can mimic some behaviours. This is # conditional on not having been done already. Otherwise loading snit # twice will fail the second time. # if [info exists tk_version] { if { ![llength [info procs destroy]] || ![regexp snit83 [info body destroy]] } { rename destroy __destroy__ } } if { ![llength [info procs namespace]] || ![regexp snit83 [info body namespace]] } { rename namespace __namespace__ rename rename __rename__ ;# must be last one renamed! } #----------------------------------------------------------------------- # Global namespace functions # destroy - # # Perform delete tracing and then invoke the actual Tk destroy command if [info exists tk_version] { proc destroy { w } { variable ::snit83::cmdTraceTable set index "delete,$w" if [info exists cmdTraceTable($index)] { set cmd $cmdTraceTable($index) ::unset cmdTraceTable($index) ;# prevent recursive tracing if [catch {eval $cmd $oldName \"$newName\" delete} err] { ; # " error $err } } return [__destroy__ $w] } } # namespace - # # Add limited support for 'namespace exists'. Must be a fully # qualified namespace name (pattern match support not provided). proc namespace { cmd args } { if {[string equal $cmd "exists"]} { set ptn [lindex $args 0] return [::snit83::private::NamespaceIsDescendantOf :: $ptn] } elseif {[string equal $cmd "delete"]} { if [namespace exists [lindex $args 0]] { return [uplevel 1 [subst {__namespace__ $cmd $args}]] } } else { return [uplevel 1 [subst {__namespace__ $cmd $args}]] } } # rename - # # Perform rename tracing and then invoke the actual Tcl rename command proc rename { oldName newName } { variable ::snit83::cmdTraceTable # Get caller's namespace since rename must be performed # in the context of the caller's namespace set callerNs "::" set callerLevel [expr {[info level] - 1}] if { $callerLevel > 0 } { set callerInfo [info level $callerLevel] set procName [lindex $callerInfo 0] set callerNs [namespace qualifiers $procName] } #puts "rename: callerNs: $callerNs" #puts "rename: '$oldName' -> '$newName'" #puts "rename: rcds - [join [array names cmdTraceTable] "\nrename: rcds - "]" set result [namespace eval $callerNs [concat __rename__ [list $oldName $newName]]] set index1 "rename,$oldName" set index2 "rename,::$oldName" foreach index [list $index1 $index2] { if [info exists cmdTraceTable($index)] { set cmd $cmdTraceTable($index) #puts "rename: '$cmd' { $oldName -> $newName }" ::unset cmdTraceTable($index) ;# prevent recursive tracing if {![string equal $newName ""]} { # Create a new trace record under the new name set cmdTraceTable(rename,$newName) $cmd } if [catch {eval $cmd $oldName \"$newName\" rename} err] { error $err } break } } return $result } #----------------------------------------------------------------------- # Private functions proc ::snit83::private::NamespaceIsDescendantOf { parent child } { set result 0 foreach ns [__namespace__ children $parent] { if [string match $ns $child] { set result 1 break; } else { if [set result [NamespaceIsDescendantOf $ns $child]] { break } } } return $result } #----------------------------------------------------------------------- # Utility functions proc ::snit83::traceAddCommand {name ops command} { variable cmdTraceTable #puts "::snit83::traceAddCommand n/$name/ o/$ops/ c/$command/" #puts "XX [join [array names cmdTraceTable] "\nXX "]" foreach op $ops { set index "$op,$name" #puts "::snit83::traceAddCommand: index = $index cmd = $command" set cmdTraceTable($index) $command } } proc ::snit83::traceRemoveCommand {name ops command} { variable cmdTraceTable #puts "::snit83::traceRemoveCommand n/$name/ o/$ops/ c/$command/" #puts "YY [join [array names cmdTraceTable] "\nYY "]" foreach op $ops { set index "$op,$name" #puts "::snit83::traceRemoveCommand: index = $index cmd = $command" catch { ::unset cmdTraceTable($index) } } } # Add support for 'unset -nocomplain' proc ::snit83::unset { args } { #puts "::snit83::unset - args: '$args'" set noComplain 0 if {[string equal [lindex $args 0] "-nocomplain"]} { set noComplain 1 set args [lrange $args 1 end] } if {[string equal [lindex $args 0] "--"]} { set args [lrange $args 1 end] } if [catch { uplevel 1 [linsert $args 0 ::unset] } err] { if { !$noComplain } { error $err } } } amsn-0.98.9/utils/snit/validate.tcl0000644000175000017500000004352411020317540017004 0ustar billiobbilliob#----------------------------------------------------------------------- # TITLE: # validate.tcl # # AUTHOR: # Will Duquette # # DESCRIPTION: # Snit validation types. # #----------------------------------------------------------------------- namespace eval ::snit:: { namespace export \ boolean \ double \ enum \ fpixels \ integer \ listtype \ pixels \ stringtype \ window } #----------------------------------------------------------------------- # snit::boolean snit::type ::snit::boolean { #------------------------------------------------------------------- # Type Methods typemethod validate {value} { if {![string is boolean -strict $value]} { return -code error \ "invalid boolean \"$value\", should be one of: 1, 0, true, false, yes, no, on, off" } return } #------------------------------------------------------------------- # Constructor # None needed; no options #------------------------------------------------------------------- # Public Methods method validate {value} { $type validate $value } } #----------------------------------------------------------------------- # snit::double snit::type ::snit::double { #------------------------------------------------------------------- # Options # -min value # # Minimum value option -min -default "" -readonly 1 # -max value # # Maximum value option -max -default "" -readonly 1 #------------------------------------------------------------------- # Type Methods typemethod validate {value} { if {![string is double -strict $value]} { return -code error \ "invalid value \"$value\", expected double" } return } #------------------------------------------------------------------- # Constructor constructor {args} { # FIRST, get the options $self configurelist $args if {"" != $options(-min) && ![string is double -strict $options(-min)]} { return -code error \ "invalid -min: \"$options(-min)\"" } if {"" != $options(-max) && ![string is double -strict $options(-max)]} { return -code error \ "invalid -max: \"$options(-max)\"" } if {"" != $options(-min) && "" != $options(-max) && $options(-max) < $options(-min)} { return -code error "-max < -min" } } #------------------------------------------------------------------- # Public Methods method validate {value} { $type validate $value if {("" != $options(-min) && $value < $options(-min)) || ("" != $options(-max) && $value > $options(-max))} { set msg "invalid value \"$value\", expected double" if {"" != $options(-min) && "" != $options(-max)} { append msg " in range $options(-min), $options(-max)" } elseif {"" != $options(-min)} { append msg " no less than $options(-min)" } return -code error $msg } return } } #----------------------------------------------------------------------- # snit::enum snit::type ::snit::enum { #------------------------------------------------------------------- # Options # -values list # # Valid values for this type option -values -default {} -readonly 1 #------------------------------------------------------------------- # Type Methods typemethod validate {value} { # No -values specified; it's always valid return } #------------------------------------------------------------------- # Constructor constructor {args} { $self configurelist $args if {[llength $options(-values)] == 0} { return -code error \ "invalid -values: \"\"" } } #------------------------------------------------------------------- # Public Methods method validate {value} { if {[lsearch -exact $options(-values) $value] == -1} { return -code error \ "invalid value \"$value\", should be one of: [join $options(-values) {, }]" } } } #----------------------------------------------------------------------- # snit::fpixels snit::type ::snit::fpixels { #------------------------------------------------------------------- # Options # -min value # # Minimum value option -min -default "" -readonly 1 # -max value # # Maximum value option -max -default "" -readonly 1 #------------------------------------------------------------------- # Instance variables variable min "" ;# -min, no suffix variable max "" ;# -max, no suffix #------------------------------------------------------------------- # Type Methods typemethod validate {value} { if {[catch {winfo fpixels . $value} dummy]} { return -code error \ "invalid value \"$value\", expected fpixels" } return } #------------------------------------------------------------------- # Constructor constructor {args} { # FIRST, get the options $self configurelist $args if {"" != $options(-min) && [catch {winfo fpixels . $options(-min)} min]} { return -code error \ "invalid -min: \"$options(-min)\"" } if {"" != $options(-max) && [catch {winfo fpixels . $options(-max)} max]} { return -code error \ "invalid -max: \"$options(-max)\"" } if {"" != $min && "" != $max && $max < $min} { return -code error "-max < -min" } } #------------------------------------------------------------------- # Public Methods method validate {value} { $type validate $value set val [winfo fpixels . $value] if {("" != $min && $val < $min) || ("" != $max && $val > $max)} { set msg "invalid value \"$value\", expected fpixels" if {"" != $min && "" != $max} { append msg " in range $options(-min), $options(-max)" } elseif {"" != $min} { append msg " no less than $options(-min)" } return -code error $msg } return } } #----------------------------------------------------------------------- # snit::integer snit::type ::snit::integer { #------------------------------------------------------------------- # Options # -min value # # Minimum value option -min -default "" -readonly 1 # -max value # # Maximum value option -max -default "" -readonly 1 #------------------------------------------------------------------- # Type Methods typemethod validate {value} { if {![string is integer -strict $value]} { return -code error \ "invalid value \"$value\", expected integer" } return } #------------------------------------------------------------------- # Constructor constructor {args} { # FIRST, get the options $self configurelist $args if {"" != $options(-min) && ![string is integer -strict $options(-min)]} { return -code error \ "invalid -min: \"$options(-min)\"" } if {"" != $options(-max) && ![string is integer -strict $options(-max)]} { return -code error \ "invalid -max: \"$options(-max)\"" } if {"" != $options(-min) && "" != $options(-max) && $options(-max) < $options(-min)} { return -code error "-max < -min" } } #------------------------------------------------------------------- # Public Methods method validate {value} { $type validate $value if {("" != $options(-min) && $value < $options(-min)) || ("" != $options(-max) && $value > $options(-max))} { set msg "invalid value \"$value\", expected integer" if {"" != $options(-min) && "" != $options(-max)} { append msg " in range $options(-min), $options(-max)" } elseif {"" != $options(-min)} { append msg " no less than $options(-min)" } return -code error $msg } return } } #----------------------------------------------------------------------- # snit::list snit::type ::snit::listtype { #------------------------------------------------------------------- # Options # -type type # # Specifies a value type option -type -readonly 1 # -minlen len # # Minimum list length option -minlen -readonly 1 -default 0 # -maxlen len # # Maximum list length option -maxlen -readonly 1 #------------------------------------------------------------------- # Type Methods typemethod validate {value} { if {[catch {llength $value} result]} { return -code error \ "invalid value \"$value\", expected list" } return } #------------------------------------------------------------------- # Constructor constructor {args} { # FIRST, get the options $self configurelist $args if {"" != $options(-minlen) && (![string is integer -strict $options(-minlen)] || $options(-minlen) < 0)} { return -code error \ "invalid -minlen: \"$options(-minlen)\"" } if {"" == $options(-minlen)} { set options(-minlen) 0 } if {"" != $options(-maxlen) && ![string is integer -strict $options(-maxlen)]} { return -code error \ "invalid -maxlen: \"$options(-maxlen)\"" } if {"" != $options(-maxlen) && $options(-maxlen) < $options(-minlen)} { return -code error "-maxlen < -minlen" } } #------------------------------------------------------------------- # Methods method validate {value} { $type validate $value set len [llength $value] if {$len < $options(-minlen)} { return -code error \ "value has too few elements; at least $options(-minlen) expected" } elseif {"" != $options(-maxlen)} { if {$len > $options(-maxlen)} { return -code error \ "value has too many elements; no more than $options(-maxlen) expected" } } # NEXT, check each value if {"" != $options(-type)} { foreach item $value { set cmd $options(-type) lappend cmd validate $item uplevel \#0 $cmd } } } } #----------------------------------------------------------------------- # snit::pixels snit::type ::snit::pixels { #------------------------------------------------------------------- # Options # -min value # # Minimum value option -min -default "" -readonly 1 # -max value # # Maximum value option -max -default "" -readonly 1 #------------------------------------------------------------------- # Instance variables variable min "" ;# -min, no suffix variable max "" ;# -max, no suffix #------------------------------------------------------------------- # Type Methods typemethod validate {value} { if {[catch {winfo pixels . $value} dummy]} { return -code error \ "invalid value \"$value\", expected pixels" } return } #------------------------------------------------------------------- # Constructor constructor {args} { # FIRST, get the options $self configurelist $args if {"" != $options(-min) && [catch {winfo pixels . $options(-min)} min]} { return -code error \ "invalid -min: \"$options(-min)\"" } if {"" != $options(-max) && [catch {winfo pixels . $options(-max)} max]} { return -code error \ "invalid -max: \"$options(-max)\"" } if {"" != $min && "" != $max && $max < $min} { return -code error "-max < -min" } } #------------------------------------------------------------------- # Public Methods method validate {value} { $type validate $value set val [winfo pixels . $value] if {("" != $min && $val < $min) || ("" != $max && $val > $max)} { set msg "invalid value \"$value\", expected pixels" if {"" != $min && "" != $max} { append msg " in range $options(-min), $options(-max)" } elseif {"" != $min} { append msg " no less than $options(-min)" } return -code error $msg } return } } #----------------------------------------------------------------------- # snit::stringtype snit::type ::snit::stringtype { #------------------------------------------------------------------- # Options # -minlen len # # Minimum list length option -minlen -readonly 1 -default 0 # -maxlen len # # Maximum list length option -maxlen -readonly 1 # -nocase 0|1 # # globs and regexps are case-insensitive if -nocase 1. option -nocase -readonly 1 -default 0 # -glob pattern # # Glob-match pattern, or "" option -glob -readonly 1 # -regexp regexp # # Regular expression to match option -regexp -readonly 1 #------------------------------------------------------------------- # Type Methods typemethod validate {value} { # By default, any string (hence, any Tcl value) is valid. return } #------------------------------------------------------------------- # Constructor constructor {args} { # FIRST, get the options $self configurelist $args # NEXT, validate -minlen and -maxlen if {"" != $options(-minlen) && (![string is integer -strict $options(-minlen)] || $options(-minlen) < 0)} { return -code error \ "invalid -minlen: \"$options(-minlen)\"" } if {"" == $options(-minlen)} { set options(-minlen) 0 } if {"" != $options(-maxlen) && ![string is integer -strict $options(-maxlen)]} { return -code error \ "invalid -maxlen: \"$options(-maxlen)\"" } if {"" != $options(-maxlen) && $options(-maxlen) < $options(-minlen)} { return -code error "-maxlen < -minlen" } # NEXT, validate -nocase if {[catch {snit::boolean validate $options(-nocase)} result]} { return -code error "invalid -nocase: $result" } # Validate the glob if {"" != $options(-glob) && [catch {string match $options(-glob) ""} dummy]} { return -code error \ "invalid -glob: \"$options(-glob)\"" } # Validate the regexp if {"" != $options(-regexp) && [catch {regexp $options(-regexp) ""} dummy]} { return -code error \ "invalid -regexp: \"$options(-regexp)\"" } } #------------------------------------------------------------------- # Methods method validate {value} { # Usually we'd call [$type validate $value] here, but # as it's a no-op, don't bother. # FIRST, validate the length. set len [string length $value] if {$len < $options(-minlen)} { return -code error \ "too short: at least $options(-minlen) characters expected" } elseif {"" != $options(-maxlen)} { if {$len > $options(-maxlen)} { return -code error \ "too long: no more than $options(-maxlen) characters expected" } } # NEXT, check the glob match, with or without case. if {"" != $options(-glob)} { if {$options(-nocase)} { set result [string match -nocase $options(-glob) $value] } else { set result [string match $options(-glob) $value] } if {!$result} { return -code error \ "invalid value \"$value\"" } } # NEXT, check regexp match with or without case if {"" != $options(-regexp)} { if {$options(-nocase)} { set result [regexp -nocase -- $options(-regexp) $value] } else { set result [regexp -- $options(-regexp) $value] } if {!$result} { return -code error \ "invalid value \"$value\"" } } } } #----------------------------------------------------------------------- # snit::window snit::type ::snit::window { #------------------------------------------------------------------- # Type Methods typemethod validate {value} { if {![winfo exists $value]} { return -code error \ "invalid value \"$value\", value is not a window" } return } #------------------------------------------------------------------- # Constructor # None needed; no options #------------------------------------------------------------------- # Public Methods method validate {value} { $type validate $value } } amsn-0.98.9/utils/snit/pkgIndex.tcl0000644000175000017500000000032011020317540016747 0ustar billiobbilliobif {[package vsatisfies [package provide Tcl] 8.5]} { package ifneeded snit 2.2.1 \ [list source [file join $dir snit2.tcl]] } package ifneeded snit 1.3.1 [list source [file join $dir snit.tcl]] amsn-0.98.9/utils/snit/snit83.tcl0000644000175000017500000035150410405240242016343 0ustar billiobbilliob#----------------------------------------------------------------------- # TITLE: # snit.tcl # # AUTHOR: # Will Duquette # # DESCRIPTION: # Snit's Not Incr Tcl, a simple object system in Pure Tcl. # # Copyright (C) 2003-2005 by William H. Duquette # This code is licensed as described in license.txt. # #----------------------------------------------------------------------- # Back-port to Tcl8.3 by Kenneth Green (kmg) # Modified by Andreas Kupries. # 06 Jun 2005 # # Local changes marked with "#kmg-tcl83" # # Global changes: # " eq " => "string equal" # " ne " -> "!string equal" # " trace add variable " -> "trace variable " # " write " -> "w" in all calls to 'trace variable' # " unset -nocomplain " -> "::snit83::unset -nocomplain" # " -glob " -> "" in all calls to 'array names' #----------------------------------------------------------------------- package provide snit 1.1 #----------------------------------------------------------------------- # Namespace namespace eval ::snit:: { namespace export \ compile type widget widgetadaptor typemethod method macro } #----------------------------------------------------------------------- # Some Snit variables namespace eval ::snit:: { variable reservedArgs {type selfns win self} # Widget classes which can be hulls (must have -class) variable hulltypes { toplevel tk::toplevel frame tk::frame ttk::frame labelframe tk::labelframe ttk::labelframe } } source [file dirname [info script]]/snit_tcl83_utils.tcl #----------------------------------------------------------------------- # Snit Type Implementation template namespace eval ::snit:: { # Template type definition: All internal and user-visible Snit # implementation code. # # The following placeholders will automatically be replaced with # the client's code, in two passes: # # First pass: # %COMPILEDDEFS% The compiled type definition. # # Second pass: # %TYPE% The fully qualified type name. # %IVARDECS% Instance variable declarations # %TVARDECS% Type variable declarations # %TCONSTBODY% Type constructor body # %INSTANCEVARS% The compiled instance variable initialization code. # %TYPEVARS% The compiled type variable initialization code. # This is the overall type template. variable typeTemplate # This is the normal type proc variable nominalTypeProc # This is the "-hastypemethods no" type proc variable simpleTypeProc } set ::snit::typeTemplate { #------------------------------------------------------------------- # The type's namespace definition and the user's type variables namespace eval %TYPE% {%TYPEVARS% } #---------------------------------------------------------------- # Commands for use in methods, typemethods, etc. # # These are implemented as aliases into the Snit runtime library. interp alias {} %TYPE%::installhull {} ::snit::RT.installhull %TYPE% interp alias {} %TYPE%::install {} ::snit::RT.install %TYPE% interp alias {} %TYPE%::typevariable {} ::variable interp alias {} %TYPE%::variable {} ::snit::RT.variable interp alias {} %TYPE%::mytypevar {} ::snit::RT.mytypevar %TYPE% interp alias {} %TYPE%::typevarname {} ::snit::RT.mytypevar %TYPE% interp alias {} %TYPE%::myvar {} ::snit::RT.myvar interp alias {} %TYPE%::varname {} ::snit::RT.myvar interp alias {} %TYPE%::codename {} ::snit::RT.codename %TYPE% interp alias {} %TYPE%::myproc {} ::snit::RT.myproc %TYPE% interp alias {} %TYPE%::mymethod {} ::snit::RT.mymethod interp alias {} %TYPE%::mytypemethod {} ::snit::RT.mytypemethod %TYPE% interp alias {} %TYPE%::from {} ::snit::RT.from %TYPE% #------------------------------------------------------------------- # Snit's internal variables namespace eval %TYPE% { # Array: General Snit Info # # ns: The type's namespace # hasinstances: T or F, from pragma -hasinstances. # simpledispatch: T or F, from pragma -hasinstances. # canreplace: T or F, from pragma -canreplace. # counter: Count of instances created so far. # widgetclass: Set by widgetclass statement. # hulltype: Hull type (frame or toplevel) for widgets only. # exceptmethods: Methods explicitly not delegated to * # excepttypemethods: Methods explicitly not delegated to * # tvardecs: Type variable declarations--for dynamic methods # ivardecs: Instance variable declarations--for dyn. methods typevariable Snit_info set Snit_info(ns) %TYPE%:: set Snit_info(hasinstances) 1 set Snit_info(simpledispatch) 0 set Snit_info(canreplace) 0 set Snit_info(counter) 0 set Snit_info(widgetclass) {} set Snit_info(hulltype) frame set Snit_info(exceptmethods) {} set Snit_info(excepttypemethods) {} set Snit_info(tvardecs) {%TVARDECS%} set Snit_info(ivardecs) {%IVARDECS%} # Array: Public methods of this type. # The index is the method name, or "*". # The value is [list $pattern $componentName], where # $componentName is "" for normal methods. typevariable Snit_typemethodInfo array unset Snit_typemethodInfo # Array: Public methods of instances of this type. # The index is the method name, or "*". # The value is [list $pattern $componentName], where # $componentName is "" for normal methods. typevariable Snit_methodInfo array unset Snit_methodInfo # Array: option information. See dictionary.txt. typevariable Snit_optionInfo array unset Snit_optionInfo set Snit_optionInfo(local) {} set Snit_optionInfo(delegated) {} set Snit_optionInfo(starcomp) {} set Snit_optionInfo(except) {} } #---------------------------------------------------------------- # Compiled Procs # # These commands are created or replaced during compilation: # Snit_instanceVars selfns # # Initializes the instance variables, if any. Called during # instance creation. proc %TYPE%::Snit_instanceVars {selfns} { %INSTANCEVARS% } # Type Constructor proc %TYPE%::Snit_typeconstructor {type} { %TVARDECS% %TCONSTBODY% } #---------------------------------------------------------------- # Default Procs # # These commands might be replaced during compilation: # Snit_destructor type selfns win self # # Default destructor for the type. By default, it does # nothing. It's replaced by any user destructor. # For types, it's called by method destroy; for widgettypes, # it's called by a destroy event handler. proc %TYPE%::Snit_destructor {type selfns win self} { } #---------------------------------------------------------- # Compiled Definitions %COMPILEDDEFS% #---------------------------------------------------------- # Finally, call the Type Constructor %TYPE%::Snit_typeconstructor %TYPE% } #----------------------------------------------------------------------- # Type procs # # These procs expect the fully-qualified type name to be # substituted in for %TYPE%. # This is the nominal type proc. It supports typemethods and # delegated typemethods. set ::snit::nominalTypeProc { # Type dispatcher function. Note: This function lives # in the parent of the %TYPE% namespace! All accesses to # %TYPE% variables and methods must be qualified! proc %TYPE% {{method ""} args} { # First, if there's no method, and no args, and there's a create # method, and this isn't a widget, then method is "create" and # "args" is %AUTO%. if {[string equal $method ""] && [llength $args] == 0} { ::variable %TYPE%::Snit_info if {$Snit_info(hasinstances) && !$Snit_info(isWidget)} { set method create lappend args %AUTO% } else { error "wrong \# args: should be \"%TYPE% method args\"" } } # Next, retrieve the command. variable %TYPE%::Snit_typemethodCache while 1 { if {[catch {set Snit_typemethodCache($method)} commandRec]} { set commandRec [::snit::RT.CacheTypemethodCommand %TYPE% $method] if {[llength $commandRec] == 0} { return -code error "\"%TYPE% $method\" is not defined" } } # If we've got a real command, break. if {[lindex $commandRec 0] == 0} { break } # Otherwise, we need to look up again...if we can. if {[llength $args] == 0} { return -code error \ "wrong number args: should be \"%TYPE% $method method args\"" } lappend method [lindex $args 0] set args [lrange $args 1 end] } set command [lindex $commandRec 1] # Pass along the return code unchanged. set retval [catch {uplevel 1 $command $args} result] if {$retval} { if {$retval == 1} { global errorInfo global errorCode return -code error -errorinfo $errorInfo \ -errorcode $errorCode $result } else { return -code $retval $result } } return $result } } # This is the simplified type proc for when there are no typemethods # except create. In this case, it doesn't take a method argument; # the method is always "create". set ::snit::simpleTypeProc { # Type dispatcher function. Note: This function lives # in the parent of the %TYPE% namespace! All accesses to # %TYPE% variables and methods must be qualified! proc %TYPE% {args} { ::variable %TYPE%::Snit_info # FIRST, if the are no args, the single arg is %AUTO% if {[llength $args] == 0} { if {$Snit_info(isWidget)} { error "wrong \# args: should be \"%TYPE% name args\"" } lappend args %AUTO% } # NEXT, we're going to call the create method. # Pass along the return code unchanged. if {$Snit_info(isWidget)} { set command [list ::snit::RT.widget.typemethod.create %TYPE%] } else { set command [list ::snit::RT.type.typemethod.create %TYPE%] } set retval [catch {uplevel 1 $command $args} result] if {$retval} { if {$retval == 1} { global errorInfo global errorCode return -code error -errorinfo $errorInfo \ -errorcode $errorCode $result } else { return -code $retval $result } } return $result } } #----------------------------------------------------------------------- # Instance procs # # The following must be substituted into these proc bodies: # # %SELFNS% The instance namespace # %WIN% The original instance name # %TYPE% The fully-qualified type name # # Nominal instance proc body: supports method caching and delegation. # # proc $instanceName {method args} .... set ::snit::nominalInstanceProc { set self [set %SELFNS%::Snit_instance] while {1} { if {[catch {set %SELFNS%::Snit_methodCache($method)} commandRec]} { set commandRec [snit::RT.CacheMethodCommand %TYPE% %SELFNS% %WIN% $self $method] if {[llength $commandRec] == 0} { return -code error \ "\"$self $method\" is not defined" } } # If we've got a real command, break. if {[lindex $commandRec 0] == 0} { break } # Otherwise, we need to look up again...if we can. if {[llength $args] == 0} { return -code error \ "wrong number args: should be \"$self $method method args\"" } lappend method [lindex $args 0] set args [lrange $args 1 end] } set command [lindex $commandRec 1] # Pass along the return code unchanged. set retval [catch {uplevel 1 $command $args} result] if {$retval} { if {$retval == 1} { global errorInfo global errorCode return -code error -errorinfo $errorInfo \ -errorcode $errorCode $result } else { return -code $retval $result } } return $result } # Simplified method proc body: No delegation allowed; no support for # upvar or exotic return codes or hierarchical methods. Designed for # max speed for simple types. # # proc $instanceName {method args} .... set ::snit::simpleInstanceProc { set self [set %SELFNS%::Snit_instance] if {[lsearch -exact ${%TYPE%::Snit_methods} $method] == -1} { set optlist [join ${%TYPE%::Snit_methods} ", "] set optlist [linsert $optlist "end-1" "or"] error "bad option \"$method\": must be $optlist" } eval [linsert $args 0 \ %TYPE%::Snit_method$method %TYPE% %SELFNS% %WIN% $self] } #======================================================================= # Snit Type Definition # # These are the procs used to define Snit types, widgets, and # widgetadaptors. #----------------------------------------------------------------------- # Snit Compilation Variables # # The following variables are used while Snit is compiling a type, # and are disposed afterwards. namespace eval ::snit:: { # The compiler variable contains the name of the slave interpreter # used to compile type definitions. variable compiler "" # The compile array accumulates information about the type or # widgettype being compiled. It is cleared before and after each # compilation. It has these indices: # # type: The name of the type being compiled, for use # in compilation procs. # defs: Compiled definitions, both standard and client. # which: type, widget, widgetadaptor # instancevars: Instance variable definitions and initializations. # ivprocdec: Instance variable proc declarations. # tvprocdec: Type variable proc declarations. # typeconstructor: Type constructor body. # widgetclass: The widgetclass, for snit::widgets, only # hasoptions: False, initially; set to true when first # option is defined. # localoptions: Names of local options. # delegatedoptions: Names of delegated options. # localmethods: Names of locally defined methods. # delegatesmethods: no if no delegated methods, yes otherwise. # hashierarchic : no if no hierarchic methods, yes otherwise. # components: Names of defined components. # typecomponents: Names of defined typecomponents. # typevars: Typevariable definitions and initializations. # varnames: Names of instance variables # typevarnames Names of type variables # hasconstructor False, initially; true when constructor is # defined. # resource-$opt The option's resource name # class-$opt The option's class # -default-$opt The option's default value # -validatemethod-$opt The option's validate method # -configuremethod-$opt The option's configure method # -cgetmethod-$opt The option's cget method. # -hastypeinfo The -hastypeinfo pragma # -hastypedestroy The -hastypedestroy pragma # -hastypemethods The -hastypemethods pragma # -hasinfo The -hasinfo pragma # -hasinstances The -hasinstances pragma # -simpledispatch The -simpledispatch pragma # -canreplace The -canreplace pragma variable compile # This variable accumulates method dispatch information; it has # the same structure as the %TYPE%::Snit_methodInfo array, and is # used to initialize it. variable methodInfo # This variable accumulates typemethod dispatch information; it has # the same structure as the %TYPE%::Snit_typemethodInfo array, and is # used to initialize it. variable typemethodInfo # The following variable lists the reserved type definition statement # names, e.g., the names you can't use as macros. It's built at # compiler definition time using "info commands". variable reservedwords {} } #----------------------------------------------------------------------- # type compilation commands # # The type and widgettype commands use a slave interpreter to compile # the type definition. These are the procs # that are aliased into it. # Initialize the compiler proc ::snit::Comp.Init {} { variable compiler variable reservedwords if {[string equal $compiler ""]} { # Create the compiler's interpreter set compiler [interp create] # Initialize the interpreter $compiler eval { # Load package information # TBD: see if this can be moved outside. catch {package require ::snit::__does_not_exist__} # Protect some Tcl commands our type definitions # will shadow. rename proc _proc rename variable _variable } # Define compilation aliases. $compiler alias pragma ::snit::Comp.statement.pragma $compiler alias widgetclass ::snit::Comp.statement.widgetclass $compiler alias hulltype ::snit::Comp.statement.hulltype $compiler alias constructor ::snit::Comp.statement.constructor $compiler alias destructor ::snit::Comp.statement.destructor $compiler alias option ::snit::Comp.statement.option $compiler alias oncget ::snit::Comp.statement.oncget $compiler alias onconfigure ::snit::Comp.statement.onconfigure $compiler alias method ::snit::Comp.statement.method $compiler alias typemethod ::snit::Comp.statement.typemethod $compiler alias typeconstructor ::snit::Comp.statement.typeconstructor $compiler alias proc ::snit::Comp.statement.proc $compiler alias typevariable ::snit::Comp.statement.typevariable $compiler alias variable ::snit::Comp.statement.variable $compiler alias typecomponent ::snit::Comp.statement.typecomponent $compiler alias component ::snit::Comp.statement.component $compiler alias delegate ::snit::Comp.statement.delegate $compiler alias expose ::snit::Comp.statement.expose # Get the list of reserved words set reservedwords [$compiler eval {info commands}] } } # Compile a type definition, and return the results as a list of two # items: the fully-qualified type name, and a script that will define # the type when executed. # # which type, widget, or widgetadaptor # type the type name # body the type definition proc ::snit::Comp.Compile {which type body} { variable typeTemplate variable nominalTypeProc variable simpleTypeProc variable compile variable compiler variable methodInfo variable typemethodInfo # FIRST, qualify the name. if {![string match "::*" $type]} { # Get caller's namespace; # append :: if not global namespace. set ns [uplevel 2 [list namespace current]] if {"::" != $ns} { append ns "::" } set type "$ns$type" } # NEXT, create and initialize the compiler, if needed. Comp.Init # NEXT, initialize the class data array unset methodInfo array unset typemethodInfo array unset compile set compile(type) $type set compile(defs) {} set compile(which) $which set compile(hasoptions) no set compile(localoptions) {} set compile(instancevars) {} set compile(typevars) {} set compile(delegatedoptions) {} set compile(ivprocdec) {} set compile(tvprocdec) {} set compile(typeconstructor) {} set compile(widgetclass) {} set compile(hulltype) {} set compile(localmethods) {} set compile(delegatesmethods) no set compile(hashierarchic) no set compile(components) {} set compile(typecomponents) {} set compile(varnames) {} set compile(typevarnames) {} set compile(hasconstructor) no set compile(-hastypedestroy) yes set compile(-hastypeinfo) yes set compile(-hastypemethods) yes set compile(-hasinfo) yes set compile(-hasinstances) yes set compile(-simpledispatch) no set compile(-canreplace) no set isWidget [string match widget* $which] set isWidgetAdaptor [string match widgetadaptor $which] # NEXT, Evaluate the type's definition in the class interpreter. $compiler eval $body # NEXT, Add the standard definitions append compile(defs) \ "\nset %TYPE%::Snit_info(isWidget) $isWidget\n" append compile(defs) \ "\nset %TYPE%::Snit_info(isWidgetAdaptor) $isWidgetAdaptor\n" # Indicate whether the type can create instances that replace # existing commands. append compile(defs) "\nset %TYPE%::Snit_info(canreplace) $compile(-canreplace)\n" # Check pragmas for conflict. if {!$compile(-hastypemethods) && !$compile(-hasinstances)} { error "$which $type has neither typemethods nor instances" } if {$compile(-simpledispatch) && $compile(delegatesmethods)} { error "$which $type requests -simpledispatch but delegates methods." } if {$compile(-simpledispatch) && $compile(hashierarchic)} { error "$which $type requests -simpledispatch but defines hierarchical methods." } # If there are typemethods, define the standard typemethods and # the nominal type proc. Otherwise define the simple type proc. if {$compile(-hastypemethods)} { # Add the info typemethod unless the pragma forbids it. if {$compile(-hastypeinfo)} { Comp.statement.delegate typemethod info \ using {::snit::RT.typemethod.info %t} } # Add the destroy typemethod unless the pragma forbids it. if {$compile(-hastypedestroy)} { Comp.statement.delegate typemethod destroy \ using {::snit::RT.typemethod.destroy %t} } # Add the nominal type proc. append compile(defs) $nominalTypeProc } else { # Add the simple type proc. append compile(defs) $simpleTypeProc } # Add standard methods/typemethods that only make sense if the # type has instances. if {$compile(-hasinstances)} { # If we're using simple dispatch, remember that. if {$compile(-simpledispatch)} { append compile(defs) "\nset %TYPE%::Snit_info(simpledispatch) 1\n" } # Add the info method unless the pragma forbids it. if {$compile(-hasinfo)} { if {!$compile(-simpledispatch)} { Comp.statement.delegate method info \ using {::snit::RT.method.info %t %n %w %s} } else { Comp.statement.method info {args} { eval [linsert $args 0 \ ::snit::RT.method.info $type $selfns $win $self] } } } # Add the option handling stuff if there are any options. if {$compile(hasoptions)} { Comp.statement.variable options if {!$compile(-simpledispatch)} { Comp.statement.delegate method cget \ using {::snit::RT.method.cget %t %n %w %s} Comp.statement.delegate method configurelist \ using {::snit::RT.method.configurelist %t %n %w %s} Comp.statement.delegate method configure \ using {::snit::RT.method.configure %t %n %w %s} } else { Comp.statement.method cget {args} { eval [linsert $args 0 \ ::snit::RT.method.cget $type $selfns $win $self] } Comp.statement.method configurelist {args} { eval [linsert $args 0 \ ::snit::RT.method.configurelist $type $selfns $win $self] } Comp.statement.method configure {args} { eval [linsert $args 0 \ ::snit::RT.method.configure $type $selfns $win $self] } } } # Add a default constructor, if they haven't already defined one. # If there are options, it will configure args; otherwise it # will do nothing. if {!$compile(hasconstructor)} { if {$compile(hasoptions)} { Comp.statement.constructor {args} { $self configurelist $args } } else { Comp.statement.constructor {} {} } } if {!$isWidget} { if {!$compile(-simpledispatch)} { Comp.statement.delegate method destroy \ using {::snit::RT.method.destroy %t %n %w %s} } else { Comp.statement.method destroy {args} { eval [linsert $args 0 \ ::snit::RT.method.destroy $type $selfns $win $self] } } Comp.statement.delegate typemethod create \ using {::snit::RT.type.typemethod.create %t} } else { Comp.statement.delegate typemethod create \ using {::snit::RT.widget.typemethod.create %t} } # Save the list of method names, for -simpledispatch; otherwise, # save the method info. if {$compile(-simpledispatch)} { append compile(defs) \ "\nset %TYPE%::Snit_methods [list $compile(localmethods)]\n" } else { append compile(defs) \ "\narray set %TYPE%::Snit_methodInfo [list [array get methodInfo]]\n" } } else { append compile(defs) "\nset %TYPE%::Snit_info(hasinstances) 0\n" } # NEXT, compiling the type definition built up a set of information # about the type's locally defined options; add this information to # the compiled definition. Comp.SaveOptionInfo # NEXT, compiling the type definition built up a set of information # about the typemethods; save the typemethod info. append compile(defs) \ "\narray set %TYPE%::Snit_typemethodInfo [list [array get typemethodInfo]]\n" # NEXT, if this is a widget define the hull component if it isn't # already defined. if {$isWidget} { Comp.DefineComponent hull } # NEXT, substitute the compiled definition into the type template # to get the type definition script. set defscript [Expand $typeTemplate \ %COMPILEDDEFS% $compile(defs)] # NEXT, substitute the defined macros into the type definition script. # This is done as a separate step so that the compile(defs) can # contain the macros defined below. set defscript [Expand $defscript \ %TYPE% $type \ %IVARDECS% $compile(ivprocdec) \ %TVARDECS% $compile(tvprocdec) \ %TCONSTBODY% $compile(typeconstructor) \ %INSTANCEVARS% $compile(instancevars) \ %TYPEVARS% $compile(typevars) \ ] array unset compile return [list $type $defscript] } # Information about locally-defined options is accumulated during # compilation, but not added to the compiled definition--the option # statement can appear multiple times, so it's easier this way. # This proc fills in Snit_optionInfo with the accumulated information. # # It also computes the option's resource and class names if needed. # # Note that the information for delegated options was put in # Snit_optionInfo during compilation. proc ::snit::Comp.SaveOptionInfo {} { variable compile foreach option $compile(localoptions) { if {[string equal $compile(resource-$option) ""]} { set compile(resource-$option) [string range $option 1 end] } if {[string equal $compile(class-$option) ""]} { set compile(class-$option) [Capitalize $compile(resource-$option)] } # NOTE: Don't verify that the validate, configure, and cget # values name real methods; the methods might be defined outside # the typedefinition using snit::method. Mappend compile(defs) { # Option %OPTION% lappend %TYPE%::Snit_optionInfo(local) %OPTION% set %TYPE%::Snit_optionInfo(islocal-%OPTION%) 1 set %TYPE%::Snit_optionInfo(resource-%OPTION%) %RESOURCE% set %TYPE%::Snit_optionInfo(class-%OPTION%) %CLASS% set %TYPE%::Snit_optionInfo(default-%OPTION%) %DEFAULT% set %TYPE%::Snit_optionInfo(validate-%OPTION%) %VALIDATE% set %TYPE%::Snit_optionInfo(configure-%OPTION%) %CONFIGURE% set %TYPE%::Snit_optionInfo(cget-%OPTION%) %CGET% set %TYPE%::Snit_optionInfo(readonly-%OPTION%) %READONLY% } %OPTION% $option \ %RESOURCE% $compile(resource-$option) \ %CLASS% $compile(class-$option) \ %DEFAULT% [list $compile(-default-$option)] \ %VALIDATE% [list $compile(-validatemethod-$option)] \ %CONFIGURE% [list $compile(-configuremethod-$option)] \ %CGET% [list $compile(-cgetmethod-$option)] \ %READONLY% $compile(-readonly-$option) } } # Evaluates a compiled type definition, thus making the type available. proc ::snit::Comp.Define {compResult} { # The compilation result is a list containing the fully qualified # type name and a script to evaluate to define the type. set type [lindex $compResult 0] set defscript [lindex $compResult 1] # Execute the type definition script. # Consider using namespace eval %TYPE%. See if it's faster. if {[catch {eval $defscript} result]} { namespace delete $type catch {rename $type ""} error $result } return $type } # Sets pragma options which control how the type is defined. proc ::snit::Comp.statement.pragma {args} { variable compile set errRoot "Error in \"pragma...\"" foreach {opt val} $args { switch -exact -- $opt { -hastypeinfo - -hastypedestroy - -hastypemethods - -hasinstances - -simpledispatch - -hasinfo - -canreplace { if {![string is boolean -strict $val]} { error "$errRoot, \"$opt\" requires a boolean value" } set compile($opt) $val } default { error "$errRoot, unknown pragma" } } } } # Defines a widget's option class name. # This statement is only available for snit::widgets, # not for snit::types or snit::widgetadaptors. proc ::snit::Comp.statement.widgetclass {name} { variable compile # First, widgetclass can only be set for true widgets if {"widget" != $compile(which)} { error "widgetclass cannot be set for snit::$compile(which)s" } # Next, validate the option name. We'll require that it begin # with an uppercase letter. set initial [string index $name 0] if {![string is upper $initial]} { error "widgetclass \"$name\" does not begin with an uppercase letter" } if {"" != $compile(widgetclass)} { error "too many widgetclass statements" } # Next, save it. Mappend compile(defs) { set %TYPE%::Snit_info(widgetclass) %WIDGETCLASS% } %WIDGETCLASS% [list $name] set compile(widgetclass) $name } # Defines a widget's hull type. # This statement is only available for snit::widgets, # not for snit::types or snit::widgetadaptors. proc ::snit::Comp.statement.hulltype {name} { variable compile variable hulltypes # First, hulltype can only be set for true widgets if {"widget" != $compile(which)} { error "hulltype cannot be set for snit::$compile(which)s" } # Next, it must be one of the valid hulltypes (frame, toplevel, ...) if {[lsearch -exact $hulltypes [string trimleft $name :]] == -1} { error "invalid hulltype \"$name\", should be one of\ [join $hulltypes {, }]" } if {"" != $compile(hulltype)} { error "too many hulltype statements" } # Next, save it. Mappend compile(defs) { set %TYPE%::Snit_info(hulltype) %HULLTYPE% } %HULLTYPE% $name set compile(hulltype) $name } # Defines a constructor. proc ::snit::Comp.statement.constructor {arglist body} { variable compile CheckArgs "constructor" $arglist # Next, add a magic reference to self. set arglist [concat type selfns win self $arglist] # Next, add variable declarations to body: set body "%TVARDECS%%IVARDECS%\n$body" set compile(hasconstructor) yes append compile(defs) "proc %TYPE%::Snit_constructor [list $arglist] [list $body]\n" } # Defines a destructor. proc ::snit::Comp.statement.destructor {body} { variable compile # Next, add variable declarations to body: set body "%TVARDECS%%IVARDECS%\n$body" append compile(defs) "proc %TYPE%::Snit_destructor {type selfns win self} [list $body]\n\n" } # Defines a type option. The option value can be a triple, specifying # the option's -name, resource name, and class name. proc ::snit::Comp.statement.option {optionDef args} { variable compile # First, get the three option names. set option [lindex $optionDef 0] set resourceName [lindex $optionDef 1] set className [lindex $optionDef 2] set errRoot "Error in \"option [list $optionDef]...\"" # Next, validate the option name. if {![Comp.OptionNameIsValid $option]} { error "$errRoot, badly named option \"$option\"" } if {[Contains $option $compile(delegatedoptions)]} { error "$errRoot, cannot define \"$option\" locally, it has been delegated" } if {![Contains $option $compile(localoptions)]} { # Remember that we've seen this one. set compile(hasoptions) yes lappend compile(localoptions) $option # Initialize compilation info for this option. set compile(resource-$option) "" set compile(class-$option) "" set compile(-default-$option) "" set compile(-validatemethod-$option) "" set compile(-configuremethod-$option) "" set compile(-cgetmethod-$option) "" set compile(-readonly-$option) 0 } # NEXT, see if we have a resource name. If so, make sure it # isn't being redefined differently. if {![string equal $resourceName ""]} { if {[string equal $compile(resource-$option) ""]} { # If it's undefined, just save the value. set compile(resource-$option) $resourceName } elseif {![string equal $resourceName $compile(resource-$option)]} { # It's been redefined differently. error "$errRoot, resource name redefined from \"$compile(resource-$option)\" to \"$resourceName\"" } } # NEXT, see if we have a class name. If so, make sure it # isn't being redefined differently. if {![string equal $className ""]} { if {[string equal $compile(class-$option) ""]} { # If it's undefined, just save the value. set compile(class-$option) $className } elseif {![string equal $className $compile(class-$option)]} { # It's been redefined differently. error "$errRoot, class name redefined from \"$compile(class-$option)\" to \"$className\"" } } # NEXT, handle the args; it's not an error to redefine these. if {[llength $args] == 1} { set compile(-default-$option) [lindex $args 0] } else { foreach {optopt val} $args { switch -exact -- $optopt { -default - -validatemethod - -configuremethod - -cgetmethod { set compile($optopt-$option) $val } -readonly { if {![string is boolean -strict $val]} { error "$errRoot, -readonly requires a boolean, got \"$val\"" } set compile($optopt-$option) $val } default { error "$errRoot, unknown option definition option \"$optopt\"" } } } } } # 1 if the option name is valid, 0 otherwise. proc ::snit::Comp.OptionNameIsValid {option} { if {![string match {-*} $option] || [string match {*[A-Z ]*} $option]} { return 0 } return 1 } # Defines an option's cget handler proc ::snit::Comp.statement.oncget {option body} { variable compile set errRoot "Error in \"oncget $option...\"" if {[lsearch -exact $compile(delegatedoptions) $option] != -1} { return -code error "$errRoot, option \"$option\" is delegated" } if {[lsearch -exact $compile(localoptions) $option] == -1} { return -code error "$errRoot, option \"$option\" unknown" } # Next, add variable declarations to body: set body "%TVARDECS%%IVARDECS%\n$body" Comp.statement.method _cget$option {_option} $body Comp.statement.option $option -cgetmethod _cget$option } # Defines an option's configure handler. proc ::snit::Comp.statement.onconfigure {option arglist body} { variable compile if {[lsearch -exact $compile(delegatedoptions) $option] != -1} { return -code error "onconfigure $option: option \"$option\" is delegated" } if {[lsearch -exact $compile(localoptions) $option] == -1} { return -code error "onconfigure $option: option \"$option\" unknown" } if {[llength $arglist] != 1} { error \ "onconfigure $option handler should have one argument, got \"$arglist\"" } CheckArgs "onconfigure $option" $arglist # Next, add a magic reference to the option name set arglist [concat _option $arglist] Comp.statement.method _configure$option $arglist $body Comp.statement.option $option -configuremethod _configure$option } # Defines an instance method. proc ::snit::Comp.statement.method {method arglist body} { variable compile variable methodInfo # FIRST, check the method name against previously defined # methods. Comp.CheckMethodName $method 0 ::snit::methodInfo \ "Error in \"method [list $method]...\"" if {[llength $method] > 1} { set compile(hashierarchic) yes } # Remeber this method lappend compile(localmethods) $method CheckArgs "method [list $method]" $arglist # Next, add magic references to type and self. set arglist [concat type selfns win self $arglist] # Next, add variable declarations to body: set body "%TVARDECS%%IVARDECS%\n$body" # Next, save the definition script. if {[llength $method] == 1} { set methodInfo($method) {0 "%t::Snit_method%m %t %n %w %s" ""} Mappend compile(defs) { proc %TYPE%::Snit_method%METHOD% %ARGLIST% %BODY% } %METHOD% $method %ARGLIST% [list $arglist] %BODY% [list $body] } else { set methodInfo($method) {0 "%t::Snit_hmethod%j %t %n %w %s" ""} Mappend compile(defs) { proc %TYPE%::Snit_hmethod%JMETHOD% %ARGLIST% %BODY% } %JMETHOD% [join $method _] %ARGLIST% [list $arglist] \ %BODY% [list $body] } } # Check for name collisions; save prefix information. # # method The name of the method or typemethod. # delFlag 1 if delegated, 0 otherwise. # infoVar The fully qualified name of the array containing # information about the defined methods. # errRoot The root string for any error messages. proc ::snit::Comp.CheckMethodName {method delFlag infoVar errRoot} { upvar $infoVar methodInfo # FIRST, make sure the method name is a valid Tcl list. if {[catch {lindex $method 0}]} { error "$errRoot, the name \"$method\" must have list syntax." } # NEXT, check whether we can define it. if {![catch {set methodInfo($method)} data]} { # We can't redefine methods with submethods. if {[lindex $data 0] == 1} { error "$errRoot, \"$method\" has submethods." } # You can't delegate a method that's defined locally, # and you can't define a method locally if it's been delegated. if {$delFlag && [string equal [lindex $data 2] ""]} { error "$errRoot, \"$method\" has been defined locally." } elseif {!$delFlag && ![string equal [lindex $data 2] ""]} { error "$errRoot, \"$method\" has been delegated" } } # Handle hierarchical case. if {[llength $method] > 1} { set prefix {} set tokens $method while {[llength $tokens] > 1} { lappend prefix [lindex $tokens 0] set tokens [lrange $tokens 1 end] if {![catch {set methodInfo($prefix)} result]} { # Prefix is known. If it's not a prefix, throw an # error. if {[lindex $result 0] == 0} { error "$errRoot, \"$prefix\" has no submethods." } } set methodInfo($prefix) [list 1] } } } # Defines a typemethod method. proc ::snit::Comp.statement.typemethod {method arglist body} { variable compile variable typemethodInfo # FIRST, check the typemethod name against previously defined # typemethods. Comp.CheckMethodName $method 0 ::snit::typemethodInfo \ "Error in \"typemethod [list $method]...\"" CheckArgs "typemethod $method" $arglist # First, add magic reference to type. set arglist [concat type $arglist] # Next, add typevariable declarations to body: set body "%TVARDECS%\n$body" # Next, save the definition script if {[llength $method] == 1} { set typemethodInfo($method) {0 "%t::Snit_typemethod%m %t" ""} Mappend compile(defs) { proc %TYPE%::Snit_typemethod%METHOD% %ARGLIST% %BODY% } %METHOD% $method %ARGLIST% [list $arglist] %BODY% [list $body] } else { set typemethodInfo($method) {0 "%t::Snit_htypemethod%j %t" ""} Mappend compile(defs) { proc %TYPE%::Snit_htypemethod%JMETHOD% %ARGLIST% %BODY% } %JMETHOD% [join $method _] \ %ARGLIST% [list $arglist] %BODY% [list $body] } } # Defines a type constructor. proc ::snit::Comp.statement.typeconstructor {body} { variable compile if {"" != $compile(typeconstructor)} { error "too many typeconstructors" } set compile(typeconstructor) $body } # Defines a static proc in the type's namespace. proc ::snit::Comp.statement.proc {proc arglist body} { variable compile # If "ns" is defined, the proc can see instance variables. if {[lsearch -exact $arglist selfns] != -1} { # Next, add instance variable declarations to body: set body "%IVARDECS%\n$body" } # The proc can always see typevariables. set body "%TVARDECS%\n$body" append compile(defs) " # Proc $proc proc [list %TYPE%::$proc $arglist $body] " } # Defines a static variable in the type's namespace. proc ::snit::Comp.statement.typevariable {name args} { variable compile set errRoot "Error in \"typevariable $name...\"" set len [llength $args] if {$len > 2 || ($len == 2 && ![string equal [lindex $args 0] "-array"])} { error "$errRoot, too many initializers" } if {[lsearch -exact $compile(varnames) $name] != -1} { error "$errRoot, \"$name\" is already an instance variable" } lappend compile(typevarnames) $name if {$len == 1} { append compile(typevars) \ "\n\t [list ::variable $name [lindex $args 0]]" } elseif {$len == 2} { append compile(typevars) \ "\n\t [list ::variable $name]" append compile(typevars) \ "\n\t [list array set $name [lindex $args 1]]" } else { append compile(typevars) \ "\n\t [list ::variable $name]" } append compile(tvprocdec) "\n\t typevariable ${name}" } # Defines an instance variable; the definition will go in the # type's create typemethod. proc ::snit::Comp.statement.variable {name args} { variable compile set errRoot "Error in \"variable $name...\"" set len [llength $args] if {$len > 2 || ($len == 2 && ![string equal [lindex $args 0] "-array"])} { error "$errRoot, too many initializers" } if {[lsearch -exact $compile(typevarnames) $name] != -1} { error "$errRoot, \"$name\" is already a typevariable" } lappend compile(varnames) $name if {$len == 1} { append compile(instancevars) \ "\nset \${selfns}::$name [list [lindex $args 0]]\n" } elseif {$len == 2} { append compile(instancevars) \ "\narray set \${selfns}::$name [list [lindex $args 1]]\n" } append compile(ivprocdec) "\n\t " Mappend compile(ivprocdec) {::variable ${selfns}::%N} %N $name } # Defines a typecomponent, and handles component options. # # component The logical name of the delegate # args options. proc ::snit::Comp.statement.typecomponent {component args} { variable compile set errRoot "Error in \"typecomponent $component...\"" # FIRST, define the component Comp.DefineTypecomponent $component $errRoot # NEXT, handle the options. set publicMethod "" set inheritFlag 0 foreach {opt val} $args { switch -exact -- $opt { -public { set publicMethod $val } -inherit { set inheritFlag $val if {![string is boolean $inheritFlag]} { error "typecomponent $component -inherit: expected boolean value, got \"$val\"" } } default { error "typecomponent $component: Invalid option \"$opt\"" } } } # NEXT, if -public specified, define the method. if {![string equal $publicMethod ""]} { Comp.statement.delegate typemethod [list $publicMethod *] to $component } # NEXT, if "-inherit 1" is specified, delegate typemethod * to # this component. if {$inheritFlag} { Comp.statement.delegate typemethod "*" to $component } } # Defines a name to be a typecomponent # # The name becomes a typevariable; in addition, it gets a # write trace so that when it is set, all of the component mechanisms # get updated. # # component The component name proc ::snit::Comp.DefineTypecomponent {component {errRoot "Error"}} { variable compile if {[lsearch -exact $compile(varnames) $component] != -1} { error "$errRoot, \"$component\" is already an instance variable" } if {[lsearch -exact $compile(typecomponents) $component] == -1} { # Remember we've done this. lappend compile(typecomponents) $component # Make it a type variable with no initial value Comp.statement.typevariable $component "" # Add a write trace to do the component thing. Mappend compile(typevars) { trace variable %COMP% w \ [list ::snit::RT.TypecomponentTrace [list %TYPE%] %COMP%] } %TYPE% $compile(type) %COMP% $component } } # Defines a component, and handles component options. # # component The logical name of the delegate # args options. # # TBD: Ideally, it should be possible to call this statement multiple # times, possibly changing the option values. To do that, I'd need # to cache the option values and not act on them until *after* I'd # read the entire type definition. proc ::snit::Comp.statement.component {component args} { variable compile set errRoot "Error in \"component $component...\"" # FIRST, define the component Comp.DefineComponent $component $errRoot # NEXT, handle the options. set publicMethod "" set inheritFlag 0 foreach {opt val} $args { switch -exact -- $opt { -public { set publicMethod $val } -inherit { set inheritFlag $val if {![string is boolean $inheritFlag]} { error "component $component -inherit: expected boolean value, got \"$val\"" } } default { error "component $component: Invalid option \"$opt\"" } } } # NEXT, if -public specified, define the method. if {![string equal $publicMethod ""]} { Comp.statement.delegate method [list $publicMethod *] to $component } # NEXT, if -inherit is specified, delegate method/option * to # this component. if {$inheritFlag} { Comp.statement.delegate method "*" to $component Comp.statement.delegate option "*" to $component } } # Defines a name to be a component # # The name becomes an instance variable; in addition, it gets a # write trace so that when it is set, all of the component mechanisms # get updated. # # component The component name proc ::snit::Comp.DefineComponent {component {errRoot "Error"}} { variable compile if {[lsearch -exact $compile(typevarnames) $component] != -1} { error "$errRoot, \"$component\" is already a typevariable" } if {[lsearch -exact $compile(components) $component] == -1} { # Remember we've done this. lappend compile(components) $component # Make it an instance variable with no initial value Comp.statement.variable $component "" # Add a write trace to do the component thing. Mappend compile(instancevars) { trace variable ${selfns}::%COMP% w \ [list ::snit::RT.ComponentTrace [list %TYPE%] $selfns %COMP%] } %TYPE% $compile(type) %COMP% $component } } # Creates a delegated method, typemethod, or option. proc ::snit::Comp.statement.delegate {what name args} { # FIRST, dispatch to correct handler. switch $what { typemethod { Comp.DelegatedTypemethod $name $args } method { Comp.DelegatedMethod $name $args } option { Comp.DelegatedOption $name $args } default { error "Error in \"delegate $what $name...\", \"$what\"?" } } if {([llength $args] % 2) != 0} { error "Error in \"delegate $what $name...\", invalid syntax" } } # Creates a delegated typemethod delegating it to a particular # typecomponent or an arbitrary command. # # method The name of the method # arglist Delegation options proc ::snit::Comp.DelegatedTypemethod {method arglist} { variable compile variable typemethodInfo set errRoot "Error in \"delegate typemethod [list $method]...\"" # Next, parse the delegation options. set component "" set target "" set exceptions {} set pattern "" set methodTail [lindex $method end] foreach {opt value} $arglist { switch -exact $opt { to { set component $value } as { set target $value } except { set exceptions $value } using { set pattern $value } default { error "$errRoot, unknown delegation option \"$opt\"" } } } if {[string equal $component ""] && [string equal $pattern ""]} { error "$errRoot, missing \"to\"" } if {[string equal $methodTail "*"] && ![string equal $target ""]} { error "$errRoot, cannot specify \"as\" with \"*\"" } if {![string equal $methodTail "*"] && ![string equal $exceptions ""]} { error "$errRoot, can only specify \"except\" with \"*\"" } if {![string equal $pattern ""] && ![string equal $target ""]} { error "$errRoot, cannot specify both \"as\" and \"using\"" } foreach token [lrange $method 1 end-1] { if {[string equal $token "*"]} { error "$errRoot, \"*\" must be the last token." } } # NEXT, define the component if {![string equal $component ""]} { Comp.DefineTypecomponent $component $errRoot } # NEXT, define the pattern. if {[string equal $pattern ""]} { if {[string equal $methodTail "*"]} { set pattern "%c %m" } elseif {![string equal $target ""]} { set pattern "%c $target" } else { set pattern "%c %m" } } # Make sure the pattern is a valid list. if {[catch {lindex $pattern 0} result]} { error "$errRoot, the using pattern, \"$pattern\", is not a valid list" } # NEXT, check the method name against previously defined # methods. Comp.CheckMethodName $method 1 ::snit::typemethodInfo $errRoot set typemethodInfo($method) [list 0 $pattern $component] if {[string equal $methodTail "*"]} { Mappend compile(defs) { set %TYPE%::Snit_info(excepttypemethods) %EXCEPT% } %EXCEPT% [list $exceptions] } } # Creates a delegated method delegating it to a particular # component or command. # # method The name of the method # arglist Delegation options. proc ::snit::Comp.DelegatedMethod {method arglist} { variable compile variable methodInfo set errRoot "Error in \"delegate method [list $method]...\"" # Next, parse the delegation options. set component "" set target "" set exceptions {} set pattern "" set methodTail [lindex $method end] foreach {opt value} $arglist { switch -exact $opt { to { set component $value } as { set target $value } except { set exceptions $value } using { set pattern $value } default { error "$errRoot, unknown delegation option \"$opt\"" } } } if {[string equal $component ""] && [string equal $pattern ""]} { error "$errRoot, missing \"to\"" } if {[string equal $methodTail "*"] && ![string equal $target ""]} { error "$errRoot, cannot specify \"as\" with \"*\"" } if {![string equal $methodTail "*"] && ![string equal $exceptions ""]} { error "$errRoot, can only specify \"except\" with \"*\"" } if {![string equal $pattern ""] &&![string equal $target ""]} { error "$errRoot, cannot specify both \"as\" and \"using\"" } foreach token [lrange $method 1 end-1] { if {[string equal $token "*"]} { error "$errRoot, \"*\" must be the last token." } } # NEXT, we delegate some methods set compile(delegatesmethods) yes # NEXT, define the component. Allow typecomponents. if {![string equal $component ""]} { if {[lsearch -exact $compile(typecomponents) $component] == -1} { Comp.DefineComponent $component $errRoot } } # NEXT, define the pattern. if {[string equal $pattern ""]} { if {[string equal $methodTail "*"]} { set pattern "%c %m" } elseif {![string equal $target ""]} { set pattern "%c $target" } else { set pattern "%c %m" } } # Make sure the pattern is a valid list. if {[catch {lindex $pattern 0} result]} { error "$errRoot, the using pattern, \"$pattern\", is not a valid list" } # NEXT, check the method name against previously defined # methods. Comp.CheckMethodName $method 1 ::snit::methodInfo $errRoot # NEXT, save the method info. set methodInfo($method) [list 0 $pattern $component] if {[string equal $methodTail "*"]} { Mappend compile(defs) { set %TYPE%::Snit_info(exceptmethods) %EXCEPT% } %EXCEPT% [list $exceptions] } } # Creates a delegated option, delegating it to a particular # component and, optionally, to a particular option of that # component. # # optionDef The option definition # args definition arguments. proc ::snit::Comp.DelegatedOption {optionDef arglist} { variable compile # First, get the three option names. set option [lindex $optionDef 0] set resourceName [lindex $optionDef 1] set className [lindex $optionDef 2] set errRoot "Error in \"delegate option [list $optionDef]...\"" # Next, parse the delegation options. set component "" set target "" set exceptions {} foreach {opt value} $arglist { switch -exact $opt { to { set component $value } as { set target $value } except { set exceptions $value } default { error "$errRoot, unknown delegation option \"$opt\"" } } } if {[string equal $component ""]} { error "$errRoot, missing \"to\"" } if {[string equal $option "*"] && ![string equal $target ""]} { error "$errRoot, cannot specify \"as\" with \"delegate option *\"" } if {![string equal $option "*"] && ![string equal $exceptions ""]} { error "$errRoot, can only specify \"except\" with \"delegate option *\"" } # Next, validate the option name if {"*" != $option} { if {![Comp.OptionNameIsValid $option]} { error "$errRoot, badly named option \"$option\"" } } if {[Contains $option $compile(localoptions)]} { error "$errRoot, \"$option\" has been defined locally" } if {[Contains $option $compile(delegatedoptions)]} { error "$errRoot, \"$option\" is multiply delegated" } # NEXT, define the component Comp.DefineComponent $component $errRoot # Next, define the target option, if not specified. if {![string equal $option "*"] && [string equal $target ""]} { set target $option } # NEXT, save the delegation data. set compile(hasoptions) yes if {![string equal $option "*"]} { lappend compile(delegatedoptions) $option # Next, compute the resource and class names, if they aren't # already defined. if {"" == $resourceName} { set resourceName [string range $option 1 end] } if {"" == $className} { set className [Capitalize $resourceName] } Mappend compile(defs) { set %TYPE%::Snit_optionInfo(islocal-%OPTION%) 0 set %TYPE%::Snit_optionInfo(resource-%OPTION%) %RES% set %TYPE%::Snit_optionInfo(class-%OPTION%) %CLASS% lappend %TYPE%::Snit_optionInfo(delegated) %OPTION% set %TYPE%::Snit_optionInfo(target-%OPTION%) [list %COMP% %TARGET%] lappend %TYPE%::Snit_optionInfo(delegated-%COMP%) %OPTION% } %OPTION% $option \ %COMP% $component \ %TARGET% $target \ %RES% $resourceName \ %CLASS% $className } else { Mappend compile(defs) { set %TYPE%::Snit_optionInfo(starcomp) %COMP% set %TYPE%::Snit_optionInfo(except) %EXCEPT% } %COMP% $component %EXCEPT% [list $exceptions] } } # Exposes a component, effectively making the component's command an # instance method. # # component The logical name of the delegate # "as" sugar; if not "", must be "as" # methodname The desired method name for the component's command, or "" proc ::snit::Comp.statement.expose {component {"as" ""} {methodname ""}} { variable compile # FIRST, define the component Comp.DefineComponent $component # NEXT, define the method just as though it were in the type # definition. if {[string equal $methodname ""]} { set methodname $component } Comp.statement.method $methodname args [Expand { if {[llength $args] == 0} { return $%COMPONENT% } if {[string equal $%COMPONENT% ""]} { error "undefined component \"%COMPONENT%\"" } set cmd [linsert $args 0 $%COMPONENT%] return [uplevel 1 $cmd] } %COMPONENT% $component] } #----------------------------------------------------------------------- # Public commands # Compile a type definition, and return the results as a list of two # items: the fully-qualified type name, and a script that will define # the type when executed. # # which type, widget, or widgetadaptor # type the type name # body the type definition proc ::snit::compile {which type body} { return [Comp.Compile $which $type $body] } proc ::snit::type {type body} { return [Comp.Define [Comp.Compile type $type $body]] } proc ::snit::widget {type body} { return [Comp.Define [Comp.Compile widget $type $body]] } proc ::snit::widgetadaptor {type body} { return [Comp.Define [Comp.Compile widgetadaptor $type $body]] } proc ::snit::typemethod {type method arglist body} { # Make sure the type exists. if {![info exists ${type}::Snit_info]} { error "no such type: \"$type\"" } upvar ${type}::Snit_info Snit_info upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo # FIRST, check the typemethod name against previously defined # typemethods. Comp.CheckMethodName $method 0 ${type}::Snit_typemethodInfo \ "Cannot define \"$method\"" # NEXT, check the arguments CheckArgs "snit::typemethod $type $method" $arglist # Next, add magic reference to type. set arglist [concat type $arglist] # Next, add typevariable declarations to body: set body "$Snit_info(tvardecs)\n$body" # Next, define it. if {[llength $method] == 1} { set Snit_typemethodInfo($method) {0 "%t::Snit_typemethod%m %t" ""} uplevel 1 [list proc ${type}::Snit_typemethod$method $arglist $body] } else { set Snit_typemethodInfo($method) {0 "%t::Snit_htypemethod%j %t" ""} set suffix [join $method _] uplevel 1 [list proc ${type}::Snit_htypemethod$suffix $arglist $body] } } proc ::snit::method {type method arglist body} { # Make sure the type exists. if {![info exists ${type}::Snit_info]} { error "no such type: \"$type\"" } upvar ${type}::Snit_methodInfo Snit_methodInfo upvar ${type}::Snit_info Snit_info # FIRST, check the method name against previously defined # methods. Comp.CheckMethodName $method 0 ${type}::Snit_methodInfo \ "Cannot define \"$method\"" # NEXT, check the arguments CheckArgs "snit::method $type $method" $arglist # Next, add magic references to type and self. set arglist [concat type selfns win self $arglist] # Next, add variable declarations to body: set body "$Snit_info(tvardecs)$Snit_info(ivardecs)\n$body" # Next, define it. if {[llength $method] == 1} { set Snit_methodInfo($method) {0 "%t::Snit_method%m %t %n %w %s" ""} uplevel 1 [list proc ${type}::Snit_method$method $arglist $body] } else { set Snit_methodInfo($method) {0 "%t::Snit_hmethod%j %t %n %w %s" ""} set suffix [join $method _] uplevel 1 [list proc ${type}::Snit_hmethod$suffix $arglist $body] } } # Defines a proc within the compiler; this proc can call other # type definition statements, and thus can be used for meta-programming. proc ::snit::macro {name arglist body} { variable compiler variable reservedwords # FIRST, make sure the compiler is defined. Comp.Init # NEXT, check the macro name against the reserved words if {[lsearch -exact $reservedwords $name] != -1} { error "invalid macro name \"$name\"" } # NEXT, see if the name has a namespace; if it does, define the # namespace. set ns [namespace qualifiers $name] if {![string equal $ns ""]} { $compiler eval "namespace eval $ns {}" } # NEXT, define the macro $compiler eval [list _proc $name $arglist $body] } #----------------------------------------------------------------------- # Utility Functions # # These are utility functions used while compiling Snit types. # Builds a template from a tagged list of text blocks, then substitutes # all symbols in the mapTable, returning the expanded template. proc ::snit::Expand {template args} { return [string map $args $template] } # Expands a template and appends it to a variable. proc ::snit::Mappend {varname template args} { upvar $varname myvar append myvar [string map $args $template] } # Checks argument list against reserved args proc ::snit::CheckArgs {which arglist} { variable reservedArgs foreach name $reservedArgs { if {[Contains $name $arglist]} { error "$which's arglist may not contain \"$name\" explicitly" } } } # Returns 1 if a value is in a list, and 0 otherwise. proc ::snit::Contains {value list} { if {[lsearch -exact $list $value] != -1} { return 1 } else { return 0 } } # Capitalizes the first letter of a string. proc ::snit::Capitalize {text} { set first [string index $text 0] set rest [string range $text 1 end] return "[string toupper $first]$rest" } # Converts an arbitrary white-space-delimited string into a list # by splitting on white-space and deleting empty tokens. proc ::snit::Listify {str} { set result {} foreach token [split [string trim $str]] { if {[string length $token] > 0} { lappend result $token } } return $result } #======================================================================= # Snit Runtime Library # # These are procs used by Snit types and widgets at runtime. #----------------------------------------------------------------------- # Object Creation # Creates a new instance of the snit::type given its name and the args. # # type The snit::type # name The instance name # args Args to pass to the constructor proc ::snit::RT.type.typemethod.create {type name args} { variable ${type}::Snit_info variable ${type}::Snit_optionInfo # FIRST, qualify the name. if {![string match "::*" $name]} { # Get caller's namespace; # append :: if not global namespace. set ns [uplevel 1 [list namespace current]] if {"::" != $ns} { append ns "::" } set name "$ns$name" } # NEXT, if %AUTO% appears in the name, generate a unique # command name. Otherwise, ensure that the name isn't in use. if {[string match "*%AUTO%*" $name]} { set name [::snit::RT.UniqueName Snit_info(counter) $type $name] } elseif {$Snit_info(canreplace) && [llength [info commands $name]]} { #kmg-tcl83 # # Had to add this elseif branch to pass test rename-1.5 # # Allowed to replace so must first destroy the prior instance $name destroy } elseif {!$Snit_info(canreplace) && [llength [info commands $name]]} { error "command \"$name\" already exists" } # NEXT, create the instance's namespace. set selfns \ [::snit::RT.UniqueInstanceNamespace Snit_info(counter) $type] namespace eval $selfns {} # NEXT, install the dispatcher RT.MakeInstanceCommand $type $selfns $name # Initialize the options to their defaults. upvar ${selfns}::options options foreach opt $Snit_optionInfo(local) { set options($opt) $Snit_optionInfo(default-$opt) } # Initialize the instance vars to their defaults. # selfns must be defined, as it is used implicitly. ${type}::Snit_instanceVars $selfns # Execute the type's constructor. set errcode [catch { RT.ConstructInstance $type $selfns $name $args } result] if {$errcode} { global errorInfo global errorCode set theInfo $errorInfo set theCode $errorCode ::snit::RT.DestroyObject $type $selfns $name error "Error in constructor: $result" $theInfo $theCode } # NEXT, return the object's name. return $name } # Creates a new instance of the snit::widget or snit::widgetadaptor # given its name and the args. # # type The snit::widget or snit::widgetadaptor # name The instance name # args Args to pass to the constructor proc ::snit::RT.widget.typemethod.create {type name args} { variable ${type}::Snit_info variable ${type}::Snit_optionInfo # FIRST, if %AUTO% appears in the name, generate a unique # command name. if {[string match "*%AUTO%*" $name]} { set name [::snit::RT.UniqueName Snit_info(counter) $type $name] } # NEXT, create the instance's namespace. set selfns \ [::snit::RT.UniqueInstanceNamespace Snit_info(counter) $type] namespace eval $selfns { } # NEXT, Initialize the widget's own options to their defaults. upvar ${selfns}::options options foreach opt $Snit_optionInfo(local) { set options($opt) $Snit_optionInfo(default-$opt) } # Initialize the instance vars to their defaults. ${type}::Snit_instanceVars $selfns # NEXT, if this is a normal widget (not a widget adaptor) then # create a frame as its hull. We set the frame's -class to # the user's widgetclass, or, if none, to the basename of # the $type with an initial upper case letter. if {!$Snit_info(isWidgetAdaptor)} { # FIRST, determine the class name if {"" == $Snit_info(widgetclass)} { set Snit_info(widgetclass) \ [::snit::Capitalize [namespace tail $type]] } # NEXT, create the widget set self $name package require Tk ${type}::installhull using \ $Snit_info(hulltype) -class $Snit_info(widgetclass) # NEXT, let's query the option database for our # widget, now that we know that it exists. foreach opt $Snit_optionInfo(local) { set dbval [RT.OptionDbGet $type $name $opt] if {"" != $dbval} { set options($opt) $dbval } } } # Execute the type's constructor, and verify that it # has a hull. set errcode [catch { RT.ConstructInstance $type $selfns $name $args ::snit::RT.Component $type $selfns hull # Prepare to call the object's destructor when the # event is received. Use a Snit-specific bindtag # so that the widget name's tag is unencumbered. bind Snit$type$name [::snit::Expand { ::snit::RT.DestroyObject %TYPE% %NS% %W } %TYPE% $type %NS% $selfns] # Insert the bindtag into the list of bindtags right # after the widget name. set taglist [bindtags $name] set ndx [lsearch -exact $taglist $name] incr ndx bindtags $name [linsert $taglist $ndx Snit$type$name] } result] if {$errcode} { global errorInfo global errorCode set theInfo $errorInfo set theCode $errorCode ::snit::RT.DestroyObject $type $selfns $name error "Error in constructor: $result" $theInfo $theCode } # NEXT, return the object's name. return $name } # RT.MakeInstanceCommand type selfns instance # # type The object type # selfns The instance namespace # instance The instance name # # Creates the instance proc. proc ::snit::RT.MakeInstanceCommand {type selfns instance} { variable ${type}::Snit_info # FIRST, remember the instance name. The Snit_instance variable # allows the instance to figure out its current name given the # instance namespace. upvar ${selfns}::Snit_instance Snit_instance set Snit_instance $instance # NEXT, qualify the proc name if it's a widget. if {$Snit_info(isWidget)} { set procname ::$instance } else { set procname $instance } # NEXT, install the new proc if {!$Snit_info(simpledispatch)} { set instanceProc $::snit::nominalInstanceProc } else { set instanceProc $::snit::simpleInstanceProc } proc $procname {method args} \ [string map \ [list %SELFNS% $selfns %WIN% $instance %TYPE% $type] \ $instanceProc] #kmg-tcl83 # NEXT, add the trace. ::snit83::traceAddCommand $procname {rename delete} \ [list ::snit::RT.InstanceTrace $type $selfns $instance] } # This proc is called when the instance command is renamed. # If op is delete, then new will always be "", so op is redundant. # # type The fully-qualified type name # selfns The instance namespace # win The original instance/tk window name. # old old instance command name # new new instance command name # op rename or delete # # If the op is delete, we need to clean up the object; otherwise, # we need to track the change. # # NOTE: In Tcl 8.4.2 there's a bug: errors in rename and delete # traces aren't propagated correctly. Instead, they silently # vanish. Add a catch to output any error message. proc ::snit::RT.InstanceTrace {type selfns win old new op} { variable ${type}::Snit_info # Note to developers ... # For Tcl 8.4.0, errors thrown in trace handlers vanish silently. # Therefore we catch them here and create some output to help in # debugging such problems. if {[catch { # FIRST, clean up if necessary if {"" == $new} { if {$Snit_info(isWidget)} { destroy $win } else { ::snit::RT.DestroyObject $type $selfns $win } } else { # Otherwise, track the change. variable ${selfns}::Snit_instance set Snit_instance [uplevel 1 [list namespace which -command $new]] # Also, clear the instance caches, as many cached commands # might be invalid. RT.ClearInstanceCaches $selfns } } result]} { global errorInfo # Pop up the console on Windows wish, to enable stdout. # This clobbers errorInfo on unix, so save it so we can print it. set ei $errorInfo catch {console show} puts "Error in ::snit::RT.InstanceTrace $type $selfns $win $old $new $op:" puts $ei } } # Calls the instance constructor and handles related housekeeping. proc ::snit::RT.ConstructInstance {type selfns instance arglist} { variable ${type}::Snit_optionInfo variable ${selfns}::Snit_iinfo # Track whether we are constructed or not. set Snit_iinfo(constructed) 0 # Call the user's constructor eval [linsert $arglist 0 \ ${type}::Snit_constructor $type $selfns $instance $instance] set Snit_iinfo(constructed) 1 # Unset the configure cache for all -readonly options. # This ensures that the next time anyone tries to # configure it, an error is thrown. foreach opt $Snit_optionInfo(local) { if {$Snit_optionInfo(readonly-$opt)} { ::snit83::unset -nocomplain ${selfns}::Snit_configureCache($opt) } } return } # Returns a unique command name. # # REQUIRE: type is a fully qualified name. # REQUIRE: name contains "%AUTO%" # PROMISE: the returned command name is unused. proc ::snit::RT.UniqueName {countervar type name} { upvar $countervar counter while 1 { # FIRST, bump the counter and define the %AUTO% instance name; # then substitute it into the specified name. Wrap around at # 2^31 - 2 to prevent overflow problems. incr counter if {$counter > 2147483646} { set counter 0 } set auto "[namespace tail $type]$counter" set candidate [Expand $name %AUTO% $auto] if {![llength [info commands $candidate]]} { return $candidate } } } # Returns a unique instance namespace, fully qualified. # # countervar The name of a counter variable # type The instance's type # # REQUIRE: type is fully qualified # PROMISE: The returned namespace name is unused. proc ::snit::RT.UniqueInstanceNamespace {countervar type} { upvar $countervar counter while 1 { # FIRST, bump the counter and define the namespace name. # Then see if it already exists. Wrap around at # 2^31 - 2 to prevent overflow problems. incr counter if {$counter > 2147483646} { set counter 0 } set ins "${type}::Snit_inst${counter}" if {![namespace exists $ins]} { return $ins } } } # Retrieves an option's value from the option database. # Returns "" if no value is found. proc ::snit::RT.OptionDbGet {type self opt} { variable ${type}::Snit_optionInfo return [option get $self \ $Snit_optionInfo(resource-$opt) \ $Snit_optionInfo(class-$opt)] } #----------------------------------------------------------------------- # Object Destruction # Implements the standard "destroy" method # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name proc ::snit::RT.method.destroy {type selfns win self} { variable ${selfns}::Snit_iinfo # Can't destroy the object if it isn't complete constructed. if {!$Snit_iinfo(constructed)} { return -code error "Called 'destroy' method in constructor" } # Calls Snit_cleanup, which (among other things) calls the # user's destructor. ::snit::RT.DestroyObject $type $selfns $win } # This is the function that really cleans up; it's automatically # called when any instance is destroyed, e.g., by "$object destroy" # for types, and by the event for widgets. # # type The fully-qualified type name. # selfns The instance namespace # win The original instance command name. proc ::snit::RT.DestroyObject {type selfns win} { variable ${type}::Snit_info # If the variable Snit_instance doesn't exist then there's no # instance command for this object -- it's most likely a # widgetadaptor. Consequently, there are some things that # we don't need to do. if {[info exists ${selfns}::Snit_instance]} { upvar ${selfns}::Snit_instance instance # First, remove the trace on the instance name, so that we # don't call RT.DestroyObject recursively. RT.RemoveInstanceTrace $type $selfns $win $instance # Next, call the user's destructor ${type}::Snit_destructor $type $selfns $win $instance # Next, if this isn't a widget, delete the instance command. # If it is a widget, get the hull component's name, and rename # it back to the widget name # Next, delete the hull component's instance command, # if there is one. if {$Snit_info(isWidget)} { set hullcmd [::snit::RT.Component $type $selfns hull] catch {rename $instance ""} # Clear the bind event bind Snit$type$win "" if {[llength [info commands $hullcmd]]} { # FIRST, rename the hull back to its original name. # If the hull is itself a megawidget, it will have its # own cleanup to do, and it might not do it properly # if it doesn't have the right name. rename $hullcmd ::$instance # NEXT, destroy it. destroy $instance } } else { catch {rename $instance ""} } } # Next, delete the instance's namespace. This kills any # instance variables. namespace delete $selfns } # Remove instance trace # # type The fully qualified type name # selfns The instance namespace # win The original instance name/Tk window name # instance The current instance name proc ::snit::RT.RemoveInstanceTrace {type selfns win instance} { variable ${type}::Snit_info if {$Snit_info(isWidget)} { set procname ::$instance } else { set procname $instance } # NEXT, remove any trace on this name catch { #kmg-tcl83 ::snit83::traceRemoveCommand $procname {rename delete} \ [list ::snit::RT.InstanceTrace $type $selfns $win] } } #----------------------------------------------------------------------- # Typecomponent Management and Method Caching # Typecomponent trace; used for write trace on typecomponent # variables. Saves the new component object name, provided # that certain conditions are met. Also clears the typemethod # cache. proc ::snit::RT.TypecomponentTrace {type component n1 n2 op} { upvar ${type}::Snit_info Snit_info upvar ${type}::${component} cvar upvar ${type}::Snit_typecomponents Snit_typecomponents # Save the new component value. set Snit_typecomponents($component) $cvar # Clear the typemethod cache. # TBD: can we unset just the elements related to # this component? ::snit83::unset -nocomplain -- ${type}::Snit_typemethodCache } # Generates and caches the command for a typemethod. # # type The type # method The name of the typemethod to call. # # The return value is one of the following lists: # # {} There's no such method. # {1} The method has submethods; look again. # {0 } Here's the command to execute. proc snit::RT.CacheTypemethodCommand {type method} { upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo upvar ${type}::Snit_typecomponents Snit_typecomponents upvar ${type}::Snit_typemethodCache Snit_typemethodCache upvar ${type}::Snit_info Snit_info # FIRST, get the pattern data and the typecomponent name. set implicitCreate 0 set instanceName "" set starredMethod [lreplace $method end end *] set methodTail [lindex $method end] if {[info exists Snit_typemethodInfo($method)]} { set key $method } elseif {[info exists Snit_typemethodInfo($starredMethod)]} { if {[lsearch -exact $Snit_info(excepttypemethods) $methodTail] == -1} { set key $starredMethod } else { return [list ] } } elseif {$Snit_info(hasinstances)} { # Assume the unknown name is an instance name to create, unless # this is a widget and the style of the name is wrong, or the # name mimics a standard typemethod. if {[set ${type}::Snit_info(isWidget)] && ![string match ".*" $method]} { return [list ] } # Without this check, the call "$type info" will redefine the # standard "::info" command, with disastrous results. Since it's # a likely thing to do if !-typeinfo, put in an explicit check. if {[string equal $method "info"] || [string equal $method "destroy"]} { return [list ] } set implicitCreate 1 set instanceName $method set key create set method create } else { return [list ] } foreach {flag pattern compName} $Snit_typemethodInfo($key) {} if {$flag == 1} { return [list 1] } # NEXT, build the substitution list set subList [list \ %% % \ %t $type \ %M $method \ %m [lindex $method end] \ %j [join $method _]] if {![string equal $compName ""]} { if {![info exists Snit_typecomponents($compName)]} { error "$type delegates typemethod \"$method\" to undefined typecomponent \"$compName\"" } lappend subList %c [list $Snit_typecomponents($compName)] } set command {} foreach subpattern $pattern { lappend command [string map $subList $subpattern] } if {$implicitCreate} { # In this case, $method is the name of the instance to # create. Don't cache, as we usually won't do this one # again. lappend command $instanceName } else { set Snit_typemethodCache($method) [list 0 $command] } return [list 0 $command] } #----------------------------------------------------------------------- # Component Management and Method Caching # Retrieves the object name given the component name. proc ::snit::RT.Component {type selfns name} { variable ${selfns}::Snit_components if {[catch {set Snit_components($name)} result]} { variable ${selfns}::Snit_instance error "component \"$name\" is undefined in $type $Snit_instance" } return $result } # Component trace; used for write trace on component instance # variables. Saves the new component object name, provided # that certain conditions are met. Also clears the method # cache. proc ::snit::RT.ComponentTrace {type selfns component n1 n2 op} { upvar ${type}::Snit_info Snit_info upvar ${selfns}::${component} cvar upvar ${selfns}::Snit_components Snit_components # If they try to redefine the hull component after # it's been defined, that's an error--but only if # this is a widget or widget adaptor. if {"hull" == $component && $Snit_info(isWidget) && [info exists Snit_components($component)]} { set cvar $Snit_components($component) error "The hull component cannot be redefined" } # Save the new component value. set Snit_components($component) $cvar # Clear the instance caches. # TBD: can we unset just the elements related to # this component? RT.ClearInstanceCaches $selfns } # Generates and caches the command for a method. # # type: The instance's type # selfns: The instance's private namespace # win: The instance's original name (a Tk widget name, for # snit::widgets. # self: The instance's current name. # method: The name of the method to call. # # The return value is one of the following lists: # # {} There's no such method. # {1} The method has submethods; look again. # {0 } Here's the command to execute. proc ::snit::RT.CacheMethodCommand {type selfns win self method} { variable ${type}::Snit_info variable ${type}::Snit_methodInfo variable ${type}::Snit_typecomponents variable ${selfns}::Snit_components variable ${selfns}::Snit_methodCache # FIRST, get the pattern data and the component name. set starredMethod [lreplace $method end end *] set methodTail [lindex $method end] if {[info exists Snit_methodInfo($method)]} { set key $method } elseif {[info exists Snit_methodInfo($starredMethod)] && [lsearch -exact $Snit_info(exceptmethods) $methodTail] == -1} { set key $starredMethod } else { return [list ] } foreach {flag pattern compName} $Snit_methodInfo($key) {} if {$flag == 1} { return [list 1] } # NEXT, build the substitution list set subList [list \ %% % \ %t $type \ %M $method \ %m [lindex $method end] \ %j [join $method _] \ %n [list $selfns] \ %w [list $win] \ %s [list $self]] if {![string equal $compName ""]} { if {[info exists Snit_components($compName)]} { set compCmd $Snit_components($compName) } elseif {[info exists Snit_typecomponents($compName)]} { set compCmd $Snit_typecomponents($compName) } else { error "$type $self delegates method \"$method\" to undefined component \"$compName\"" } lappend subList %c [list $compCmd] } # Note: The cached command will executed faster if it's # already a list. set command {} foreach subpattern $pattern { lappend command [string map $subList $subpattern] } set commandRec [list 0 $command] set Snit_methodCache($method) $commandRec return $commandRec } # Looks up a method's command. # # type: The instance's type # selfns: The instance's private namespace # win: The instance's original name (a Tk widget name, for # snit::widgets. # self: The instance's current name. # method: The name of the method to call. # errPrefix: Prefix for any error method proc ::snit::RT.LookupMethodCommand {type selfns win self method errPrefix} { set commandRec [snit::RT.CacheMethodCommand \ $type $selfns $win $self \ $method] if {[llength $commandRec] == 0} { return -code error \ "$errPrefix, \"$self $method\" is not defined" } elseif {[lindex $commandRec 0] == 1} { return -code error \ "$errPrefix, wrong number args: should be \"$self\" $method method args" } return [lindex $commandRec 1] } # Clears all instance command caches proc ::snit::RT.ClearInstanceCaches {selfns} { ::snit83::unset -nocomplain -- ${selfns}::Snit_methodCache ::snit83::unset -nocomplain -- ${selfns}::Snit_cgetCache ::snit83::unset -nocomplain -- ${selfns}::Snit_configureCache ::snit83::unset -nocomplain -- ${selfns}::Snit_validateCache } #----------------------------------------------------------------------- # Component Installation # Implements %TYPE%::installhull. The variables self and selfns # must be defined in the caller's context. # # Installs the named widget as the hull of a # widgetadaptor. Once the widget is hijacked, its new name # is assigned to the hull component. proc ::snit::RT.installhull {type {using "using"} {widgetType ""} args} { variable ${type}::Snit_info variable ${type}::Snit_optionInfo upvar self self upvar selfns selfns upvar ${selfns}::hull hull upvar ${selfns}::options options # FIRST, make sure we can do it. if {!$Snit_info(isWidget)} { error "installhull is valid only for snit::widgetadaptors" } if {[info exists ${selfns}::Snit_instance]} { error "hull already installed for $type $self" } # NEXT, has it been created yet? If not, create it using # the specified arguments. if {"using" == $using} { # FIRST, create the widget set cmd [linsert $args 0 $widgetType $self] set obj [uplevel 1 $cmd] # NEXT, for each option explicitly delegated to the hull # that doesn't appear in the usedOpts list, get the # option database value and apply it--provided that the # real option name and the target option name are different. # (If they are the same, then the option database was # already queried as part of the normal widget creation.) # # Also, we don't need to worry about implicitly delegated # options, as the option and target option names must be # the same. if {[info exists Snit_optionInfo(delegated-hull)]} { # FIRST, extract all option names from args set usedOpts {} set ndx [lsearch -glob $args "-*"] foreach {opt val} [lrange $args $ndx end] { lappend usedOpts $opt } foreach opt $Snit_optionInfo(delegated-hull) { set target [lindex $Snit_optionInfo(target-$opt) 1] if {"$target" == $opt} { continue } set result [lsearch -exact $usedOpts $target] if {$result != -1} { continue } set dbval [RT.OptionDbGet $type $self $opt] $obj configure $target $dbval } } } else { set obj $using if {![string equal $obj $self]} { error \ "hull name mismatch: \"$obj\" != \"$self\"" } } # NEXT, get the local option defaults. foreach opt $Snit_optionInfo(local) { set dbval [RT.OptionDbGet $type $self $opt] if {"" != $dbval} { set options($opt) $dbval } } # NEXT, do the magic set i 0 while 1 { incr i set newName "::hull${i}$self" if {![llength [info commands $newName]]} { break } } rename ::$self $newName RT.MakeInstanceCommand $type $selfns $self # Note: this relies on RT.ComponentTrace to do the dirty work. set hull $newName return } # Implements %TYPE%::install. # # Creates a widget and installs it as the named component. # It expects self and selfns to be defined in the caller's context. proc ::snit::RT.install {type compName "using" widgetType winPath args} { variable ${type}::Snit_optionInfo variable ${type}::Snit_info upvar self self upvar selfns selfns upvar ${selfns}::$compName comp upvar ${selfns}::hull hull # We do the magic option database stuff only if $self is # a widget. if {$Snit_info(isWidget)} { if {"" == $hull} { error "tried to install \"$compName\" before the hull exists" } # FIRST, query the option database and save the results # into args. Insert them before the first option in the # list, in case there are any non-standard parameters. # # Note: there might not be any delegated options; if so, # don't bother. if {[info exists Snit_optionInfo(delegated-$compName)]} { set ndx [lsearch -glob $args "-*"] foreach opt $Snit_optionInfo(delegated-$compName) { set dbval [RT.OptionDbGet $type $self $opt] if {"" != $dbval} { set target [lindex $Snit_optionInfo(target-$opt) 1] set args [linsert $args $ndx $target $dbval] } } } } # NEXT, create the component and save it. set cmd [concat [list $widgetType $winPath] $args] set comp [uplevel 1 $cmd] # NEXT, handle the option database for "delegate option *", # in widgets only. if {$Snit_info(isWidget) && [string equal $Snit_optionInfo(starcomp) $compName]} { # FIRST, get the list of option specs from the widget. # If configure doesn't work, skip it. if {[catch {$comp configure} specs]} { return } # NEXT, get the set of explicitly used options from args set usedOpts {} set ndx [lsearch -glob $args "-*"] foreach {opt val} [lrange $args $ndx end] { lappend usedOpts $opt } # NEXT, "delegate option *" matches all options defined # by this widget that aren't defined by the widget as a whole, # and that aren't excepted. Plus, we skip usedOpts. So build # a list of the options it can't match. set skiplist [concat \ $usedOpts \ $Snit_optionInfo(except) \ $Snit_optionInfo(local) \ $Snit_optionInfo(delegated)] # NEXT, loop over all of the component's options, and set # any not in the skip list for which there is an option # database value. foreach spec $specs { # Skip aliases if {[llength $spec] != 5} { continue } set opt [lindex $spec 0] if {[lsearch -exact $skiplist $opt] != -1} { continue } set res [lindex $spec 1] set cls [lindex $spec 2] set dbvalue [option get $self $res $cls] if {"" != $dbvalue} { $comp configure $opt $dbvalue } } } return } #----------------------------------------------------------------------- # Method/Variable Name Qualification # Implements %TYPE%::variable. Requires selfns. proc ::snit::RT.variable {varname} { upvar selfns selfns if {![string match "::*" $varname]} { uplevel 1 [list upvar 1 ${selfns}::$varname $varname] } else { # varname is fully qualified; let the standard # "variable" command handle it. uplevel 1 [list ::variable $varname] } } # Fully qualifies a typevariable name. # # This is used to implement the mytypevar command. proc ::snit::RT.mytypevar {type name} { return ${type}::$name } # Fully qualifies an instance variable name. # # This is used to implement the myvar command. proc ::snit::RT.myvar {name} { upvar selfns selfns return ${selfns}::$name } # Use this like "list" to convert a proc call into a command # string to pass to another object (e.g., as a -command). # Qualifies the proc name properly. # # This is used to implement the "myproc" command. proc ::snit::RT.myproc {type procname args} { set procname "${type}::$procname" return [linsert $args 0 $procname] } # DEPRECATED proc ::snit::RT.codename {type name} { return "${type}::$name" } # Use this like "list" to convert a typemethod call into a command # string to pass to another object (e.g., as a -command). # Inserts the type command at the beginning. # # This is used to implement the "mytypemethod" command. proc ::snit::RT.mytypemethod {type args} { return [linsert $args 0 $type] } # Use this like "list" to convert a method call into a command # string to pass to another object (e.g., as a -command). # Inserts the code at the beginning to call the right object, even if # the object's name has changed. Requires that selfns be defined # in the calling context, eg. can only be called in instance # code. # # This is used to implement the "mymethod" command. proc ::snit::RT.mymethod {args} { upvar selfns selfns return [linsert $args 0 ::snit::RT.CallInstance ${selfns}] } # Calls an instance method for an object given its # instance namespace and remaining arguments (the first of which # will be the method name. # # selfns The instance namespace # args The arguments # # Uses the selfns to determine $self, and calls the method # in the normal way. # # This is used to implement the "mymethod" command. proc ::snit::RT.CallInstance {selfns args} { upvar ${selfns}::Snit_instance self set retval [catch {uplevel 1 [linsert $args 0 $self]} result] if {$retval} { if {$retval == 1} { global errorInfo global errorCode return -code error -errorinfo $errorInfo \ -errorcode $errorCode $result } else { return -code $retval $result } } return $result } # Looks for the named option in the named variable. If found, # it and its value are removed from the list, and the value # is returned. Otherwise, the default value is returned. # If the option is undelegated, it's own default value will be # used if none is specified. # # Implements the "from" command. proc ::snit::RT.from {type argvName option {defvalue ""}} { variable ${type}::Snit_optionInfo upvar $argvName argv set ioption [lsearch -exact $argv $option] if {$ioption == -1} { if {"" == $defvalue && [info exists Snit_optionInfo(default-$option)]} { return $Snit_optionInfo(default-$option) } else { return $defvalue } } set ivalue [expr {$ioption + 1}] set value [lindex $argv $ivalue] set argv [lreplace $argv $ioption $ivalue] return $value } #----------------------------------------------------------------------- # Type Destruction # Implements the standard "destroy" typemethod: # Destroys a type completely. # # type The snit type proc ::snit::RT.typemethod.destroy {type} { variable ${type}::Snit_info # FIRST, destroy all instances foreach selfns [namespace children $type] { if {![namespace exists $selfns]} { continue } upvar ${selfns}::Snit_instance obj if {$Snit_info(isWidget)} { destroy $obj } else { if {[llength [info commands $obj]]} { $obj destroy } } } # NEXT, destroy the type's data. namespace delete $type # NEXT, get rid of the type command. rename $type "" } #----------------------------------------------------------------------- # Option Handling # Implements the standard "cget" method # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # option The name of the option proc ::snit::RT.method.cget {type selfns win self option} { if {[catch {set ${selfns}::Snit_cgetCache($option)} command]} { set command [snit::RT.CacheCgetCommand $type $selfns $win $self $option] if {[llength $command] == 0} { return -code error "unknown option \"$option\"" } } uplevel 1 $command } # Retrieves and caches the command that implements "cget" for the # specified option. # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # option The name of the option proc ::snit::RT.CacheCgetCommand {type selfns win self option} { variable ${type}::Snit_optionInfo variable ${selfns}::Snit_cgetCache if {[info exists Snit_optionInfo(islocal-$option)]} { # We know the item; it's either local, or explicitly delegated. if {$Snit_optionInfo(islocal-$option)} { # It's a local option. If it has a cget method defined, # use it; otherwise just return the value. if {[string equal $Snit_optionInfo(cget-$option) ""]} { set command [list set ${selfns}::options($option)] } else { set command [snit::RT.LookupMethodCommand \ $type $selfns $win $self \ $Snit_optionInfo(cget-$option) \ "can't cget $option"] lappend command $option } set Snit_cgetCache($option) $command return $command } # Explicitly delegated option; get target set comp [lindex $Snit_optionInfo(target-$option) 0] set target [lindex $Snit_optionInfo(target-$option) 1] } elseif {![string equal $Snit_optionInfo(starcomp) ""] && [lsearch -exact $Snit_optionInfo(except) $option] == -1} { # Unknown option, but unknowns are delegated; get target. set comp $Snit_optionInfo(starcomp) set target $option } else { return "" } # Get the component's object. set obj [RT.Component $type $selfns $comp] set command [list $obj cget $target] set Snit_cgetCache($option) $command return $command } # Implements the standard "configurelist" method # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # optionlist A list of options and their values. proc ::snit::RT.method.configurelist {type selfns win self optionlist} { variable ${type}::Snit_optionInfo foreach {option value} $optionlist { # FIRST, get the configure command, caching it if need be. if {[catch {set ${selfns}::Snit_configureCache($option)} command]} { set command [snit::RT.CacheConfigureCommand \ $type $selfns $win $self $option] if {[llength $command] == 0} { return -code error "unknown option \"$option\"" } } # NEXT, the caching the configure command also cached the # validate command, if any. If we have one, run it. set valcommand [set ${selfns}::Snit_validateCache($option)] if {[llength $valcommand]} { lappend valcommand $value uplevel 1 $valcommand } # NEXT, configure the option with the value. lappend command $value uplevel 1 $command } return } # Retrieves and caches the command that stores the named option. # Also stores the command that validates the name option if any; # If none, the validate command is "", so that the cache is always # populated. # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # option An option name proc ::snit::RT.CacheConfigureCommand {type selfns win self option} { variable ${type}::Snit_optionInfo variable ${selfns}::Snit_configureCache variable ${selfns}::Snit_validateCache if {[info exist Snit_optionInfo(islocal-$option)]} { # We know the item; it's either local, or explicitly delegated. if {$Snit_optionInfo(islocal-$option)} { # It's a local option. # If it's readonly, it throws an error if we're already # constructed. if {$Snit_optionInfo(readonly-$option)} { if {[set ${selfns}::Snit_iinfo(constructed)]} { error "option $option can only be set at instance creation" } } # If it has a validate method, cache that for later. if {![string equal $Snit_optionInfo(validate-$option) ""]} { set command [snit::RT.LookupMethodCommand \ $type $selfns $win $self \ $Snit_optionInfo(validate-$option) \ "can't validate $option"] lappend command $option set Snit_validateCache($option) $command } else { set Snit_validateCache($option) "" } # If it has a configure method defined, # cache it; otherwise, just set the value. if {[string equal $Snit_optionInfo(configure-$option) ""]} { set command [list set ${selfns}::options($option)] } else { set command [snit::RT.LookupMethodCommand \ $type $selfns $win $self \ $Snit_optionInfo(configure-$option) \ "can't configure $option"] lappend command $option } set Snit_configureCache($option) $command return $command } # Delegated option: get target. set comp [lindex $Snit_optionInfo(target-$option) 0] set target [lindex $Snit_optionInfo(target-$option) 1] } elseif {$Snit_optionInfo(starcomp) != "" && [lsearch -exact $Snit_optionInfo(except) $option] == -1} { # Unknown option, but unknowns are delegated. set comp $Snit_optionInfo(starcomp) set target $option } else { return "" } # There is no validate command in this case; save an empty string. set Snit_validateCache($option) "" # Get the component's object set obj [RT.Component $type $selfns $comp] set command [list $obj configure $target] set Snit_configureCache($option) $command return $command } # Implements the standard "configure" method # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # args A list of options and their values, possibly empty. proc ::snit::RT.method.configure {type selfns win self args} { # If two or more arguments, set values as usual. if {[llength $args] >= 2} { ::snit::RT.method.configurelist $type $selfns $win $self $args return } # If zero arguments, acquire data for each known option # and return the list if {[llength $args] == 0} { set result {} foreach opt [RT.method.info.options $type $selfns $win $self] { # Refactor this, so that we don't need to call via $self. lappend result [RT.GetOptionDbSpec \ $type $selfns $win $self $opt] } return $result } # They want it for just one. set opt [lindex $args 0] return [RT.GetOptionDbSpec $type $selfns $win $self $opt] } # Retrieves the option database spec for a single option. # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # option The name of an option # # TBD: This is a bad name. What it's returning is the # result of the configure query. proc ::snit::RT.GetOptionDbSpec {type selfns win self opt} { variable ${type}::Snit_optionInfo upvar ${selfns}::Snit_components Snit_components upvar ${selfns}::options options if {[info exists options($opt)]} { # This is a locally-defined option. Just build the # list and return it. set res $Snit_optionInfo(resource-$opt) set cls $Snit_optionInfo(class-$opt) set def $Snit_optionInfo(default-$opt) return [list $opt $res $cls $def \ [RT.method.cget $type $selfns $win $self $opt]] } elseif {[info exists Snit_optionInfo(target-$opt)]} { # This is an explicitly delegated option. The only # thing we don't have is the default. set res $Snit_optionInfo(resource-$opt) set cls $Snit_optionInfo(class-$opt) # Get the default set logicalName [lindex $Snit_optionInfo(target-$opt) 0] set comp $Snit_components($logicalName) set target [lindex $Snit_optionInfo(target-$opt) 1] if {[catch {$comp configure $target} result]} { set defValue {} } else { set defValue [lindex $result 3] } return [list $opt $res $cls $defValue [$self cget $opt]] } elseif {![string equal $Snit_optionInfo(starcomp) ""] && [lsearch -exact $Snit_optionInfo(except) $opt] == -1} { set logicalName $Snit_optionInfo(starcomp) set target $opt set comp $Snit_components($logicalName) if {[catch {set value [$comp cget $target]} result]} { error "unknown option \"$opt\"" } if {![catch {$comp configure $target} result]} { # Replace the delegated option name with the local name. return [::snit::Expand $result $target $opt] } # configure didn't work; return simple form. return [list $opt "" "" "" $value] } else { error "unknown option \"$opt\"" } } #----------------------------------------------------------------------- # Type Introspection # Implements the standard "info" typemethod. # # type The snit type # command The info subcommand # args All other arguments. proc ::snit::RT.typemethod.info {type command args} { global errorInfo global errorCode switch -exact $command { typevars - typemethods - instances { # TBD: it should be possible to delete this error # handling. set errflag [catch { uplevel 1 [linsert $args 0 \ ::snit::RT.typemethod.info.$command $type] } result] if {$errflag} { return -code error -errorinfo $errorInfo \ -errorcode $errorCode $result } else { return $result } } default { error "\"$type info $command\" is not defined" } } } # Returns a list of the type's typevariables whose names match a # pattern, excluding Snit internal variables. # # type A Snit type # pattern Optional. The glob pattern to match. Defaults # to *. proc ::snit::RT.typemethod.info.typevars {type {pattern *}} { set result {} foreach name [info vars "${type}::$pattern"] { set tail [namespace tail $name] if {![string match "Snit_*" $tail]} { lappend result $name } } return $result } # Returns a list of the type's methods whose names match a # pattern. If "delegate typemethod *" is used, the list may # not be complete. # # type A Snit type # pattern Optional. The glob pattern to match. Defaults # to *. proc ::snit::RT.typemethod.info.typemethods {type {pattern *}} { variable ${type}::Snit_typemethodInfo variable ${type}::Snit_typemethodCache # FIRST, get the explicit names, skipping prefixes. set result {} foreach name [array names Snit_typemethodInfo $pattern] { if {[lindex $Snit_typemethodInfo($name) 0] != 1} { lappend result $name } } # NEXT, add any from the cache that aren't explicit. if {[info exists Snit_typemethodInfo(*)]} { # First, remove "*" from the list. set ndx [lsearch -exact $result "*"] if {$ndx != -1} { set result [lreplace $result $ndx $ndx] } foreach name [array names Snit_typemethodCache $pattern] { if {[lsearch -exact $result $name] == -1} { lappend result $name } } } return $result } # Returns a list of the type's instances whose names match # a pattern. # # type A Snit type # pattern Optional. The glob pattern to match # Defaults to * # # REQUIRE: type is fully qualified. proc ::snit::RT.typemethod.info.instances {type {pattern *}} { set result {} foreach selfns [namespace children $type] { upvar ${selfns}::Snit_instance instance if {[string match $pattern $instance]} { lappend result $instance } } return $result } #----------------------------------------------------------------------- # Instance Introspection # Implements the standard "info" method. # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # command The info subcommand # args All other arguments. proc ::snit::RT.method.info {type selfns win self command args} { switch -exact $command { type - vars - options - methods - typevars - typemethods { set errflag [catch { uplevel 1 [linsert $args 0 ::snit::RT.method.info.$command \ $type $selfns $win $self] } result] if {$errflag} { global errorInfo return -code error -errorinfo $errorInfo $result } else { return $result } } default { # error "\"$self info $command\" is not defined" return -code error "\"$self info $command\" is not defined" } } } # $self info type # # Returns the instance's type proc ::snit::RT.method.info.type {type selfns win self} { return $type } # $self info typevars # # Returns the instance's type's typevariables proc ::snit::RT.method.info.typevars {type selfns win self {pattern *}} { return [RT.typemethod.info.typevars $type $pattern] } # $self info typemethods # # Returns the instance's type's typemethods proc ::snit::RT.method.info.typemethods {type selfns win self {pattern *}} { return [RT.typemethod.info.typemethods $type $pattern] } # Returns a list of the instance's methods whose names match a # pattern. If "delegate method *" is used, the list may # not be complete. # # type A Snit type # selfns The instance namespace # win The original instance name # self The current instance name # pattern Optional. The glob pattern to match. Defaults # to *. proc ::snit::RT.method.info.methods {type selfns win self {pattern *}} { variable ${type}::Snit_methodInfo variable ${selfns}::Snit_methodCache # FIRST, get the explicit names, skipping prefixes. set result {} foreach name [array names Snit_methodInfo $pattern] { if {[lindex $Snit_methodInfo($name) 0] != 1} { lappend result $name } } # NEXT, add any from the cache that aren't explicit. if {[info exists Snit_methodInfo(*)]} { # First, remove "*" from the list. set ndx [lsearch -exact $result "*"] if {$ndx != -1} { set result [lreplace $result $ndx $ndx] } foreach name [array names Snit_methodCache $pattern] { if {[lsearch -exact $result $name] == -1} { lappend result $name } } } return $result } # $self info vars # # Returns the instance's instance variables proc ::snit::RT.method.info.vars {type selfns win self {pattern *}} { set result {} foreach name [info vars "${selfns}::$pattern"] { set tail [namespace tail $name] if {![string match "Snit_*" $tail]} { lappend result $name } } return $result } # $self info options # # Returns a list of the names of the instance's options proc ::snit::RT.method.info.options {type selfns win self {pattern *}} { variable ${type}::Snit_optionInfo # First, get the local and explicitly delegated options set result [concat $Snit_optionInfo(local) $Snit_optionInfo(delegated)] # If "configure" works as for Tk widgets, add the resulting # options to the list. Skip excepted options if {![string equal $Snit_optionInfo(starcomp) ""]} { upvar ${selfns}::Snit_components Snit_components set logicalName $Snit_optionInfo(starcomp) set comp $Snit_components($logicalName) if {![catch {$comp configure} records]} { foreach record $records { set opt [lindex $record 0] if {[lsearch -exact $result $opt] == -1 && [lsearch -exact $Snit_optionInfo(except) $opt] == -1} { lappend result $opt } } } } # Next, apply the pattern set names {} foreach name $result { if {[string match $pattern $name]} { lappend names $name } } return $names } amsn-0.98.9/utils/snit/main2.tcl0000644000175000017500000036412011020317540016217 0ustar billiobbilliob#----------------------------------------------------------------------- # TITLE: # main2.tcl # # AUTHOR: # Will Duquette # # DESCRIPTION: # Snit's Not Incr Tcl, a simple object system in Pure Tcl. # # Snit 2.x Compiler and Run-Time Library # # Copyright (C) 2003-2006 by William H. Duquette # This code is licensed as described in license.txt. # #----------------------------------------------------------------------- #----------------------------------------------------------------------- # Namespace namespace eval ::snit:: { namespace export \ compile type widget widgetadaptor typemethod method macro } #----------------------------------------------------------------------- # Some Snit variables namespace eval ::snit:: { variable reservedArgs {type selfns win self} # Widget classes which can be hulls (must have -class) variable hulltypes { toplevel tk::toplevel frame tk::frame ttk::frame labelframe tk::labelframe ttk::labelframe } } #----------------------------------------------------------------------- # Snit Type Implementation template namespace eval ::snit:: { # Template type definition: All internal and user-visible Snit # implementation code. # # The following placeholders will automatically be replaced with # the client's code, in two passes: # # First pass: # %COMPILEDDEFS% The compiled type definition. # # Second pass: # %TYPE% The fully qualified type name. # %IVARDECS% Instance variable declarations # %TVARDECS% Type variable declarations # %TCONSTBODY% Type constructor body # %INSTANCEVARS% The compiled instance variable initialization code. # %TYPEVARS% The compiled type variable initialization code. # This is the overall type template. variable typeTemplate # This is the normal type proc variable nominalTypeProc # This is the "-hastypemethods no" type proc variable simpleTypeProc } set ::snit::typeTemplate { #------------------------------------------------------------------- # The type's namespace definition and the user's type variables namespace eval %TYPE% {%TYPEVARS% } #---------------------------------------------------------------- # Commands for use in methods, typemethods, etc. # # These are implemented as aliases into the Snit runtime library. interp alias {} %TYPE%::installhull {} ::snit::RT.installhull %TYPE% interp alias {} %TYPE%::install {} ::snit::RT.install %TYPE% interp alias {} %TYPE%::typevariable {} ::variable interp alias {} %TYPE%::variable {} ::snit::RT.variable interp alias {} %TYPE%::mytypevar {} ::snit::RT.mytypevar %TYPE% interp alias {} %TYPE%::typevarname {} ::snit::RT.mytypevar %TYPE% interp alias {} %TYPE%::myvar {} ::snit::RT.myvar interp alias {} %TYPE%::varname {} ::snit::RT.myvar interp alias {} %TYPE%::codename {} ::snit::RT.codename %TYPE% interp alias {} %TYPE%::myproc {} ::snit::RT.myproc %TYPE% interp alias {} %TYPE%::mymethod {} ::snit::RT.mymethod interp alias {} %TYPE%::mytypemethod {} ::snit::RT.mytypemethod %TYPE% interp alias {} %TYPE%::from {} ::snit::RT.from %TYPE% #------------------------------------------------------------------- # Snit's internal variables namespace eval %TYPE% { # Array: General Snit Info # # ns: The type's namespace # hasinstances: T or F, from pragma -hasinstances. # simpledispatch: T or F, from pragma -hasinstances. # canreplace: T or F, from pragma -canreplace. # counter: Count of instances created so far. # widgetclass: Set by widgetclass statement. # hulltype: Hull type (frame or toplevel) for widgets only. # exceptmethods: Methods explicitly not delegated to * # excepttypemethods: Methods explicitly not delegated to * # tvardecs: Type variable declarations--for dynamic methods # ivardecs: Instance variable declarations--for dyn. methods typevariable Snit_info set Snit_info(ns) %TYPE%:: set Snit_info(hasinstances) 1 set Snit_info(simpledispatch) 0 set Snit_info(canreplace) 0 set Snit_info(counter) 0 set Snit_info(widgetclass) {} set Snit_info(hulltype) frame set Snit_info(exceptmethods) {} set Snit_info(excepttypemethods) {} set Snit_info(tvardecs) {%TVARDECS%} set Snit_info(ivardecs) {%IVARDECS%} # Array: Public methods of this type. # The index is the method name, or "*". # The value is [list $pattern $componentName], where # $componentName is "" for normal methods. typevariable Snit_typemethodInfo array unset Snit_typemethodInfo # Array: Public methods of instances of this type. # The index is the method name, or "*". # The value is [list $pattern $componentName], where # $componentName is "" for normal methods. typevariable Snit_methodInfo array unset Snit_methodInfo # Array: option information. See dictionary.txt. typevariable Snit_optionInfo array unset Snit_optionInfo set Snit_optionInfo(local) {} set Snit_optionInfo(delegated) {} set Snit_optionInfo(starcomp) {} set Snit_optionInfo(except) {} } #---------------------------------------------------------------- # Compiled Procs # # These commands are created or replaced during compilation: # Snit_instanceVars selfns # # Initializes the instance variables, if any. Called during # instance creation. proc %TYPE%::Snit_instanceVars {selfns} { %INSTANCEVARS% } # Type Constructor proc %TYPE%::Snit_typeconstructor {type} { %TVARDECS% namespace path [namespace parent $type] %TCONSTBODY% } #---------------------------------------------------------------- # Default Procs # # These commands might be replaced during compilation: # Snit_destructor type selfns win self # # Default destructor for the type. By default, it does # nothing. It's replaced by any user destructor. # For types, it's called by method destroy; for widgettypes, # it's called by a destroy event handler. proc %TYPE%::Snit_destructor {type selfns win self} { } #---------------------------------------------------------- # Compiled Definitions %COMPILEDDEFS% #---------------------------------------------------------- # Finally, call the Type Constructor %TYPE%::Snit_typeconstructor %TYPE% } #----------------------------------------------------------------------- # Type procs # # These procs expect the fully-qualified type name to be # substituted in for %TYPE%. # This is the nominal type proc. It supports typemethods and # delegated typemethods. set ::snit::nominalTypeProc { # WHD: Code for creating the type ensemble namespace eval %TYPE% { namespace ensemble create \ -unknown [list ::snit::RT.UnknownTypemethod %TYPE% ""] \ -prefixes 0 } } # This is the simplified type proc for when there are no typemethods # except create. In this case, it doesn't take a method argument; # the method is always "create". set ::snit::simpleTypeProc { # Type dispatcher function. Note: This function lives # in the parent of the %TYPE% namespace! All accesses to # %TYPE% variables and methods must be qualified! proc %TYPE% {args} { ::variable %TYPE%::Snit_info # FIRST, if the are no args, the single arg is %AUTO% if {[llength $args] == 0} { if {$Snit_info(isWidget)} { error "wrong \# args: should be \"%TYPE% name args\"" } lappend args %AUTO% } # NEXT, we're going to call the create method. # Pass along the return code unchanged. if {$Snit_info(isWidget)} { set command [list ::snit::RT.widget.typemethod.create %TYPE%] } else { set command [list ::snit::RT.type.typemethod.create %TYPE%] } set retval [catch {uplevel 1 $command $args} result] if {$retval} { if {$retval == 1} { global errorInfo global errorCode return -code error -errorinfo $errorInfo \ -errorcode $errorCode $result } else { return -code $retval $result } } return $result } } #======================================================================= # Snit Type Definition # # These are the procs used to define Snit types, widgets, and # widgetadaptors. #----------------------------------------------------------------------- # Snit Compilation Variables # # The following variables are used while Snit is compiling a type, # and are disposed afterwards. namespace eval ::snit:: { # The compiler variable contains the name of the slave interpreter # used to compile type definitions. variable compiler "" # The compile array accumulates information about the type or # widgettype being compiled. It is cleared before and after each # compilation. It has these indices: # # type: The name of the type being compiled, for use # in compilation procs. # defs: Compiled definitions, both standard and client. # which: type, widget, widgetadaptor # instancevars: Instance variable definitions and initializations. # ivprocdec: Instance variable proc declarations. # tvprocdec: Type variable proc declarations. # typeconstructor: Type constructor body. # widgetclass: The widgetclass, for snit::widgets, only # hasoptions: False, initially; set to true when first # option is defined. # localoptions: Names of local options. # delegatedoptions: Names of delegated options. # localmethods: Names of locally defined methods. # delegatesmethods: no if no delegated methods, yes otherwise. # hashierarchic : no if no hierarchic methods, yes otherwise. # components: Names of defined components. # typecomponents: Names of defined typecomponents. # typevars: Typevariable definitions and initializations. # varnames: Names of instance variables # typevarnames Names of type variables # hasconstructor False, initially; true when constructor is # defined. # resource-$opt The option's resource name # class-$opt The option's class # -default-$opt The option's default value # -validatemethod-$opt The option's validate method # -configuremethod-$opt The option's configure method # -cgetmethod-$opt The option's cget method. # -hastypeinfo The -hastypeinfo pragma # -hastypedestroy The -hastypedestroy pragma # -hastypemethods The -hastypemethods pragma # -hasinfo The -hasinfo pragma # -hasinstances The -hasinstances pragma # -simpledispatch The -simpledispatch pragma WHD: OBSOLETE # -canreplace The -canreplace pragma variable compile # This variable accumulates method dispatch information; it has # the same structure as the %TYPE%::Snit_methodInfo array, and is # used to initialize it. variable methodInfo # This variable accumulates typemethod dispatch information; it has # the same structure as the %TYPE%::Snit_typemethodInfo array, and is # used to initialize it. variable typemethodInfo # The following variable lists the reserved type definition statement # names, e.g., the names you can't use as macros. It's built at # compiler definition time using "info commands". variable reservedwords {} } #----------------------------------------------------------------------- # type compilation commands # # The type and widgettype commands use a slave interpreter to compile # the type definition. These are the procs # that are aliased into it. # Initialize the compiler proc ::snit::Comp.Init {} { variable compiler variable reservedwords if {$compiler eq ""} { # Create the compiler's interpreter set compiler [interp create] # Initialize the interpreter $compiler eval { # Load package information # TBD: see if this can be moved outside. # @mdgen NODEP: ::snit::__does_not_exist__ catch {package require ::snit::__does_not_exist__} # Protect some Tcl commands our type definitions # will shadow. rename proc _proc rename variable _variable } # Define compilation aliases. $compiler alias pragma ::snit::Comp.statement.pragma $compiler alias widgetclass ::snit::Comp.statement.widgetclass $compiler alias hulltype ::snit::Comp.statement.hulltype $compiler alias constructor ::snit::Comp.statement.constructor $compiler alias destructor ::snit::Comp.statement.destructor $compiler alias option ::snit::Comp.statement.option $compiler alias oncget ::snit::Comp.statement.oncget $compiler alias onconfigure ::snit::Comp.statement.onconfigure $compiler alias method ::snit::Comp.statement.method $compiler alias typemethod ::snit::Comp.statement.typemethod $compiler alias typeconstructor ::snit::Comp.statement.typeconstructor $compiler alias proc ::snit::Comp.statement.proc $compiler alias typevariable ::snit::Comp.statement.typevariable $compiler alias variable ::snit::Comp.statement.variable $compiler alias typecomponent ::snit::Comp.statement.typecomponent $compiler alias component ::snit::Comp.statement.component $compiler alias delegate ::snit::Comp.statement.delegate $compiler alias expose ::snit::Comp.statement.expose # Get the list of reserved words set reservedwords [$compiler eval {info commands}] } } # Compile a type definition, and return the results as a list of two # items: the fully-qualified type name, and a script that will define # the type when executed. # # which type, widget, or widgetadaptor # type the type name # body the type definition proc ::snit::Comp.Compile {which type body} { variable typeTemplate variable nominalTypeProc variable simpleTypeProc variable compile variable compiler variable methodInfo variable typemethodInfo # FIRST, qualify the name. if {![string match "::*" $type]} { # Get caller's namespace; # append :: if not global namespace. set ns [uplevel 2 [list namespace current]] if {"::" != $ns} { append ns "::" } set type "$ns$type" } # NEXT, create and initialize the compiler, if needed. Comp.Init # NEXT, initialize the class data array unset methodInfo array unset typemethodInfo array unset compile set compile(type) $type set compile(defs) {} set compile(which) $which set compile(hasoptions) no set compile(localoptions) {} set compile(instancevars) {} set compile(typevars) {} set compile(delegatedoptions) {} set compile(ivprocdec) {} set compile(tvprocdec) {} set compile(typeconstructor) {} set compile(widgetclass) {} set compile(hulltype) {} set compile(localmethods) {} set compile(delegatesmethods) no set compile(hashierarchic) no set compile(components) {} set compile(typecomponents) {} set compile(varnames) {} set compile(typevarnames) {} set compile(hasconstructor) no set compile(-hastypedestroy) yes set compile(-hastypeinfo) yes set compile(-hastypemethods) yes set compile(-hasinfo) yes set compile(-hasinstances) yes set compile(-canreplace) no set isWidget [string match widget* $which] set isWidgetAdaptor [string match widgetadaptor $which] # NEXT, Evaluate the type's definition in the class interpreter. $compiler eval $body # NEXT, Add the standard definitions append compile(defs) \ "\nset %TYPE%::Snit_info(isWidget) $isWidget\n" append compile(defs) \ "\nset %TYPE%::Snit_info(isWidgetAdaptor) $isWidgetAdaptor\n" # Indicate whether the type can create instances that replace # existing commands. append compile(defs) "\nset %TYPE%::Snit_info(canreplace) $compile(-canreplace)\n" # Check pragmas for conflict. if {!$compile(-hastypemethods) && !$compile(-hasinstances)} { error "$which $type has neither typemethods nor instances" } # If there are typemethods, define the standard typemethods and # the nominal type proc. Otherwise define the simple type proc. if {$compile(-hastypemethods)} { # Add the info typemethod unless the pragma forbids it. if {$compile(-hastypeinfo)} { Comp.statement.delegate typemethod info \ using {::snit::RT.typemethod.info %t} } # Add the destroy typemethod unless the pragma forbids it. if {$compile(-hastypedestroy)} { Comp.statement.delegate typemethod destroy \ using {::snit::RT.typemethod.destroy %t} } # Add the nominal type proc. append compile(defs) $nominalTypeProc } else { # Add the simple type proc. append compile(defs) $simpleTypeProc } # Add standard methods/typemethods that only make sense if the # type has instances. if {$compile(-hasinstances)} { # Add the info method unless the pragma forbids it. if {$compile(-hasinfo)} { Comp.statement.delegate method info \ using {::snit::RT.method.info %t %n %w %s} } # Add the option handling stuff if there are any options. if {$compile(hasoptions)} { Comp.statement.variable options Comp.statement.delegate method cget \ using {::snit::RT.method.cget %t %n %w %s} Comp.statement.delegate method configurelist \ using {::snit::RT.method.configurelist %t %n %w %s} Comp.statement.delegate method configure \ using {::snit::RT.method.configure %t %n %w %s} } # Add a default constructor, if they haven't already defined one. # If there are options, it will configure args; otherwise it # will do nothing. if {!$compile(hasconstructor)} { if {$compile(hasoptions)} { Comp.statement.constructor {args} { $self configurelist $args } } else { Comp.statement.constructor {} {} } } if {!$isWidget} { Comp.statement.delegate method destroy \ using {::snit::RT.method.destroy %t %n %w %s} Comp.statement.delegate typemethod create \ using {::snit::RT.type.typemethod.create %t} } else { Comp.statement.delegate typemethod create \ using {::snit::RT.widget.typemethod.create %t} } # Save the method info. append compile(defs) \ "\narray set %TYPE%::Snit_methodInfo [list [array get methodInfo]]\n" } else { append compile(defs) "\nset %TYPE%::Snit_info(hasinstances) 0\n" } # NEXT, compiling the type definition built up a set of information # about the type's locally defined options; add this information to # the compiled definition. Comp.SaveOptionInfo # NEXT, compiling the type definition built up a set of information # about the typemethods; save the typemethod info. append compile(defs) \ "\narray set %TYPE%::Snit_typemethodInfo [list [array get typemethodInfo]]\n" # NEXT, if this is a widget define the hull component if it isn't # already defined. if {$isWidget} { Comp.DefineComponent hull } # NEXT, substitute the compiled definition into the type template # to get the type definition script. set defscript [Expand $typeTemplate \ %COMPILEDDEFS% $compile(defs)] # NEXT, substitute the defined macros into the type definition script. # This is done as a separate step so that the compile(defs) can # contain the macros defined below. set defscript [Expand $defscript \ %TYPE% $type \ %IVARDECS% $compile(ivprocdec) \ %TVARDECS% $compile(tvprocdec) \ %TCONSTBODY% $compile(typeconstructor) \ %INSTANCEVARS% $compile(instancevars) \ %TYPEVARS% $compile(typevars) \ ] array unset compile return [list $type $defscript] } # Information about locally-defined options is accumulated during # compilation, but not added to the compiled definition--the option # statement can appear multiple times, so it's easier this way. # This proc fills in Snit_optionInfo with the accumulated information. # # It also computes the option's resource and class names if needed. # # Note that the information for delegated options was put in # Snit_optionInfo during compilation. proc ::snit::Comp.SaveOptionInfo {} { variable compile foreach option $compile(localoptions) { if {$compile(resource-$option) eq ""} { set compile(resource-$option) [string range $option 1 end] } if {$compile(class-$option) eq ""} { set compile(class-$option) [Capitalize $compile(resource-$option)] } # NOTE: Don't verify that the validate, configure, and cget # values name real methods; the methods might be defined outside # the typedefinition using snit::method. Mappend compile(defs) { # Option %OPTION% lappend %TYPE%::Snit_optionInfo(local) %OPTION% set %TYPE%::Snit_optionInfo(islocal-%OPTION%) 1 set %TYPE%::Snit_optionInfo(resource-%OPTION%) %RESOURCE% set %TYPE%::Snit_optionInfo(class-%OPTION%) %CLASS% set %TYPE%::Snit_optionInfo(default-%OPTION%) %DEFAULT% set %TYPE%::Snit_optionInfo(validate-%OPTION%) %VALIDATE% set %TYPE%::Snit_optionInfo(configure-%OPTION%) %CONFIGURE% set %TYPE%::Snit_optionInfo(cget-%OPTION%) %CGET% set %TYPE%::Snit_optionInfo(readonly-%OPTION%) %READONLY% set %TYPE%::Snit_optionInfo(typespec-%OPTION%) %TYPESPEC% } %OPTION% $option \ %RESOURCE% $compile(resource-$option) \ %CLASS% $compile(class-$option) \ %DEFAULT% [list $compile(-default-$option)] \ %VALIDATE% [list $compile(-validatemethod-$option)] \ %CONFIGURE% [list $compile(-configuremethod-$option)] \ %CGET% [list $compile(-cgetmethod-$option)] \ %READONLY% $compile(-readonly-$option) \ %TYPESPEC% [list $compile(-type-$option)] } } # Evaluates a compiled type definition, thus making the type available. proc ::snit::Comp.Define {compResult} { # The compilation result is a list containing the fully qualified # type name and a script to evaluate to define the type. set type [lindex $compResult 0] set defscript [lindex $compResult 1] # Execute the type definition script. # Consider using namespace eval %TYPE%. See if it's faster. if {[catch {eval $defscript} result]} { namespace delete $type catch {rename $type ""} error $result } return $type } # Sets pragma options which control how the type is defined. proc ::snit::Comp.statement.pragma {args} { variable compile set errRoot "Error in \"pragma...\"" foreach {opt val} $args { switch -exact -- $opt { -hastypeinfo - -hastypedestroy - -hastypemethods - -hasinstances - -simpledispatch - -hasinfo - -canreplace { if {![string is boolean -strict $val]} { error "$errRoot, \"$opt\" requires a boolean value" } set compile($opt) $val } default { error "$errRoot, unknown pragma" } } } } # Defines a widget's option class name. # This statement is only available for snit::widgets, # not for snit::types or snit::widgetadaptors. proc ::snit::Comp.statement.widgetclass {name} { variable compile # First, widgetclass can only be set for true widgets if {"widget" != $compile(which)} { error "widgetclass cannot be set for snit::$compile(which)s" } # Next, validate the option name. We'll require that it begin # with an uppercase letter. set initial [string index $name 0] if {![string is upper $initial]} { error "widgetclass \"$name\" does not begin with an uppercase letter" } if {"" != $compile(widgetclass)} { error "too many widgetclass statements" } # Next, save it. Mappend compile(defs) { set %TYPE%::Snit_info(widgetclass) %WIDGETCLASS% } %WIDGETCLASS% [list $name] set compile(widgetclass) $name } # Defines a widget's hull type. # This statement is only available for snit::widgets, # not for snit::types or snit::widgetadaptors. proc ::snit::Comp.statement.hulltype {name} { variable compile variable hulltypes # First, hulltype can only be set for true widgets if {"widget" != $compile(which)} { error "hulltype cannot be set for snit::$compile(which)s" } # Next, it must be one of the valid hulltypes (frame, toplevel, ...) if {[lsearch -exact $hulltypes [string trimleft $name :]] == -1} { error "invalid hulltype \"$name\", should be one of\ [join $hulltypes {, }]" } if {"" != $compile(hulltype)} { error "too many hulltype statements" } # Next, save it. Mappend compile(defs) { set %TYPE%::Snit_info(hulltype) %HULLTYPE% } %HULLTYPE% $name set compile(hulltype) $name } # Defines a constructor. proc ::snit::Comp.statement.constructor {arglist body} { variable compile CheckArgs "constructor" $arglist # Next, add a magic reference to self. set arglist [concat type selfns win self $arglist] # Next, add variable declarations to body: set body "%TVARDECS%\n%IVARDECS%\n$body" set compile(hasconstructor) yes append compile(defs) "proc %TYPE%::Snit_constructor [list $arglist] [list $body]\n" } # Defines a destructor. proc ::snit::Comp.statement.destructor {body} { variable compile # Next, add variable declarations to body: set body "%TVARDECS%\n%IVARDECS%\n$body" append compile(defs) "proc %TYPE%::Snit_destructor {type selfns win self} [list $body]\n\n" } # Defines a type option. The option value can be a triple, specifying # the option's -name, resource name, and class name. proc ::snit::Comp.statement.option {optionDef args} { variable compile # First, get the three option names. set option [lindex $optionDef 0] set resourceName [lindex $optionDef 1] set className [lindex $optionDef 2] set errRoot "Error in \"option [list $optionDef]...\"" # Next, validate the option name. if {![Comp.OptionNameIsValid $option]} { error "$errRoot, badly named option \"$option\"" } if {$option in $compile(delegatedoptions)} { error "$errRoot, cannot define \"$option\" locally, it has been delegated" } if {!($option in $compile(localoptions))} { # Remember that we've seen this one. set compile(hasoptions) yes lappend compile(localoptions) $option # Initialize compilation info for this option. set compile(resource-$option) "" set compile(class-$option) "" set compile(-default-$option) "" set compile(-validatemethod-$option) "" set compile(-configuremethod-$option) "" set compile(-cgetmethod-$option) "" set compile(-readonly-$option) 0 set compile(-type-$option) "" } # NEXT, see if we have a resource name. If so, make sure it # isn't being redefined differently. if {$resourceName ne ""} { if {$compile(resource-$option) eq ""} { # If it's undefined, just save the value. set compile(resource-$option) $resourceName } elseif {$resourceName ne $compile(resource-$option)} { # It's been redefined differently. error "$errRoot, resource name redefined from \"$compile(resource-$option)\" to \"$resourceName\"" } } # NEXT, see if we have a class name. If so, make sure it # isn't being redefined differently. if {$className ne ""} { if {$compile(class-$option) eq ""} { # If it's undefined, just save the value. set compile(class-$option) $className } elseif {$className ne $compile(class-$option)} { # It's been redefined differently. error "$errRoot, class name redefined from \"$compile(class-$option)\" to \"$className\"" } } # NEXT, handle the args; it's not an error to redefine these. if {[llength $args] == 1} { set compile(-default-$option) [lindex $args 0] } else { foreach {optopt val} $args { switch -exact -- $optopt { -default - -validatemethod - -configuremethod - -cgetmethod { set compile($optopt-$option) $val } -type { set compile($optopt-$option) $val if {[llength $val] == 1} { # The type spec *is* the validation object append compile(defs) \ "\nset %TYPE%::Snit_optionInfo(typeobj-$option) [list $val]\n" } else { # Compilation the creation of the validation object set cmd [linsert $val 1 %TYPE%::Snit_TypeObj_%AUTO%] append compile(defs) \ "\nset %TYPE%::Snit_optionInfo(typeobj-$option) \[$cmd\]\n" } } -readonly { if {![string is boolean -strict $val]} { error "$errRoot, -readonly requires a boolean, got \"$val\"" } set compile($optopt-$option) $val } default { error "$errRoot, unknown option definition option \"$optopt\"" } } } } } # 1 if the option name is valid, 0 otherwise. proc ::snit::Comp.OptionNameIsValid {option} { if {![string match {-*} $option] || [string match {*[A-Z ]*} $option]} { return 0 } return 1 } # Defines an option's cget handler proc ::snit::Comp.statement.oncget {option body} { variable compile set errRoot "Error in \"oncget $option...\"" if {[lsearch -exact $compile(delegatedoptions) $option] != -1} { return -code error "$errRoot, option \"$option\" is delegated" } if {[lsearch -exact $compile(localoptions) $option] == -1} { return -code error "$errRoot, option \"$option\" unknown" } Comp.statement.method _cget$option {_option} $body Comp.statement.option $option -cgetmethod _cget$option } # Defines an option's configure handler. proc ::snit::Comp.statement.onconfigure {option arglist body} { variable compile if {[lsearch -exact $compile(delegatedoptions) $option] != -1} { return -code error "onconfigure $option: option \"$option\" is delegated" } if {[lsearch -exact $compile(localoptions) $option] == -1} { return -code error "onconfigure $option: option \"$option\" unknown" } if {[llength $arglist] != 1} { error \ "onconfigure $option handler should have one argument, got \"$arglist\"" } CheckArgs "onconfigure $option" $arglist # Next, add a magic reference to the option name set arglist [concat _option $arglist] Comp.statement.method _configure$option $arglist $body Comp.statement.option $option -configuremethod _configure$option } # Defines an instance method. proc ::snit::Comp.statement.method {method arglist body} { variable compile variable methodInfo # FIRST, check the method name against previously defined # methods. Comp.CheckMethodName $method 0 ::snit::methodInfo \ "Error in \"method [list $method]...\"" if {[llength $method] > 1} { set compile(hashierarchic) yes } # Remeber this method lappend compile(localmethods) $method CheckArgs "method [list $method]" $arglist # Next, add magic references to type and self. set arglist [concat type selfns win self $arglist] # Next, add variable declarations to body: set body "%TVARDECS%\n%IVARDECS%\n# END snit method prolog\n$body" # Next, save the definition script. if {[llength $method] == 1} { set methodInfo($method) {0 "%t::Snit_method%m %t %n %w %s" ""} Mappend compile(defs) { proc %TYPE%::Snit_method%METHOD% %ARGLIST% %BODY% } %METHOD% $method %ARGLIST% [list $arglist] %BODY% [list $body] } else { set methodInfo($method) {0 "%t::Snit_hmethod%j %t %n %w %s" ""} Mappend compile(defs) { proc %TYPE%::Snit_hmethod%JMETHOD% %ARGLIST% %BODY% } %JMETHOD% [join $method _] %ARGLIST% [list $arglist] \ %BODY% [list $body] } } # Check for name collisions; save prefix information. # # method The name of the method or typemethod. # delFlag 1 if delegated, 0 otherwise. # infoVar The fully qualified name of the array containing # information about the defined methods. # errRoot The root string for any error messages. proc ::snit::Comp.CheckMethodName {method delFlag infoVar errRoot} { upvar $infoVar methodInfo # FIRST, make sure the method name is a valid Tcl list. if {[catch {lindex $method 0}]} { error "$errRoot, the name \"$method\" must have list syntax." } # NEXT, check whether we can define it. if {![catch {set methodInfo($method)} data]} { # We can't redefine methods with submethods. if {[lindex $data 0] == 1} { error "$errRoot, \"$method\" has submethods." } # You can't delegate a method that's defined locally, # and you can't define a method locally if it's been delegated. if {$delFlag && [lindex $data 2] eq ""} { error "$errRoot, \"$method\" has been defined locally." } elseif {!$delFlag && [lindex $data 2] ne ""} { error "$errRoot, \"$method\" has been delegated" } } # Handle hierarchical case. if {[llength $method] > 1} { set prefix {} set tokens $method while {[llength $tokens] > 1} { lappend prefix [lindex $tokens 0] set tokens [lrange $tokens 1 end] if {![catch {set methodInfo($prefix)} result]} { # Prefix is known. If it's not a prefix, throw an # error. if {[lindex $result 0] == 0} { error "$errRoot, \"$prefix\" has no submethods." } } set methodInfo($prefix) [list 1] } } } # Defines a typemethod method. proc ::snit::Comp.statement.typemethod {method arglist body} { variable compile variable typemethodInfo # FIRST, check the typemethod name against previously defined # typemethods. Comp.CheckMethodName $method 0 ::snit::typemethodInfo \ "Error in \"typemethod [list $method]...\"" CheckArgs "typemethod $method" $arglist # First, add magic reference to type. set arglist [concat type $arglist] # Next, add typevariable declarations to body: set body "%TVARDECS%\n# END snit method prolog\n$body" # Next, save the definition script if {[llength $method] == 1} { set typemethodInfo($method) {0 "%t::Snit_typemethod%m %t" ""} Mappend compile(defs) { proc %TYPE%::Snit_typemethod%METHOD% %ARGLIST% %BODY% } %METHOD% $method %ARGLIST% [list $arglist] %BODY% [list $body] } else { set typemethodInfo($method) {0 "%t::Snit_htypemethod%j %t" ""} Mappend compile(defs) { proc %TYPE%::Snit_htypemethod%JMETHOD% %ARGLIST% %BODY% } %JMETHOD% [join $method _] \ %ARGLIST% [list $arglist] %BODY% [list $body] } } # Defines a type constructor. proc ::snit::Comp.statement.typeconstructor {body} { variable compile if {"" != $compile(typeconstructor)} { error "too many typeconstructors" } set compile(typeconstructor) $body } # Defines a static proc in the type's namespace. proc ::snit::Comp.statement.proc {proc arglist body} { variable compile # If "ns" is defined, the proc can see instance variables. if {[lsearch -exact $arglist selfns] != -1} { # Next, add instance variable declarations to body: set body "%IVARDECS%\n$body" } # The proc can always see typevariables. set body "%TVARDECS%\n$body" append compile(defs) " # Proc $proc proc [list %TYPE%::$proc $arglist $body] " } # Defines a static variable in the type's namespace. proc ::snit::Comp.statement.typevariable {name args} { variable compile set errRoot "Error in \"typevariable $name...\"" set len [llength $args] if {$len > 2 || ($len == 2 && [lindex $args 0] ne "-array")} { error "$errRoot, too many initializers" } if {[lsearch -exact $compile(varnames) $name] != -1} { error "$errRoot, \"$name\" is already an instance variable" } lappend compile(typevarnames) $name if {$len == 1} { append compile(typevars) \ "\n\t [list ::variable $name [lindex $args 0]]" } elseif {$len == 2} { append compile(typevars) \ "\n\t [list ::variable $name]" append compile(typevars) \ "\n\t [list array set $name [lindex $args 1]]" } else { append compile(typevars) \ "\n\t [list ::variable $name]" } if {$compile(tvprocdec) eq ""} { set compile(tvprocdec) "\n\t" append compile(tvprocdec) "namespace upvar [list $compile(type)]" } append compile(tvprocdec) " [list $name $name]" } # Defines an instance variable; the definition will go in the # type's create typemethod. proc ::snit::Comp.statement.variable {name args} { variable compile set errRoot "Error in \"variable $name...\"" set len [llength $args] if {$len > 2 || ($len == 2 && [lindex $args 0] ne "-array")} { error "$errRoot, too many initializers" } if {[lsearch -exact $compile(typevarnames) $name] != -1} { error "$errRoot, \"$name\" is already a typevariable" } lappend compile(varnames) $name # Add a ::variable to instancevars, so that ::variable is used # at least once; ::variable makes the variable visible to # [info vars] even if no value is assigned. append compile(instancevars) "\n" Mappend compile(instancevars) {::variable ${selfns}::%N} %N $name if {$len == 1} { append compile(instancevars) \ "\nset $name [list [lindex $args 0]]\n" } elseif {$len == 2} { append compile(instancevars) \ "\narray set $name [list [lindex $args 1]]\n" } if {$compile(ivprocdec) eq ""} { set compile(ivprocdec) "\n\t" append compile(ivprocdec) {namespace upvar $selfns} } append compile(ivprocdec) " [list $name $name]" } # Defines a typecomponent, and handles component options. # # component The logical name of the delegate # args options. proc ::snit::Comp.statement.typecomponent {component args} { variable compile set errRoot "Error in \"typecomponent $component...\"" # FIRST, define the component Comp.DefineTypecomponent $component $errRoot # NEXT, handle the options. set publicMethod "" set inheritFlag 0 foreach {opt val} $args { switch -exact -- $opt { -public { set publicMethod $val } -inherit { set inheritFlag $val if {![string is boolean $inheritFlag]} { error "typecomponent $component -inherit: expected boolean value, got \"$val\"" } } default { error "typecomponent $component: Invalid option \"$opt\"" } } } # NEXT, if -public specified, define the method. if {$publicMethod ne ""} { Comp.statement.delegate typemethod [list $publicMethod *] to $component } # NEXT, if "-inherit 1" is specified, delegate typemethod * to # this component. if {$inheritFlag} { Comp.statement.delegate typemethod "*" to $component } } # Defines a name to be a typecomponent # # The name becomes a typevariable; in addition, it gets a # write trace so that when it is set, all of the component mechanisms # get updated. # # component The component name proc ::snit::Comp.DefineTypecomponent {component {errRoot "Error"}} { variable compile if {[lsearch -exact $compile(varnames) $component] != -1} { error "$errRoot, \"$component\" is already an instance variable" } if {[lsearch -exact $compile(typecomponents) $component] == -1} { # Remember we've done this. lappend compile(typecomponents) $component # Make it a type variable with no initial value Comp.statement.typevariable $component "" # Add a write trace to do the component thing. Mappend compile(typevars) { trace add variable %COMP% write \ [list ::snit::RT.TypecomponentTrace [list %TYPE%] %COMP%] } %TYPE% $compile(type) %COMP% $component } } # Defines a component, and handles component options. # # component The logical name of the delegate # args options. # # TBD: Ideally, it should be possible to call this statement multiple # times, possibly changing the option values. To do that, I'd need # to cache the option values and not act on them until *after* I'd # read the entire type definition. proc ::snit::Comp.statement.component {component args} { variable compile set errRoot "Error in \"component $component...\"" # FIRST, define the component Comp.DefineComponent $component $errRoot # NEXT, handle the options. set publicMethod "" set inheritFlag 0 foreach {opt val} $args { switch -exact -- $opt { -public { set publicMethod $val } -inherit { set inheritFlag $val if {![string is boolean $inheritFlag]} { error "component $component -inherit: expected boolean value, got \"$val\"" } } default { error "component $component: Invalid option \"$opt\"" } } } # NEXT, if -public specified, define the method. if {$publicMethod ne ""} { Comp.statement.delegate method [list $publicMethod *] to $component } # NEXT, if -inherit is specified, delegate method/option * to # this component. if {$inheritFlag} { Comp.statement.delegate method "*" to $component Comp.statement.delegate option "*" to $component } } # Defines a name to be a component # # The name becomes an instance variable; in addition, it gets a # write trace so that when it is set, all of the component mechanisms # get updated. # # component The component name proc ::snit::Comp.DefineComponent {component {errRoot "Error"}} { variable compile if {[lsearch -exact $compile(typevarnames) $component] != -1} { error "$errRoot, \"$component\" is already a typevariable" } if {[lsearch -exact $compile(components) $component] == -1} { # Remember we've done this. lappend compile(components) $component # Make it an instance variable with no initial value Comp.statement.variable $component "" # Add a write trace to do the component thing. Mappend compile(instancevars) { trace add variable ${selfns}::%COMP% write \ [list ::snit::RT.ComponentTrace [list %TYPE%] $selfns %COMP%] } %TYPE% $compile(type) %COMP% $component } } # Creates a delegated method, typemethod, or option. proc ::snit::Comp.statement.delegate {what name args} { # FIRST, dispatch to correct handler. switch $what { typemethod { Comp.DelegatedTypemethod $name $args } method { Comp.DelegatedMethod $name $args } option { Comp.DelegatedOption $name $args } default { error "Error in \"delegate $what $name...\", \"$what\"?" } } if {([llength $args] % 2) != 0} { error "Error in \"delegate $what $name...\", invalid syntax" } } # Creates a delegated typemethod delegating it to a particular # typecomponent or an arbitrary command. # # method The name of the method # arglist Delegation options proc ::snit::Comp.DelegatedTypemethod {method arglist} { variable compile variable typemethodInfo set errRoot "Error in \"delegate typemethod [list $method]...\"" # Next, parse the delegation options. set component "" set target "" set exceptions {} set pattern "" set methodTail [lindex $method end] foreach {opt value} $arglist { switch -exact $opt { to { set component $value } as { set target $value } except { set exceptions $value } using { set pattern $value } default { error "$errRoot, unknown delegation option \"$opt\"" } } } if {$component eq "" && $pattern eq ""} { error "$errRoot, missing \"to\"" } if {$methodTail eq "*" && $target ne ""} { error "$errRoot, cannot specify \"as\" with \"*\"" } if {$methodTail ne "*" && $exceptions ne ""} { error "$errRoot, can only specify \"except\" with \"*\"" } if {$pattern ne "" && $target ne ""} { error "$errRoot, cannot specify both \"as\" and \"using\"" } foreach token [lrange $method 1 end-1] { if {$token eq "*"} { error "$errRoot, \"*\" must be the last token." } } # NEXT, define the component if {$component ne ""} { Comp.DefineTypecomponent $component $errRoot } # NEXT, define the pattern. if {$pattern eq ""} { if {$methodTail eq "*"} { set pattern "%c %m" } elseif {$target ne ""} { set pattern "%c $target" } else { set pattern "%c %m" } } # Make sure the pattern is a valid list. if {[catch {lindex $pattern 0} result]} { error "$errRoot, the using pattern, \"$pattern\", is not a valid list" } # NEXT, check the method name against previously defined # methods. Comp.CheckMethodName $method 1 ::snit::typemethodInfo $errRoot set typemethodInfo($method) [list 0 $pattern $component] if {[string equal $methodTail "*"]} { Mappend compile(defs) { set %TYPE%::Snit_info(excepttypemethods) %EXCEPT% } %EXCEPT% [list $exceptions] } } # Creates a delegated method delegating it to a particular # component or command. # # method The name of the method # arglist Delegation options. proc ::snit::Comp.DelegatedMethod {method arglist} { variable compile variable methodInfo set errRoot "Error in \"delegate method [list $method]...\"" # Next, parse the delegation options. set component "" set target "" set exceptions {} set pattern "" set methodTail [lindex $method end] foreach {opt value} $arglist { switch -exact $opt { to { set component $value } as { set target $value } except { set exceptions $value } using { set pattern $value } default { error "$errRoot, unknown delegation option \"$opt\"" } } } if {$component eq "" && $pattern eq ""} { error "$errRoot, missing \"to\"" } if {$methodTail eq "*" && $target ne ""} { error "$errRoot, cannot specify \"as\" with \"*\"" } if {$methodTail ne "*" && $exceptions ne ""} { error "$errRoot, can only specify \"except\" with \"*\"" } if {$pattern ne "" && $target ne ""} { error "$errRoot, cannot specify both \"as\" and \"using\"" } foreach token [lrange $method 1 end-1] { if {$token eq "*"} { error "$errRoot, \"*\" must be the last token." } } # NEXT, we delegate some methods set compile(delegatesmethods) yes # NEXT, define the component. Allow typecomponents. if {$component ne ""} { if {[lsearch -exact $compile(typecomponents) $component] == -1} { Comp.DefineComponent $component $errRoot } } # NEXT, define the pattern. if {$pattern eq ""} { if {$methodTail eq "*"} { set pattern "%c %m" } elseif {$target ne ""} { set pattern "%c $target" } else { set pattern "%c %m" } } # Make sure the pattern is a valid list. if {[catch {lindex $pattern 0} result]} { error "$errRoot, the using pattern, \"$pattern\", is not a valid list" } # NEXT, check the method name against previously defined # methods. Comp.CheckMethodName $method 1 ::snit::methodInfo $errRoot # NEXT, save the method info. set methodInfo($method) [list 0 $pattern $component] if {[string equal $methodTail "*"]} { Mappend compile(defs) { set %TYPE%::Snit_info(exceptmethods) %EXCEPT% } %EXCEPT% [list $exceptions] } } # Creates a delegated option, delegating it to a particular # component and, optionally, to a particular option of that # component. # # optionDef The option definition # args definition arguments. proc ::snit::Comp.DelegatedOption {optionDef arglist} { variable compile # First, get the three option names. set option [lindex $optionDef 0] set resourceName [lindex $optionDef 1] set className [lindex $optionDef 2] set errRoot "Error in \"delegate option [list $optionDef]...\"" # Next, parse the delegation options. set component "" set target "" set exceptions {} foreach {opt value} $arglist { switch -exact $opt { to { set component $value } as { set target $value } except { set exceptions $value } default { error "$errRoot, unknown delegation option \"$opt\"" } } } if {$component eq ""} { error "$errRoot, missing \"to\"" } if {$option eq "*" && $target ne ""} { error "$errRoot, cannot specify \"as\" with \"delegate option *\"" } if {$option ne "*" && $exceptions ne ""} { error "$errRoot, can only specify \"except\" with \"delegate option *\"" } # Next, validate the option name if {"*" != $option} { if {![Comp.OptionNameIsValid $option]} { error "$errRoot, badly named option \"$option\"" } } if {$option in $compile(localoptions)} { error "$errRoot, \"$option\" has been defined locally" } if {$option in $compile(delegatedoptions)} { error "$errRoot, \"$option\" is multiply delegated" } # NEXT, define the component Comp.DefineComponent $component $errRoot # Next, define the target option, if not specified. if {![string equal $option "*"] && [string equal $target ""]} { set target $option } # NEXT, save the delegation data. set compile(hasoptions) yes if {![string equal $option "*"]} { lappend compile(delegatedoptions) $option # Next, compute the resource and class names, if they aren't # already defined. if {"" == $resourceName} { set resourceName [string range $option 1 end] } if {"" == $className} { set className [Capitalize $resourceName] } Mappend compile(defs) { set %TYPE%::Snit_optionInfo(islocal-%OPTION%) 0 set %TYPE%::Snit_optionInfo(resource-%OPTION%) %RES% set %TYPE%::Snit_optionInfo(class-%OPTION%) %CLASS% lappend %TYPE%::Snit_optionInfo(delegated) %OPTION% set %TYPE%::Snit_optionInfo(target-%OPTION%) [list %COMP% %TARGET%] lappend %TYPE%::Snit_optionInfo(delegated-%COMP%) %OPTION% } %OPTION% $option \ %COMP% $component \ %TARGET% $target \ %RES% $resourceName \ %CLASS% $className } else { Mappend compile(defs) { set %TYPE%::Snit_optionInfo(starcomp) %COMP% set %TYPE%::Snit_optionInfo(except) %EXCEPT% } %COMP% $component %EXCEPT% [list $exceptions] } } # Exposes a component, effectively making the component's command an # instance method. # # component The logical name of the delegate # "as" sugar; if not "", must be "as" # methodname The desired method name for the component's command, or "" proc ::snit::Comp.statement.expose {component {"as" ""} {methodname ""}} { variable compile # FIRST, define the component Comp.DefineComponent $component # NEXT, define the method just as though it were in the type # definition. if {[string equal $methodname ""]} { set methodname $component } Comp.statement.method $methodname args [Expand { if {[llength $args] == 0} { return $%COMPONENT% } if {[string equal $%COMPONENT% ""]} { error "undefined component \"%COMPONENT%\"" } set cmd [linsert $args 0 $%COMPONENT%] return [uplevel 1 $cmd] } %COMPONENT% $component] } #----------------------------------------------------------------------- # Public commands # Compile a type definition, and return the results as a list of two # items: the fully-qualified type name, and a script that will define # the type when executed. # # which type, widget, or widgetadaptor # type the type name # body the type definition proc ::snit::compile {which type body} { return [Comp.Compile $which $type $body] } proc ::snit::type {type body} { return [Comp.Define [Comp.Compile type $type $body]] } proc ::snit::widget {type body} { return [Comp.Define [Comp.Compile widget $type $body]] } proc ::snit::widgetadaptor {type body} { return [Comp.Define [Comp.Compile widgetadaptor $type $body]] } proc ::snit::typemethod {type method arglist body} { # Make sure the type exists. if {![info exists ${type}::Snit_info]} { error "no such type: \"$type\"" } upvar ${type}::Snit_info Snit_info upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo # FIRST, check the typemethod name against previously defined # typemethods. Comp.CheckMethodName $method 0 ${type}::Snit_typemethodInfo \ "Cannot define \"$method\"" # NEXT, check the arguments CheckArgs "snit::typemethod $type $method" $arglist # Next, add magic reference to type. set arglist [concat type $arglist] # Next, add typevariable declarations to body: set body "$Snit_info(tvardecs)\n$body" # Next, define it. if {[llength $method] == 1} { set Snit_typemethodInfo($method) {0 "%t::Snit_typemethod%m %t" ""} uplevel 1 [list proc ${type}::Snit_typemethod$method $arglist $body] } else { set Snit_typemethodInfo($method) {0 "%t::Snit_htypemethod%j %t" ""} set suffix [join $method _] uplevel 1 [list proc ${type}::Snit_htypemethod$suffix $arglist $body] } } proc ::snit::method {type method arglist body} { # Make sure the type exists. if {![info exists ${type}::Snit_info]} { error "no such type: \"$type\"" } upvar ${type}::Snit_methodInfo Snit_methodInfo upvar ${type}::Snit_info Snit_info # FIRST, check the method name against previously defined # methods. Comp.CheckMethodName $method 0 ${type}::Snit_methodInfo \ "Cannot define \"$method\"" # NEXT, check the arguments CheckArgs "snit::method $type $method" $arglist # Next, add magic references to type and self. set arglist [concat type selfns win self $arglist] # Next, add variable declarations to body: set body "$Snit_info(tvardecs)\n$Snit_info(ivardecs)\n$body" # Next, define it. if {[llength $method] == 1} { set Snit_methodInfo($method) {0 "%t::Snit_method%m %t %n %w %s" ""} uplevel 1 [list proc ${type}::Snit_method$method $arglist $body] } else { set Snit_methodInfo($method) {0 "%t::Snit_hmethod%j %t %n %w %s" ""} set suffix [join $method _] uplevel 1 [list proc ${type}::Snit_hmethod$suffix $arglist $body] } } # Defines a proc within the compiler; this proc can call other # type definition statements, and thus can be used for meta-programming. proc ::snit::macro {name arglist body} { variable compiler variable reservedwords # FIRST, make sure the compiler is defined. Comp.Init # NEXT, check the macro name against the reserved words if {[lsearch -exact $reservedwords $name] != -1} { error "invalid macro name \"$name\"" } # NEXT, see if the name has a namespace; if it does, define the # namespace. set ns [namespace qualifiers $name] if {$ns ne ""} { $compiler eval "namespace eval $ns {}" } # NEXT, define the macro $compiler eval [list _proc $name $arglist $body] } #----------------------------------------------------------------------- # Utility Functions # # These are utility functions used while compiling Snit types. # Builds a template from a tagged list of text blocks, then substitutes # all symbols in the mapTable, returning the expanded template. proc ::snit::Expand {template args} { return [string map $args $template] } # Expands a template and appends it to a variable. proc ::snit::Mappend {varname template args} { upvar $varname myvar append myvar [string map $args $template] } # Checks argument list against reserved args proc ::snit::CheckArgs {which arglist} { variable reservedArgs foreach name $reservedArgs { if {$name in $arglist} { error "$which's arglist may not contain \"$name\" explicitly" } } } # Capitalizes the first letter of a string. proc ::snit::Capitalize {text} { return [string toupper $text 0] } #======================================================================= # Snit Runtime Library # # These are procs used by Snit types and widgets at runtime. #----------------------------------------------------------------------- # Object Creation # Creates a new instance of the snit::type given its name and the args. # # type The snit::type # name The instance name # args Args to pass to the constructor proc ::snit::RT.type.typemethod.create {type name args} { variable ${type}::Snit_info variable ${type}::Snit_optionInfo # FIRST, qualify the name. if {![string match "::*" $name]} { # Get caller's namespace; # append :: if not global namespace. set ns [uplevel 1 [list namespace current]] if {"::" != $ns} { append ns "::" } set name "$ns$name" } # NEXT, if %AUTO% appears in the name, generate a unique # command name. Otherwise, ensure that the name isn't in use. if {[string match "*%AUTO%*" $name]} { set name [::snit::RT.UniqueName Snit_info(counter) $type $name] } elseif {!$Snit_info(canreplace) && [llength [info commands $name]]} { error "command \"$name\" already exists" } # NEXT, create the instance's namespace. set selfns \ [::snit::RT.UniqueInstanceNamespace Snit_info(counter) $type] namespace eval $selfns {} # NEXT, install the dispatcher RT.MakeInstanceCommand $type $selfns $name # Initialize the options to their defaults. namespace upvar ${selfns} options options foreach opt $Snit_optionInfo(local) { set options($opt) $Snit_optionInfo(default-$opt) } # Initialize the instance vars to their defaults. # selfns must be defined, as it is used implicitly. ${type}::Snit_instanceVars $selfns # Execute the type's constructor. set errcode [catch { RT.ConstructInstance $type $selfns $name $args } result] if {$errcode} { global errorInfo global errorCode set theInfo $errorInfo set theCode $errorCode ::snit::RT.DestroyObject $type $selfns $name error "Error in constructor: $result" $theInfo $theCode } # NEXT, return the object's name. return $name } # Creates a new instance of the snit::widget or snit::widgetadaptor # given its name and the args. # # type The snit::widget or snit::widgetadaptor # name The instance name # args Args to pass to the constructor proc ::snit::RT.widget.typemethod.create {type name args} { variable ${type}::Snit_info variable ${type}::Snit_optionInfo # FIRST, if %AUTO% appears in the name, generate a unique # command name. if {[string match "*%AUTO%*" $name]} { set name [::snit::RT.UniqueName Snit_info(counter) $type $name] } # NEXT, create the instance's namespace. set selfns \ [::snit::RT.UniqueInstanceNamespace Snit_info(counter) $type] namespace eval $selfns { } # NEXT, Initialize the widget's own options to their defaults. namespace upvar $selfns options options foreach opt $Snit_optionInfo(local) { set options($opt) $Snit_optionInfo(default-$opt) } # Initialize the instance vars to their defaults. ${type}::Snit_instanceVars $selfns # NEXT, if this is a normal widget (not a widget adaptor) then create a # frame as its hull. We set the frame's -class to the user's widgetclass, # or, if none, search for -class in the args list, otherwise default to # the basename of the $type with an initial upper case letter. if {!$Snit_info(isWidgetAdaptor)} { # FIRST, determine the class name set wclass $Snit_info(widgetclass) if {$Snit_info(widgetclass) eq ""} { set idx [lsearch -exact $args -class] if {$idx >= 0 && ($idx%2 == 0)} { # -class exists and is in the -option position set wclass [lindex $args [expr {$idx+1}]] set args [lreplace $args $idx [expr {$idx+1}]] } else { set wclass [::snit::Capitalize [namespace tail $type]] } } # NEXT, create the widget set self $name package require Tk ${type}::installhull using $Snit_info(hulltype) -class $wclass # NEXT, let's query the option database for our # widget, now that we know that it exists. foreach opt $Snit_optionInfo(local) { set dbval [RT.OptionDbGet $type $name $opt] if {"" != $dbval} { set options($opt) $dbval } } } # Execute the type's constructor, and verify that it # has a hull. set errcode [catch { RT.ConstructInstance $type $selfns $name $args ::snit::RT.Component $type $selfns hull # Prepare to call the object's destructor when the # event is received. Use a Snit-specific bindtag # so that the widget name's tag is unencumbered. bind Snit$type$name [::snit::Expand { ::snit::RT.DestroyObject %TYPE% %NS% %W } %TYPE% $type %NS% $selfns] # Insert the bindtag into the list of bindtags right # after the widget name. set taglist [bindtags $name] set ndx [lsearch -exact $taglist $name] incr ndx bindtags $name [linsert $taglist $ndx Snit$type$name] } result] if {$errcode} { global errorInfo global errorCode set theInfo $errorInfo set theCode $errorCode ::snit::RT.DestroyObject $type $selfns $name error "Error in constructor: $result" $theInfo $theCode } # NEXT, return the object's name. return $name } # RT.MakeInstanceCommand type selfns instance # # type The object type # selfns The instance namespace # instance The instance name # # Creates the instance proc. proc ::snit::RT.MakeInstanceCommand {type selfns instance} { variable ${type}::Snit_info # FIRST, remember the instance name. The Snit_instance variable # allows the instance to figure out its current name given the # instance namespace. namespace upvar $selfns Snit_instance Snit_instance set Snit_instance $instance # NEXT, qualify the proc name if it's a widget. if {$Snit_info(isWidget)} { set procname ::$instance } else { set procname $instance } # NEXT, install the new proc # WHD: Snit 2.0 code set unknownCmd [list ::snit::RT.UnknownMethod $type $selfns $instance ""] set createCmd [list namespace ensemble create \ -command $procname \ -unknown $unknownCmd \ -prefixes 0] namespace eval $selfns $createCmd # NEXT, add the trace. trace add command $procname {rename delete} \ [list ::snit::RT.InstanceTrace $type $selfns $instance] } # This proc is called when the instance command is renamed. # If op is delete, then new will always be "", so op is redundant. # # type The fully-qualified type name # selfns The instance namespace # win The original instance/tk window name. # old old instance command name # new new instance command name # op rename or delete # # If the op is delete, we need to clean up the object; otherwise, # we need to track the change. # # NOTE: In Tcl 8.4.2 there's a bug: errors in rename and delete # traces aren't propagated correctly. Instead, they silently # vanish. Add a catch to output any error message. proc ::snit::RT.InstanceTrace {type selfns win old new op} { variable ${type}::Snit_info # Note to developers ... # For Tcl 8.4.0, errors thrown in trace handlers vanish silently. # Therefore we catch them here and create some output to help in # debugging such problems. if {[catch { # FIRST, clean up if necessary if {"" == $new} { if {$Snit_info(isWidget)} { destroy $win } else { ::snit::RT.DestroyObject $type $selfns $win } } else { # Otherwise, track the change. variable ${selfns}::Snit_instance set Snit_instance [uplevel 1 [list namespace which -command $new]] # Also, clear the instance caches, as many cached commands # might be invalid. RT.ClearInstanceCaches $selfns } } result]} { global errorInfo # Pop up the console on Windows wish, to enable stdout. # This clobbers errorInfo on unix, so save it so we can print it. set ei $errorInfo catch {console show} puts "Error in ::snit::RT.InstanceTrace $type $selfns $win $old $new $op:" puts $ei } } # Calls the instance constructor and handles related housekeeping. proc ::snit::RT.ConstructInstance {type selfns instance arglist} { variable ${type}::Snit_optionInfo variable ${selfns}::Snit_iinfo # Track whether we are constructed or not. set Snit_iinfo(constructed) 0 # Call the user's constructor eval [linsert $arglist 0 \ ${type}::Snit_constructor $type $selfns $instance $instance] set Snit_iinfo(constructed) 1 # Validate the initial set of options (including defaults) foreach option $Snit_optionInfo(local) { set value [set ${selfns}::options($option)] if {$Snit_optionInfo(typespec-$option) ne ""} { if {[catch { $Snit_optionInfo(typeobj-$option) validate $value } result]} { return -code error "invalid $option default: $result" } } } # Unset the configure cache for all -readonly options. # This ensures that the next time anyone tries to # configure it, an error is thrown. foreach opt $Snit_optionInfo(local) { if {$Snit_optionInfo(readonly-$opt)} { unset -nocomplain ${selfns}::Snit_configureCache($opt) } } return } # Returns a unique command name. # # REQUIRE: type is a fully qualified name. # REQUIRE: name contains "%AUTO%" # PROMISE: the returned command name is unused. proc ::snit::RT.UniqueName {countervar type name} { upvar $countervar counter while 1 { # FIRST, bump the counter and define the %AUTO% instance name; # then substitute it into the specified name. Wrap around at # 2^31 - 2 to prevent overflow problems. incr counter if {$counter > 2147483646} { set counter 0 } set auto "[namespace tail $type]$counter" set candidate [Expand $name %AUTO% $auto] if {![llength [info commands $candidate]]} { return $candidate } } } # Returns a unique instance namespace, fully qualified. # # countervar The name of a counter variable # type The instance's type # # REQUIRE: type is fully qualified # PROMISE: The returned namespace name is unused. proc ::snit::RT.UniqueInstanceNamespace {countervar type} { upvar $countervar counter while 1 { # FIRST, bump the counter and define the namespace name. # Then see if it already exists. Wrap around at # 2^31 - 2 to prevent overflow problems. incr counter if {$counter > 2147483646} { set counter 0 } set ins "${type}::Snit_inst${counter}" if {![namespace exists $ins]} { return $ins } } } # Retrieves an option's value from the option database. # Returns "" if no value is found. proc ::snit::RT.OptionDbGet {type self opt} { variable ${type}::Snit_optionInfo return [option get $self \ $Snit_optionInfo(resource-$opt) \ $Snit_optionInfo(class-$opt)] } #----------------------------------------------------------------------- # Object Destruction # Implements the standard "destroy" method # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name proc ::snit::RT.method.destroy {type selfns win self} { variable ${selfns}::Snit_iinfo # Can't destroy the object if it isn't complete constructed. if {!$Snit_iinfo(constructed)} { return -code error "Called 'destroy' method in constructor" } # Calls Snit_cleanup, which (among other things) calls the # user's destructor. ::snit::RT.DestroyObject $type $selfns $win } # This is the function that really cleans up; it's automatically # called when any instance is destroyed, e.g., by "$object destroy" # for types, and by the event for widgets. # # type The fully-qualified type name. # selfns The instance namespace # win The original instance command name. proc ::snit::RT.DestroyObject {type selfns win} { variable ${type}::Snit_info # If the variable Snit_instance doesn't exist then there's no # instance command for this object -- it's most likely a # widgetadaptor. Consequently, there are some things that # we don't need to do. if {[info exists ${selfns}::Snit_instance]} { namespace upvar $selfns Snit_instance instance # First, remove the trace on the instance name, so that we # don't call RT.DestroyObject recursively. RT.RemoveInstanceTrace $type $selfns $win $instance # Next, call the user's destructor ${type}::Snit_destructor $type $selfns $win $instance # Next, if this isn't a widget, delete the instance command. # If it is a widget, get the hull component's name, and rename # it back to the widget name # Next, delete the hull component's instance command, # if there is one. if {$Snit_info(isWidget)} { set hullcmd [::snit::RT.Component $type $selfns hull] catch {rename $instance ""} # Clear the bind event bind Snit$type$win "" if {[llength [info commands $hullcmd]]} { # FIRST, rename the hull back to its original name. # If the hull is itself a megawidget, it will have its # own cleanup to do, and it might not do it properly # if it doesn't have the right name. rename $hullcmd ::$instance # NEXT, destroy it. destroy $instance } } else { catch {rename $instance ""} } } # Next, delete the instance's namespace. This kills any # instance variables. namespace delete $selfns return } # Remove instance trace # # type The fully qualified type name # selfns The instance namespace # win The original instance name/Tk window name # instance The current instance name proc ::snit::RT.RemoveInstanceTrace {type selfns win instance} { variable ${type}::Snit_info if {$Snit_info(isWidget)} { set procname ::$instance } else { set procname $instance } # NEXT, remove any trace on this name catch { trace remove command $procname {rename delete} \ [list ::snit::RT.InstanceTrace $type $selfns $win] } } #----------------------------------------------------------------------- # Typecomponent Management and Method Caching # Typecomponent trace; used for write trace on typecomponent # variables. Saves the new component object name, provided # that certain conditions are met. Also clears the typemethod # cache. proc ::snit::RT.TypecomponentTrace {type component n1 n2 op} { namespace upvar $type \ Snit_info Snit_info \ $component cvar \ Snit_typecomponents Snit_typecomponents # Save the new component value. set Snit_typecomponents($component) $cvar # Clear the typemethod cache. # TBD: can we unset just the elements related to # this component? # WHD: Namespace 2.0 code namespace ensemble configure $type -map {} } # WHD: Snit 2.0 code # # RT.UnknownTypemethod type eId eCmd method args # # type The type # eId The ensemble command ID; "" for the instance itself. # eCmd The ensemble command name. # method The unknown method name. # args The additional arguments, if any. # # This proc looks up the method relative to the specified ensemble. # If no method is found, it assumes that the "create" method is # desired, and that the "method" is the instance name. In this case, # it returns the "create" typemethod command with the instance name # appended; this will cause the instance to be created without updating # the -map. If the method is found, the method's command is created and # added to the -map; the function returns the empty list. proc snit::RT.UnknownTypemethod {type eId eCmd method args} { namespace upvar $type \ Snit_typemethodInfo Snit_typemethodInfo \ Snit_typecomponents Snit_typecomponents \ Snit_info Snit_info # FIRST, get the pattern data and the typecomponent name. set implicitCreate 0 set instanceName "" set fullMethod $eId lappend fullMethod $method set starredMethod [concat $eId *] set methodTail $method if {[info exists Snit_typemethodInfo($fullMethod)]} { set key $fullMethod } elseif {[info exists Snit_typemethodInfo($starredMethod)]} { if {[lsearch -exact $Snit_info(excepttypemethods) $methodTail] == -1} { set key $starredMethod } else { # WHD: The method is explicitly not delegated, so this is an error. # Or should we treat it as an instance name? return [list ] } } elseif {$Snit_info(hasinstances)} { # Assume the unknown name is an instance name to create, unless # this is a widget and the style of the name is wrong, or the # name mimics a standard typemethod. if {[set ${type}::Snit_info(isWidget)] && ![string match ".*" $method]} { return [list ] } # Without this check, the call "$type info" will redefine the # standard "::info" command, with disastrous results. Since it's # a likely thing to do if !-typeinfo, put in an explicit check. if {$method eq "info" || $method eq "destroy"} { return [list ] } set implicitCreate 1 set instanceName $method set key create set method create } else { return [list ] } foreach {flag pattern compName} $Snit_typemethodInfo($key) {} if {$flag == 1} { # FIRST, define the ensemble command. lappend eId $method set newCmd ${type}::Snit_ten[llength $eId]_[join $eId _] set unknownCmd [list ::snit::RT.UnknownTypemethod \ $type $eId] set createCmd [list namespace ensemble create \ -command $newCmd \ -unknown $unknownCmd \ -prefixes 0] namespace eval $type $createCmd # NEXT, add the method to the current ensemble set map [namespace ensemble configure $eCmd -map] dict append map $method $newCmd namespace ensemble configure $eCmd -map $map return [list ] } # NEXT, build the substitution list set subList [list \ %% % \ %t $type \ %M $fullMethod \ %m [lindex $fullMethod end] \ %j [join $fullMethod _]] if {$compName ne ""} { if {![info exists Snit_typecomponents($compName)]} { error "$type delegates typemethod \"$method\" to undefined typecomponent \"$compName\"" } lappend subList %c [list $Snit_typecomponents($compName)] } set command {} foreach subpattern $pattern { lappend command [string map $subList $subpattern] } if {$implicitCreate} { # In this case, $method is the name of the instance to # create. Don't cache, as we usually won't do this one # again. lappend command $instanceName return $command } # NEXT, if the actual command name isn't fully qualified, # assume it's global. set cmd [lindex $command 0] if {[string index $cmd 0] ne ":"} { set command [lreplace $command 0 0 "::$cmd"] } # NEXT, update the ensemble map. set map [namespace ensemble configure $eCmd -map] dict append map $method $command namespace ensemble configure $eCmd -map $map return [list ] } #----------------------------------------------------------------------- # Component Management and Method Caching # Retrieves the object name given the component name. proc ::snit::RT.Component {type selfns name} { variable ${selfns}::Snit_components if {[catch {set Snit_components($name)} result]} { variable ${selfns}::Snit_instance error "component \"$name\" is undefined in $type $Snit_instance" } return $result } # Component trace; used for write trace on component instance # variables. Saves the new component object name, provided # that certain conditions are met. Also clears the method # cache. proc ::snit::RT.ComponentTrace {type selfns component n1 n2 op} { namespace upvar $type Snit_info Snit_info namespace upvar $selfns \ $component cvar \ Snit_components Snit_components # If they try to redefine the hull component after # it's been defined, that's an error--but only if # this is a widget or widget adaptor. if {"hull" == $component && $Snit_info(isWidget) && [info exists Snit_components($component)]} { set cvar $Snit_components($component) error "The hull component cannot be redefined" } # Save the new component value. set Snit_components($component) $cvar # Clear the instance caches. # TBD: can we unset just the elements related to # this component? RT.ClearInstanceCaches $selfns } # WHD: Snit 2.0 code # # RT.UnknownMethod type selfns win eId eCmd method args # # type The type or widget command. # selfns The instance namespace. # win The original instance name. # eId The ensemble command ID; "" for the instance itself. # eCmd The real ensemble command name # method The unknown method name # args The additional arguments, if any. # # This proc looks up the method relative to the specific ensemble. # If no method is found, it returns an empty list; this will result in # the parent ensemble throwing an error. # If the method is found, the ensemble's -map is extended with the # correct command, and the empty list is returned; this caches the # method's command. If the method is found, and it is also an # ensemble, the ensemble command is created with an empty map. proc ::snit::RT.UnknownMethod {type selfns win eId eCmd method args} { variable ${type}::Snit_info variable ${type}::Snit_methodInfo variable ${type}::Snit_typecomponents variable ${selfns}::Snit_components # FIRST, get the "self" value set self [set ${selfns}::Snit_instance] # FIRST, get the pattern data and the component name. set fullMethod $eId lappend fullMethod $method set starredMethod [concat $eId *] set methodTail $method if {[info exists Snit_methodInfo($fullMethod)]} { set key $fullMethod } elseif {[info exists Snit_methodInfo($starredMethod)] && [lsearch -exact $Snit_info(exceptmethods) $methodTail] == -1} { set key $starredMethod } else { return [list ] } foreach {flag pattern compName} $Snit_methodInfo($key) {} if {$flag == 1} { # FIRST, define the ensemble command. lappend eId $method # Fix provided by Anton Kovalenko; previously this call erroneously # used ${type} rather than ${selfns}. set newCmd ${selfns}::Snit_en[llength $eId]_[join $eId _] set unknownCmd [list ::snit::RT.UnknownMethod \ $type $selfns $win $eId] set createCmd [list namespace ensemble create \ -command $newCmd \ -unknown $unknownCmd \ -prefixes 0] namespace eval $selfns $createCmd # NEXT, add the method to the current ensemble set map [namespace ensemble configure $eCmd -map] dict append map $method $newCmd namespace ensemble configure $eCmd -map $map return [list ] } # NEXT, build the substitution list set subList [list \ %% % \ %t $type \ %M $fullMethod \ %m [lindex $fullMethod end] \ %j [join $fullMethod _] \ %n [list $selfns] \ %w [list $win] \ %s [list $self]] if {$compName ne ""} { if {[info exists Snit_components($compName)]} { set compCmd $Snit_components($compName) } elseif {[info exists Snit_typecomponents($compName)]} { set compCmd $Snit_typecomponents($compName) } else { error "$type $self delegates method \"$fullMethod\" to undefined component \"$compName\"" } lappend subList %c [list $compCmd] } # Note: The cached command will execute faster if it's # already a list. set command {} foreach subpattern $pattern { lappend command [string map $subList $subpattern] } # NEXT, if the actual command name isn't fully qualified, # assume it's global. set cmd [lindex $command 0] if {[string index $cmd 0] ne ":"} { set command [lreplace $command 0 0 "::$cmd"] } # NEXT, update the ensemble map. set map [namespace ensemble configure $eCmd -map] dict append map $method $command namespace ensemble configure $eCmd -map $map return [list ] } # Clears all instance command caches proc ::snit::RT.ClearInstanceCaches {selfns} { # WHD: clear ensemble -map if {![info exists ${selfns}::Snit_instance]} { # Component variable set prior to constructor # via the "variable" type definition statement. return } set self [set ${selfns}::Snit_instance] namespace ensemble configure $self -map {} unset -nocomplain -- ${selfns}::Snit_cgetCache unset -nocomplain -- ${selfns}::Snit_configureCache unset -nocomplain -- ${selfns}::Snit_validateCache } #----------------------------------------------------------------------- # Component Installation # Implements %TYPE%::installhull. The variables self and selfns # must be defined in the caller's context. # # Installs the named widget as the hull of a # widgetadaptor. Once the widget is hijacked, its new name # is assigned to the hull component. proc ::snit::RT.installhull {type {using "using"} {widgetType ""} args} { variable ${type}::Snit_info variable ${type}::Snit_optionInfo upvar 1 self self upvar 1 selfns selfns namespace upvar $selfns \ hull hull \ options options # FIRST, make sure we can do it. if {!$Snit_info(isWidget)} { error "installhull is valid only for snit::widgetadaptors" } if {[info exists ${selfns}::Snit_instance]} { error "hull already installed for $type $self" } # NEXT, has it been created yet? If not, create it using # the specified arguments. if {"using" == $using} { # FIRST, create the widget set cmd [linsert $args 0 $widgetType $self] set obj [uplevel 1 $cmd] # NEXT, for each option explicitly delegated to the hull # that doesn't appear in the usedOpts list, get the # option database value and apply it--provided that the # real option name and the target option name are different. # (If they are the same, then the option database was # already queried as part of the normal widget creation.) # # Also, we don't need to worry about implicitly delegated # options, as the option and target option names must be # the same. if {[info exists Snit_optionInfo(delegated-hull)]} { # FIRST, extract all option names from args set usedOpts {} set ndx [lsearch -glob $args "-*"] foreach {opt val} [lrange $args $ndx end] { lappend usedOpts $opt } foreach opt $Snit_optionInfo(delegated-hull) { set target [lindex $Snit_optionInfo(target-$opt) 1] if {"$target" == $opt} { continue } set result [lsearch -exact $usedOpts $target] if {$result != -1} { continue } set dbval [RT.OptionDbGet $type $self $opt] $obj configure $target $dbval } } } else { set obj $using if {$obj ne $self} { error \ "hull name mismatch: \"$obj\" != \"$self\"" } } # NEXT, get the local option defaults. foreach opt $Snit_optionInfo(local) { set dbval [RT.OptionDbGet $type $self $opt] if {"" != $dbval} { set options($opt) $dbval } } # NEXT, do the magic set i 0 while 1 { incr i set newName "::hull${i}$self" if {![llength [info commands $newName]]} { break } } rename ::$self $newName RT.MakeInstanceCommand $type $selfns $self # Note: this relies on RT.ComponentTrace to do the dirty work. set hull $newName return } # Implements %TYPE%::install. # # Creates a widget and installs it as the named component. # It expects self and selfns to be defined in the caller's context. proc ::snit::RT.install {type compName "using" widgetType winPath args} { variable ${type}::Snit_optionInfo variable ${type}::Snit_info upvar 1 self self upvar 1 selfns selfns namespace upvar ${selfns} \ $compName comp \ hull hull # We do the magic option database stuff only if $self is # a widget. if {$Snit_info(isWidget)} { if {"" == $hull} { error "tried to install \"$compName\" before the hull exists" } # FIRST, query the option database and save the results # into args. Insert them before the first option in the # list, in case there are any non-standard parameters. # # Note: there might not be any delegated options; if so, # don't bother. if {[info exists Snit_optionInfo(delegated-$compName)]} { set ndx [lsearch -glob $args "-*"] foreach opt $Snit_optionInfo(delegated-$compName) { set dbval [RT.OptionDbGet $type $self $opt] if {"" != $dbval} { set target [lindex $Snit_optionInfo(target-$opt) 1] set args [linsert $args $ndx $target $dbval] } } } } # NEXT, create the component and save it. set cmd [concat [list $widgetType $winPath] $args] set comp [uplevel 1 $cmd] # NEXT, handle the option database for "delegate option *", # in widgets only. if {$Snit_info(isWidget) && $Snit_optionInfo(starcomp) eq $compName} { # FIRST, get the list of option specs from the widget. # If configure doesn't work, skip it. if {[catch {$comp configure} specs]} { return } # NEXT, get the set of explicitly used options from args set usedOpts {} set ndx [lsearch -glob $args "-*"] foreach {opt val} [lrange $args $ndx end] { lappend usedOpts $opt } # NEXT, "delegate option *" matches all options defined # by this widget that aren't defined by the widget as a whole, # and that aren't excepted. Plus, we skip usedOpts. So build # a list of the options it can't match. set skiplist [concat \ $usedOpts \ $Snit_optionInfo(except) \ $Snit_optionInfo(local) \ $Snit_optionInfo(delegated)] # NEXT, loop over all of the component's options, and set # any not in the skip list for which there is an option # database value. foreach spec $specs { # Skip aliases if {[llength $spec] != 5} { continue } set opt [lindex $spec 0] if {[lsearch -exact $skiplist $opt] != -1} { continue } set res [lindex $spec 1] set cls [lindex $spec 2] set dbvalue [option get $self $res $cls] if {"" != $dbvalue} { $comp configure $opt $dbvalue } } } return } #----------------------------------------------------------------------- # Method/Variable Name Qualification # Implements %TYPE%::variable. Requires selfns. proc ::snit::RT.variable {varname} { upvar 1 selfns selfns if {![string match "::*" $varname]} { uplevel 1 [list upvar 1 ${selfns}::$varname $varname] } else { # varname is fully qualified; let the standard # "variable" command handle it. uplevel 1 [list ::variable $varname] } } # Fully qualifies a typevariable name. # # This is used to implement the mytypevar command. proc ::snit::RT.mytypevar {type name} { return ${type}::$name } # Fully qualifies an instance variable name. # # This is used to implement the myvar command. proc ::snit::RT.myvar {name} { upvar 1 selfns selfns return ${selfns}::$name } # Use this like "list" to convert a proc call into a command # string to pass to another object (e.g., as a -command). # Qualifies the proc name properly. # # This is used to implement the "myproc" command. proc ::snit::RT.myproc {type procname args} { set procname "${type}::$procname" return [linsert $args 0 $procname] } # DEPRECATED proc ::snit::RT.codename {type name} { return "${type}::$name" } # Use this like "list" to convert a typemethod call into a command # string to pass to another object (e.g., as a -command). # Inserts the type command at the beginning. # # This is used to implement the "mytypemethod" command. proc ::snit::RT.mytypemethod {type args} { return [linsert $args 0 $type] } # Use this like "list" to convert a method call into a command # string to pass to another object (e.g., as a -command). # Inserts the code at the beginning to call the right object, even if # the object's name has changed. Requires that selfns be defined # in the calling context, eg. can only be called in instance # code. # # This is used to implement the "mymethod" command. proc ::snit::RT.mymethod {args} { upvar 1 selfns selfns return [linsert $args 0 ::snit::RT.CallInstance ${selfns}] } # Calls an instance method for an object given its # instance namespace and remaining arguments (the first of which # will be the method name. # # selfns The instance namespace # args The arguments # # Uses the selfns to determine $self, and calls the method # in the normal way. # # This is used to implement the "mymethod" command. proc ::snit::RT.CallInstance {selfns args} { namespace upvar $selfns Snit_instance self set retval [catch {uplevel 1 [linsert $args 0 $self]} result] if {$retval} { if {$retval == 1} { global errorInfo global errorCode return -code error -errorinfo $errorInfo \ -errorcode $errorCode $result } else { return -code $retval $result } } return $result } # Looks for the named option in the named variable. If found, # it and its value are removed from the list, and the value # is returned. Otherwise, the default value is returned. # If the option is undelegated, it's own default value will be # used if none is specified. # # Implements the "from" command. proc ::snit::RT.from {type argvName option {defvalue ""}} { namespace upvar $type Snit_optionInfo Snit_optionInfo upvar $argvName argv set ioption [lsearch -exact $argv $option] if {$ioption == -1} { if {"" == $defvalue && [info exists Snit_optionInfo(default-$option)]} { return $Snit_optionInfo(default-$option) } else { return $defvalue } } set ivalue [expr {$ioption + 1}] set value [lindex $argv $ivalue] set argv [lreplace $argv $ioption $ivalue] return $value } #----------------------------------------------------------------------- # Type Destruction # Implements the standard "destroy" typemethod: # Destroys a type completely. # # type The snit type proc ::snit::RT.typemethod.destroy {type} { variable ${type}::Snit_info # FIRST, destroy all instances foreach selfns [namespace children $type] { if {![namespace exists $selfns]} { continue } namespace upvar $selfns Snit_instance obj if {$Snit_info(isWidget)} { destroy $obj } else { if {[llength [info commands $obj]]} { $obj destroy } } } # NEXT, get rid of the type command. rename $type "" # NEXT, destroy the type's data. namespace delete $type } #----------------------------------------------------------------------- # Option Handling # Implements the standard "cget" method # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # option The name of the option proc ::snit::RT.method.cget {type selfns win self option} { if {[catch {set ${selfns}::Snit_cgetCache($option)} command]} { set command [snit::RT.CacheCgetCommand $type $selfns $win $self $option] if {[llength $command] == 0} { return -code error "unknown option \"$option\"" } } uplevel 1 $command } # Retrieves and caches the command that implements "cget" for the # specified option. # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # option The name of the option proc ::snit::RT.CacheCgetCommand {type selfns win self option} { variable ${type}::Snit_optionInfo variable ${selfns}::Snit_cgetCache if {[info exists Snit_optionInfo(islocal-$option)]} { # We know the item; it's either local, or explicitly delegated. if {$Snit_optionInfo(islocal-$option)} { # It's a local option. If it has a cget method defined, # use it; otherwise just return the value. if {$Snit_optionInfo(cget-$option) eq ""} { set command [list set ${selfns}::options($option)] } else { # WHD: Snit 2.0 code -- simpler, no slower. set command [list \ $self \ {*}$Snit_optionInfo(cget-$option) \ $option] } set Snit_cgetCache($option) $command return $command } # Explicitly delegated option; get target set comp [lindex $Snit_optionInfo(target-$option) 0] set target [lindex $Snit_optionInfo(target-$option) 1] } elseif {$Snit_optionInfo(starcomp) ne "" && [lsearch -exact $Snit_optionInfo(except) $option] == -1} { # Unknown option, but unknowns are delegated; get target. set comp $Snit_optionInfo(starcomp) set target $option } else { return "" } # Get the component's object. set obj [RT.Component $type $selfns $comp] set command [list $obj cget $target] set Snit_cgetCache($option) $command return $command } # Implements the standard "configurelist" method # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # optionlist A list of options and their values. proc ::snit::RT.method.configurelist {type selfns win self optionlist} { variable ${type}::Snit_optionInfo foreach {option value} $optionlist { # FIRST, get the configure command, caching it if need be. if {[catch {set ${selfns}::Snit_configureCache($option)} command]} { set command [snit::RT.CacheConfigureCommand \ $type $selfns $win $self $option] if {[llength $command] == 0} { return -code error "unknown option \"$option\"" } } # NEXT, if we have a type-validation object, use it. # TBD: Should test (islocal-$option) here, but islocal # isn't defined for implicitly delegated options. if {[info exists Snit_optionInfo(typeobj-$option)] && $Snit_optionInfo(typeobj-$option) ne ""} { if {[catch { $Snit_optionInfo(typeobj-$option) validate $value } result]} { return -code error "invalid $option value: $result" } } # NEXT, the caching the configure command also cached the # validate command, if any. If we have one, run it. set valcommand [set ${selfns}::Snit_validateCache($option)] if {[llength $valcommand]} { lappend valcommand $value uplevel 1 $valcommand } # NEXT, configure the option with the value. lappend command $value uplevel 1 $command } return } # Retrieves and caches the command that stores the named option. # Also stores the command that validates the name option if any; # If none, the validate command is "", so that the cache is always # populated. # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # option An option name proc ::snit::RT.CacheConfigureCommand {type selfns win self option} { variable ${type}::Snit_optionInfo variable ${selfns}::Snit_configureCache variable ${selfns}::Snit_validateCache if {[info exist Snit_optionInfo(islocal-$option)]} { # We know the item; it's either local, or explicitly delegated. if {$Snit_optionInfo(islocal-$option)} { # It's a local option. # If it's readonly, it throws an error if we're already # constructed. if {$Snit_optionInfo(readonly-$option)} { if {[set ${selfns}::Snit_iinfo(constructed)]} { error "option $option can only be set at instance creation" } } # If it has a validate method, cache that for later. if {$Snit_optionInfo(validate-$option) ne ""} { # WHD: Snit 2.0 code -- simpler, no slower. set command [list \ $self \ {*}$Snit_optionInfo(validate-$option) \ $option] set Snit_validateCache($option) $command } else { set Snit_validateCache($option) "" } # If it has a configure method defined, # cache it; otherwise, just set the value. if {$Snit_optionInfo(configure-$option) eq ""} { set command [list set ${selfns}::options($option)] } else { # WHD: Snit 2.0 code -- simpler, no slower. set command [list \ $self \ {*}$Snit_optionInfo(configure-$option) \ $option] } set Snit_configureCache($option) $command return $command } # Delegated option: get target. set comp [lindex $Snit_optionInfo(target-$option) 0] set target [lindex $Snit_optionInfo(target-$option) 1] } elseif {$Snit_optionInfo(starcomp) != "" && [lsearch -exact $Snit_optionInfo(except) $option] == -1} { # Unknown option, but unknowns are delegated. set comp $Snit_optionInfo(starcomp) set target $option } else { return "" } # There is no validate command in this case; save an empty string. set Snit_validateCache($option) "" # Get the component's object set obj [RT.Component $type $selfns $comp] set command [list $obj configure $target] set Snit_configureCache($option) $command return $command } # Implements the standard "configure" method # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # args A list of options and their values, possibly empty. proc ::snit::RT.method.configure {type selfns win self args} { # If two or more arguments, set values as usual. if {[llength $args] >= 2} { ::snit::RT.method.configurelist $type $selfns $win $self $args return } # If zero arguments, acquire data for each known option # and return the list if {[llength $args] == 0} { set result {} foreach opt [RT.method.info.options $type $selfns $win $self] { # Refactor this, so that we don't need to call via $self. lappend result [RT.GetOptionDbSpec \ $type $selfns $win $self $opt] } return $result } # They want it for just one. set opt [lindex $args 0] return [RT.GetOptionDbSpec $type $selfns $win $self $opt] } # Retrieves the option database spec for a single option. # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # option The name of an option # # TBD: This is a bad name. What it's returning is the # result of the configure query. proc ::snit::RT.GetOptionDbSpec {type selfns win self opt} { variable ${type}::Snit_optionInfo namespace upvar $selfns \ Snit_components Snit_components \ options options if {[info exists options($opt)]} { # This is a locally-defined option. Just build the # list and return it. set res $Snit_optionInfo(resource-$opt) set cls $Snit_optionInfo(class-$opt) set def $Snit_optionInfo(default-$opt) return [list $opt $res $cls $def \ [RT.method.cget $type $selfns $win $self $opt]] } elseif {[info exists Snit_optionInfo(target-$opt)]} { # This is an explicitly delegated option. The only # thing we don't have is the default. set res $Snit_optionInfo(resource-$opt) set cls $Snit_optionInfo(class-$opt) # Get the default set logicalName [lindex $Snit_optionInfo(target-$opt) 0] set comp $Snit_components($logicalName) set target [lindex $Snit_optionInfo(target-$opt) 1] if {[catch {$comp configure $target} result]} { set defValue {} } else { set defValue [lindex $result 3] } return [list $opt $res $cls $defValue [$self cget $opt]] } elseif {$Snit_optionInfo(starcomp) ne "" && [lsearch -exact $Snit_optionInfo(except) $opt] == -1} { set logicalName $Snit_optionInfo(starcomp) set target $opt set comp $Snit_components($logicalName) if {[catch {set value [$comp cget $target]} result]} { error "unknown option \"$opt\"" } if {![catch {$comp configure $target} result]} { # Replace the delegated option name with the local name. return [::snit::Expand $result $target $opt] } # configure didn't work; return simple form. return [list $opt "" "" "" $value] } else { error "unknown option \"$opt\"" } } #----------------------------------------------------------------------- # Type Introspection # Implements the standard "info" typemethod. # # type The snit type # command The info subcommand # args All other arguments. proc ::snit::RT.typemethod.info {type command args} { global errorInfo global errorCode switch -exact $command { args - body - default - typevars - typemethods - instances { # TBD: it should be possible to delete this error # handling. set errflag [catch { uplevel 1 [linsert $args 0 \ ::snit::RT.typemethod.info.$command $type] } result] if {$errflag} { return -code error -errorinfo $errorInfo \ -errorcode $errorCode $result } else { return $result } } default { error "\"$type info $command\" is not defined" } } } # Returns a list of the type's typevariables whose names match a # pattern, excluding Snit internal variables. # # type A Snit type # pattern Optional. The glob pattern to match. Defaults # to *. proc ::snit::RT.typemethod.info.typevars {type {pattern *}} { set result {} foreach name [info vars "${type}::$pattern"] { set tail [namespace tail $name] if {![string match "Snit_*" $tail]} { lappend result $name } } return $result } # Returns a list of the type's methods whose names match a # pattern. If "delegate typemethod *" is used, the list may # not be complete. # # type A Snit type # pattern Optional. The glob pattern to match. Defaults # to *. proc ::snit::RT.typemethod.info.typemethods {type {pattern *}} { variable ${type}::Snit_typemethodInfo # FIRST, get the explicit names, skipping prefixes. set result {} foreach name [array names Snit_typemethodInfo -glob $pattern] { if {[lindex $Snit_typemethodInfo($name) 0] != 1} { lappend result $name } } # NEXT, add any from the cache that aren't explicit. # WHD: fixed up to use newstyle method cache/list of subcommands. if {[info exists Snit_typemethodInfo(*)]} { # First, remove "*" from the list. set ndx [lsearch -exact $result "*"] if {$ndx != -1} { set result [lreplace $result $ndx $ndx] } # Next, get the type's -map array set typemethodCache [namespace ensemble configure $type -map] # Next, get matching names from the cache that we don't already # know about. foreach name [array names typemethodCache -glob $pattern] { if {[lsearch -exact $result $name] == -1} { lappend result $name } } } return $result } # $type info args # # Returns a method's list of arguments. does not work for delegated # methods, nor for the internal dispatch methods of multi-word # methods. proc ::snit::RT.typemethod.info.args {type method} { upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo # Snit_methodInfo: method -> list (flag cmd component) # flag : 1 -> internal dispatcher for multi-word method. # 0 -> regular method # # cmd : template mapping from method to command prefix, may # contain placeholders for various pieces of information. # # component : is empty for normal methods. #parray Snit_typemethodInfo if {![info exists Snit_typemethodInfo($method)]} { return -code error "Unknown typemethod \"$method\"" } foreach {flag cmd component} $Snit_typemethodInfo($method) break if {$flag} { return -code error "Unknown typemethod \"$method\"" } if {$component != ""} { return -code error "Delegated typemethod \"$method\"" } set map [list %m $method %j [join $method _] %t $type] set theproc [lindex [string map $map $cmd] 0] return [lrange [::info args $theproc] 1 end] } # $type info body # # Returns a method's body. does not work for delegated # methods, nor for the internal dispatch methods of multi-word # methods. proc ::snit::RT.typemethod.info.body {type method} { upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo # Snit_methodInfo: method -> list (flag cmd component) # flag : 1 -> internal dispatcher for multi-word method. # 0 -> regular method # # cmd : template mapping from method to command prefix, may # contain placeholders for various pieces of information. # # component : is empty for normal methods. #parray Snit_typemethodInfo if {![info exists Snit_typemethodInfo($method)]} { return -code error "Unknown typemethod \"$method\"" } foreach {flag cmd component} $Snit_typemethodInfo($method) break if {$flag} { return -code error "Unknown typemethod \"$method\"" } if {$component != ""} { return -code error "Delegated typemethod \"$method\"" } set map [list %m $method %j [join $method _] %t $type] set theproc [lindex [string map $map $cmd] 0] return [RT.body [::info body $theproc]] } # $type info default # # Returns a method's list of arguments. does not work for delegated # methods, nor for the internal dispatch methods of multi-word # methods. proc ::snit::RT.typemethod.info.default {type method aname dvar} { upvar 1 $dvar def upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo # Snit_methodInfo: method -> list (flag cmd component) # flag : 1 -> internal dispatcher for multi-word method. # 0 -> regular method # # cmd : template mapping from method to command prefix, may # contain placeholders for various pieces of information. # # component : is empty for normal methods. #parray Snit_methodInfo if {![info exists Snit_typemethodInfo($method)]} { return -code error "Unknown typemethod \"$method\"" } foreach {flag cmd component} $Snit_typemethodInfo($method) break if {$flag} { return -code error "Unknown typemethod \"$method\"" } if {$component != ""} { return -code error "Delegated typemethod \"$method\"" } set map [list %m $method %j [join $method _] %t $type] set theproc [lindex [string map $map $cmd] 0] return [::info default $theproc $aname def] } # Returns a list of the type's instances whose names match # a pattern. # # type A Snit type # pattern Optional. The glob pattern to match # Defaults to * # # REQUIRE: type is fully qualified. proc ::snit::RT.typemethod.info.instances {type {pattern *}} { set result {} foreach selfns [namespace children $type] { namespace upvar $selfns Snit_instance instance if {[string match $pattern $instance]} { lappend result $instance } } return $result } #----------------------------------------------------------------------- # Instance Introspection # Implements the standard "info" method. # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # command The info subcommand # args All other arguments. proc ::snit::RT.method.info {type selfns win self command args} { switch -exact $command { args - body - default - type - vars - options - methods - typevars - typemethods { set errflag [catch { uplevel 1 [linsert $args 0 ::snit::RT.method.info.$command \ $type $selfns $win $self] } result] if {$errflag} { global errorInfo return -code error -errorinfo $errorInfo $result } else { return $result } } default { # error "\"$self info $command\" is not defined" return -code error "\"$self info $command\" is not defined" } } } # $self info type # # Returns the instance's type proc ::snit::RT.method.info.type {type selfns win self} { return $type } # $self info typevars # # Returns the instance's type's typevariables proc ::snit::RT.method.info.typevars {type selfns win self {pattern *}} { return [RT.typemethod.info.typevars $type $pattern] } # $self info typemethods # # Returns the instance's type's typemethods proc ::snit::RT.method.info.typemethods {type selfns win self {pattern *}} { return [RT.typemethod.info.typemethods $type $pattern] } # Returns a list of the instance's methods whose names match a # pattern. If "delegate method *" is used, the list may # not be complete. # # type A Snit type # selfns The instance namespace # win The original instance name # self The current instance name # pattern Optional. The glob pattern to match. Defaults # to *. proc ::snit::RT.method.info.methods {type selfns win self {pattern *}} { variable ${type}::Snit_methodInfo # FIRST, get the explicit names, skipping prefixes. set result {} foreach name [array names Snit_methodInfo -glob $pattern] { if {[lindex $Snit_methodInfo($name) 0] != 1} { lappend result $name } } # NEXT, add any from the cache that aren't explicit. # WHD: Fixed up to use newstyle method cache/list of subcommands. if {[info exists Snit_methodInfo(*)]} { # First, remove "*" from the list. set ndx [lsearch -exact $result "*"] if {$ndx != -1} { set result [lreplace $result $ndx $ndx] } # Next, get the instance's -map set self [set ${selfns}::Snit_instance] array set methodCache [namespace ensemble configure $self -map] # Next, get matching names from the cache that we don't already # know about. foreach name [array names methodCache -glob $pattern] { if {[lsearch -exact $result $name] == -1} { lappend result $name } } } return $result } # $self info args # # Returns a method's list of arguments. does not work for delegated # methods, nor for the internal dispatch methods of multi-word # methods. proc ::snit::RT.method.info.args {type selfns win self method} { upvar ${type}::Snit_methodInfo Snit_methodInfo # Snit_methodInfo: method -> list (flag cmd component) # flag : 1 -> internal dispatcher for multi-word method. # 0 -> regular method # # cmd : template mapping from method to command prefix, may # contain placeholders for various pieces of information. # # component : is empty for normal methods. #parray Snit_methodInfo if {![info exists Snit_methodInfo($method)]} { return -code error "Unknown method \"$method\"" } foreach {flag cmd component} $Snit_methodInfo($method) break if {$flag} { return -code error "Unknown method \"$method\"" } if {$component != ""} { return -code error "Delegated method \"$method\"" } set map [list %m $method %j [join $method _] %t $type %n $selfns %w $win %s $self] set theproc [lindex [string map $map $cmd] 0] return [lrange [::info args $theproc] 4 end] } # $self info body # # Returns a method's body. does not work for delegated # methods, nor for the internal dispatch methods of multi-word # methods. proc ::snit::RT.method.info.body {type selfns win self method} { upvar ${type}::Snit_methodInfo Snit_methodInfo # Snit_methodInfo: method -> list (flag cmd component) # flag : 1 -> internal dispatcher for multi-word method. # 0 -> regular method # # cmd : template mapping from method to command prefix, may # contain placeholders for various pieces of information. # # component : is empty for normal methods. #parray Snit_methodInfo if {![info exists Snit_methodInfo($method)]} { return -code error "Unknown method \"$method\"" } foreach {flag cmd component} $Snit_methodInfo($method) break if {$flag} { return -code error "Unknown method \"$method\"" } if {$component != ""} { return -code error "Delegated method \"$method\"" } set map [list %m $method %j [join $method _] %t $type %n $selfns %w $win %s $self] set theproc [lindex [string map $map $cmd] 0] return [RT.body [::info body $theproc]] } # $self info default # # Returns a method's list of arguments. does not work for delegated # methods, nor for the internal dispatch methods of multi-word # methods. proc ::snit::RT.method.info.default {type selfns win self method aname dvar} { upvar 1 $dvar def upvar ${type}::Snit_methodInfo Snit_methodInfo # Snit_methodInfo: method -> list (flag cmd component) # flag : 1 -> internal dispatcher for multi-word method. # 0 -> regular method # # cmd : template mapping from method to command prefix, may # contain placeholders for various pieces of information. # # component : is empty for normal methods. if {![info exists Snit_methodInfo($method)]} { return -code error "Unknown method \"$method\"" } foreach {flag cmd component} $Snit_methodInfo($method) break if {$flag} { return -code error "Unknown method \"$method\"" } if {$component != ""} { return -code error "Delegated method \"$method\"" } set map [list %m $method %j [join $method _] %t $type %n $selfns %w $win %s $self] set theproc [lindex [string map $map $cmd] 0] return [::info default $theproc $aname def] } # $self info vars # # Returns the instance's instance variables proc ::snit::RT.method.info.vars {type selfns win self {pattern *}} { set result {} foreach name [info vars "${selfns}::$pattern"] { set tail [namespace tail $name] if {![string match "Snit_*" $tail]} { lappend result $name } } return $result } # $self info options # # Returns a list of the names of the instance's options proc ::snit::RT.method.info.options {type selfns win self {pattern *}} { variable ${type}::Snit_optionInfo # First, get the local and explicitly delegated options set result [concat $Snit_optionInfo(local) $Snit_optionInfo(delegated)] # If "configure" works as for Tk widgets, add the resulting # options to the list. Skip excepted options if {$Snit_optionInfo(starcomp) ne ""} { namespace upvar $selfns Snit_components Snit_components set logicalName $Snit_optionInfo(starcomp) set comp $Snit_components($logicalName) if {![catch {$comp configure} records]} { foreach record $records { set opt [lindex $record 0] if {[lsearch -exact $result $opt] == -1 && [lsearch -exact $Snit_optionInfo(except) $opt] == -1} { lappend result $opt } } } } # Next, apply the pattern set names {} foreach name $result { if {[string match $pattern $name]} { lappend names $name } } return $names } proc ::snit::RT.body {body} { regsub -all ".*# END snit method prolog\n" $body {} body return $body } amsn-0.98.9/utils/snit/main1.tcl0000644000175000017500000037113411020317540016221 0ustar billiobbilliob#----------------------------------------------------------------------- # TITLE: # main1.tcl # # AUTHOR: # Will Duquette # # DESCRIPTION: # Snit's Not Incr Tcl, a simple object system in Pure Tcl. # # Snit 1.x Compiler and Run-Time Library, Tcl 8.4 and later # # Copyright (C) 2003-2006 by William H. Duquette # This code is licensed as described in license.txt. # #----------------------------------------------------------------------- #----------------------------------------------------------------------- # Namespace namespace eval ::snit:: { namespace export \ compile type widget widgetadaptor typemethod method macro } #----------------------------------------------------------------------- # Some Snit variables namespace eval ::snit:: { variable reservedArgs {type selfns win self} # Widget classes which can be hulls (must have -class) variable hulltypes { toplevel tk::toplevel frame tk::frame ttk::frame labelframe tk::labelframe ttk::labelframe } } #----------------------------------------------------------------------- # Snit Type Implementation template namespace eval ::snit:: { # Template type definition: All internal and user-visible Snit # implementation code. # # The following placeholders will automatically be replaced with # the client's code, in two passes: # # First pass: # %COMPILEDDEFS% The compiled type definition. # # Second pass: # %TYPE% The fully qualified type name. # %IVARDECS% Instance variable declarations # %TVARDECS% Type variable declarations # %TCONSTBODY% Type constructor body # %INSTANCEVARS% The compiled instance variable initialization code. # %TYPEVARS% The compiled type variable initialization code. # This is the overall type template. variable typeTemplate # This is the normal type proc variable nominalTypeProc # This is the "-hastypemethods no" type proc variable simpleTypeProc } set ::snit::typeTemplate { #------------------------------------------------------------------- # The type's namespace definition and the user's type variables namespace eval %TYPE% {%TYPEVARS% } #---------------------------------------------------------------- # Commands for use in methods, typemethods, etc. # # These are implemented as aliases into the Snit runtime library. interp alias {} %TYPE%::installhull {} ::snit::RT.installhull %TYPE% interp alias {} %TYPE%::install {} ::snit::RT.install %TYPE% interp alias {} %TYPE%::typevariable {} ::variable interp alias {} %TYPE%::variable {} ::snit::RT.variable interp alias {} %TYPE%::mytypevar {} ::snit::RT.mytypevar %TYPE% interp alias {} %TYPE%::typevarname {} ::snit::RT.mytypevar %TYPE% interp alias {} %TYPE%::myvar {} ::snit::RT.myvar interp alias {} %TYPE%::varname {} ::snit::RT.myvar interp alias {} %TYPE%::codename {} ::snit::RT.codename %TYPE% interp alias {} %TYPE%::myproc {} ::snit::RT.myproc %TYPE% interp alias {} %TYPE%::mymethod {} ::snit::RT.mymethod interp alias {} %TYPE%::mytypemethod {} ::snit::RT.mytypemethod %TYPE% interp alias {} %TYPE%::from {} ::snit::RT.from %TYPE% #------------------------------------------------------------------- # Snit's internal variables namespace eval %TYPE% { # Array: General Snit Info # # ns: The type's namespace # hasinstances: T or F, from pragma -hasinstances. # simpledispatch: T or F, from pragma -hasinstances. # canreplace: T or F, from pragma -canreplace. # counter: Count of instances created so far. # widgetclass: Set by widgetclass statement. # hulltype: Hull type (frame or toplevel) for widgets only. # exceptmethods: Methods explicitly not delegated to * # excepttypemethods: Methods explicitly not delegated to * # tvardecs: Type variable declarations--for dynamic methods # ivardecs: Instance variable declarations--for dyn. methods typevariable Snit_info set Snit_info(ns) %TYPE%:: set Snit_info(hasinstances) 1 set Snit_info(simpledispatch) 0 set Snit_info(canreplace) 0 set Snit_info(counter) 0 set Snit_info(widgetclass) {} set Snit_info(hulltype) frame set Snit_info(exceptmethods) {} set Snit_info(excepttypemethods) {} set Snit_info(tvardecs) {%TVARDECS%} set Snit_info(ivardecs) {%IVARDECS%} # Array: Public methods of this type. # The index is the method name, or "*". # The value is [list $pattern $componentName], where # $componentName is "" for normal methods. typevariable Snit_typemethodInfo array unset Snit_typemethodInfo # Array: Public methods of instances of this type. # The index is the method name, or "*". # The value is [list $pattern $componentName], where # $componentName is "" for normal methods. typevariable Snit_methodInfo array unset Snit_methodInfo # Array: option information. See dictionary.txt. typevariable Snit_optionInfo array unset Snit_optionInfo set Snit_optionInfo(local) {} set Snit_optionInfo(delegated) {} set Snit_optionInfo(starcomp) {} set Snit_optionInfo(except) {} } #---------------------------------------------------------------- # Compiled Procs # # These commands are created or replaced during compilation: # Snit_instanceVars selfns # # Initializes the instance variables, if any. Called during # instance creation. proc %TYPE%::Snit_instanceVars {selfns} { %INSTANCEVARS% } # Type Constructor proc %TYPE%::Snit_typeconstructor {type} { %TVARDECS% %TCONSTBODY% } #---------------------------------------------------------------- # Default Procs # # These commands might be replaced during compilation: # Snit_destructor type selfns win self # # Default destructor for the type. By default, it does # nothing. It's replaced by any user destructor. # For types, it's called by method destroy; for widgettypes, # it's called by a destroy event handler. proc %TYPE%::Snit_destructor {type selfns win self} { } #---------------------------------------------------------- # Compiled Definitions %COMPILEDDEFS% #---------------------------------------------------------- # Finally, call the Type Constructor %TYPE%::Snit_typeconstructor %TYPE% } #----------------------------------------------------------------------- # Type procs # # These procs expect the fully-qualified type name to be # substituted in for %TYPE%. # This is the nominal type proc. It supports typemethods and # delegated typemethods. set ::snit::nominalTypeProc { # Type dispatcher function. Note: This function lives # in the parent of the %TYPE% namespace! All accesses to # %TYPE% variables and methods must be qualified! proc %TYPE% {{method ""} args} { # First, if there's no method, and no args, and there's a create # method, and this isn't a widget, then method is "create" and # "args" is %AUTO%. if {"" == $method && [llength $args] == 0} { ::variable %TYPE%::Snit_info if {$Snit_info(hasinstances) && !$Snit_info(isWidget)} { set method create lappend args %AUTO% } else { error "wrong \# args: should be \"%TYPE% method args\"" } } # Next, retrieve the command. variable %TYPE%::Snit_typemethodCache while 1 { if {[catch {set Snit_typemethodCache($method)} commandRec]} { set commandRec [::snit::RT.CacheTypemethodCommand %TYPE% $method] if {[llength $commandRec] == 0} { return -code error "\"%TYPE% $method\" is not defined" } } # If we've got a real command, break. if {[lindex $commandRec 0] == 0} { break } # Otherwise, we need to look up again...if we can. if {[llength $args] == 0} { return -code error \ "wrong number args: should be \"%TYPE% $method method args\"" } lappend method [lindex $args 0] set args [lrange $args 1 end] } set command [lindex $commandRec 1] # Pass along the return code unchanged. set retval [catch {uplevel 1 $command $args} result] if {$retval} { if {$retval == 1} { global errorInfo global errorCode return -code error -errorinfo $errorInfo \ -errorcode $errorCode $result } else { return -code $retval $result } } return $result } } # This is the simplified type proc for when there are no typemethods # except create. In this case, it doesn't take a method argument; # the method is always "create". set ::snit::simpleTypeProc { # Type dispatcher function. Note: This function lives # in the parent of the %TYPE% namespace! All accesses to # %TYPE% variables and methods must be qualified! proc %TYPE% {args} { ::variable %TYPE%::Snit_info # FIRST, if the are no args, the single arg is %AUTO% if {[llength $args] == 0} { if {$Snit_info(isWidget)} { error "wrong \# args: should be \"%TYPE% name args\"" } lappend args %AUTO% } # NEXT, we're going to call the create method. # Pass along the return code unchanged. if {$Snit_info(isWidget)} { set command [list ::snit::RT.widget.typemethod.create %TYPE%] } else { set command [list ::snit::RT.type.typemethod.create %TYPE%] } set retval [catch {uplevel 1 $command $args} result] if {$retval} { if {$retval == 1} { global errorInfo global errorCode return -code error -errorinfo $errorInfo \ -errorcode $errorCode $result } else { return -code $retval $result } } return $result } } #----------------------------------------------------------------------- # Instance procs # # The following must be substituted into these proc bodies: # # %SELFNS% The instance namespace # %WIN% The original instance name # %TYPE% The fully-qualified type name # # Nominal instance proc body: supports method caching and delegation. # # proc $instanceName {method args} .... set ::snit::nominalInstanceProc { set self [set %SELFNS%::Snit_instance] while {1} { if {[catch {set %SELFNS%::Snit_methodCache($method)} commandRec]} { set commandRec [snit::RT.CacheMethodCommand %TYPE% %SELFNS% %WIN% $self $method] if {[llength $commandRec] == 0} { return -code error \ "\"$self $method\" is not defined" } } # If we've got a real command, break. if {[lindex $commandRec 0] == 0} { break } # Otherwise, we need to look up again...if we can. if {[llength $args] == 0} { return -code error \ "wrong number args: should be \"$self $method method args\"" } lappend method [lindex $args 0] set args [lrange $args 1 end] } set command [lindex $commandRec 1] # Pass along the return code unchanged. set retval [catch {uplevel 1 $command $args} result] if {$retval} { if {$retval == 1} { global errorInfo global errorCode return -code error -errorinfo $errorInfo \ -errorcode $errorCode $result } else { return -code $retval $result } } return $result } # Simplified method proc body: No delegation allowed; no support for # upvar or exotic return codes or hierarchical methods. Designed for # max speed for simple types. # # proc $instanceName {method args} .... set ::snit::simpleInstanceProc { set self [set %SELFNS%::Snit_instance] if {[lsearch -exact ${%TYPE%::Snit_methods} $method] == -1} { set optlist [join ${%TYPE%::Snit_methods} ", "] set optlist [linsert $optlist "end-1" "or"] error "bad option \"$method\": must be $optlist" } eval [linsert $args 0 \ %TYPE%::Snit_method$method %TYPE% %SELFNS% %WIN% $self] } #======================================================================= # Snit Type Definition # # These are the procs used to define Snit types, widgets, and # widgetadaptors. #----------------------------------------------------------------------- # Snit Compilation Variables # # The following variables are used while Snit is compiling a type, # and are disposed afterwards. namespace eval ::snit:: { # The compiler variable contains the name of the slave interpreter # used to compile type definitions. variable compiler "" # The compile array accumulates information about the type or # widgettype being compiled. It is cleared before and after each # compilation. It has these indices: # # type: The name of the type being compiled, for use # in compilation procs. # defs: Compiled definitions, both standard and client. # which: type, widget, widgetadaptor # instancevars: Instance variable definitions and initializations. # ivprocdec: Instance variable proc declarations. # tvprocdec: Type variable proc declarations. # typeconstructor: Type constructor body. # widgetclass: The widgetclass, for snit::widgets, only # hasoptions: False, initially; set to true when first # option is defined. # localoptions: Names of local options. # delegatedoptions: Names of delegated options. # localmethods: Names of locally defined methods. # delegatesmethods: no if no delegated methods, yes otherwise. # hashierarchic : no if no hierarchic methods, yes otherwise. # components: Names of defined components. # typecomponents: Names of defined typecomponents. # typevars: Typevariable definitions and initializations. # varnames: Names of instance variables # typevarnames Names of type variables # hasconstructor False, initially; true when constructor is # defined. # resource-$opt The option's resource name # class-$opt The option's class # -default-$opt The option's default value # -validatemethod-$opt The option's validate method # -configuremethod-$opt The option's configure method # -cgetmethod-$opt The option's cget method. # -hastypeinfo The -hastypeinfo pragma # -hastypedestroy The -hastypedestroy pragma # -hastypemethods The -hastypemethods pragma # -hasinfo The -hasinfo pragma # -hasinstances The -hasinstances pragma # -simpledispatch The -simpledispatch pragma # -canreplace The -canreplace pragma variable compile # This variable accumulates method dispatch information; it has # the same structure as the %TYPE%::Snit_methodInfo array, and is # used to initialize it. variable methodInfo # This variable accumulates typemethod dispatch information; it has # the same structure as the %TYPE%::Snit_typemethodInfo array, and is # used to initialize it. variable typemethodInfo # The following variable lists the reserved type definition statement # names, e.g., the names you can't use as macros. It's built at # compiler definition time using "info commands". variable reservedwords {} } #----------------------------------------------------------------------- # type compilation commands # # The type and widgettype commands use a slave interpreter to compile # the type definition. These are the procs # that are aliased into it. # Initialize the compiler proc ::snit::Comp.Init {} { variable compiler variable reservedwords if {"" == $compiler} { # Create the compiler's interpreter set compiler [interp create] # Initialize the interpreter $compiler eval { # Load package information # TBD: see if this can be moved outside. # @mdgen NODEP: ::snit::__does_not_exist__ catch {package require ::snit::__does_not_exist__} # Protect some Tcl commands our type definitions # will shadow. rename proc _proc rename variable _variable } # Define compilation aliases. $compiler alias pragma ::snit::Comp.statement.pragma $compiler alias widgetclass ::snit::Comp.statement.widgetclass $compiler alias hulltype ::snit::Comp.statement.hulltype $compiler alias constructor ::snit::Comp.statement.constructor $compiler alias destructor ::snit::Comp.statement.destructor $compiler alias option ::snit::Comp.statement.option $compiler alias oncget ::snit::Comp.statement.oncget $compiler alias onconfigure ::snit::Comp.statement.onconfigure $compiler alias method ::snit::Comp.statement.method $compiler alias typemethod ::snit::Comp.statement.typemethod $compiler alias typeconstructor ::snit::Comp.statement.typeconstructor $compiler alias proc ::snit::Comp.statement.proc $compiler alias typevariable ::snit::Comp.statement.typevariable $compiler alias variable ::snit::Comp.statement.variable $compiler alias typecomponent ::snit::Comp.statement.typecomponent $compiler alias component ::snit::Comp.statement.component $compiler alias delegate ::snit::Comp.statement.delegate $compiler alias expose ::snit::Comp.statement.expose # Get the list of reserved words set reservedwords [$compiler eval {info commands}] } } # Compile a type definition, and return the results as a list of two # items: the fully-qualified type name, and a script that will define # the type when executed. # # which type, widget, or widgetadaptor # type the type name # body the type definition proc ::snit::Comp.Compile {which type body} { variable typeTemplate variable nominalTypeProc variable simpleTypeProc variable compile variable compiler variable methodInfo variable typemethodInfo # FIRST, qualify the name. if {![string match "::*" $type]} { # Get caller's namespace; # append :: if not global namespace. set ns [uplevel 2 [list namespace current]] if {"::" != $ns} { append ns "::" } set type "$ns$type" } # NEXT, create and initialize the compiler, if needed. Comp.Init # NEXT, initialize the class data array unset methodInfo array unset typemethodInfo array unset compile set compile(type) $type set compile(defs) {} set compile(which) $which set compile(hasoptions) no set compile(localoptions) {} set compile(instancevars) {} set compile(typevars) {} set compile(delegatedoptions) {} set compile(ivprocdec) {} set compile(tvprocdec) {} set compile(typeconstructor) {} set compile(widgetclass) {} set compile(hulltype) {} set compile(localmethods) {} set compile(delegatesmethods) no set compile(hashierarchic) no set compile(components) {} set compile(typecomponents) {} set compile(varnames) {} set compile(typevarnames) {} set compile(hasconstructor) no set compile(-hastypedestroy) yes set compile(-hastypeinfo) yes set compile(-hastypemethods) yes set compile(-hasinfo) yes set compile(-hasinstances) yes set compile(-simpledispatch) no set compile(-canreplace) no set isWidget [string match widget* $which] set isWidgetAdaptor [string match widgetadaptor $which] # NEXT, Evaluate the type's definition in the class interpreter. $compiler eval $body # NEXT, Add the standard definitions append compile(defs) \ "\nset %TYPE%::Snit_info(isWidget) $isWidget\n" append compile(defs) \ "\nset %TYPE%::Snit_info(isWidgetAdaptor) $isWidgetAdaptor\n" # Indicate whether the type can create instances that replace # existing commands. append compile(defs) "\nset %TYPE%::Snit_info(canreplace) $compile(-canreplace)\n" # Check pragmas for conflict. if {!$compile(-hastypemethods) && !$compile(-hasinstances)} { error "$which $type has neither typemethods nor instances" } if {$compile(-simpledispatch) && $compile(delegatesmethods)} { error "$which $type requests -simpledispatch but delegates methods." } if {$compile(-simpledispatch) && $compile(hashierarchic)} { error "$which $type requests -simpledispatch but defines hierarchical methods." } # If there are typemethods, define the standard typemethods and # the nominal type proc. Otherwise define the simple type proc. if {$compile(-hastypemethods)} { # Add the info typemethod unless the pragma forbids it. if {$compile(-hastypeinfo)} { Comp.statement.delegate typemethod info \ using {::snit::RT.typemethod.info %t} } # Add the destroy typemethod unless the pragma forbids it. if {$compile(-hastypedestroy)} { Comp.statement.delegate typemethod destroy \ using {::snit::RT.typemethod.destroy %t} } # Add the nominal type proc. append compile(defs) $nominalTypeProc } else { # Add the simple type proc. append compile(defs) $simpleTypeProc } # Add standard methods/typemethods that only make sense if the # type has instances. if {$compile(-hasinstances)} { # If we're using simple dispatch, remember that. if {$compile(-simpledispatch)} { append compile(defs) "\nset %TYPE%::Snit_info(simpledispatch) 1\n" } # Add the info method unless the pragma forbids it. if {$compile(-hasinfo)} { if {!$compile(-simpledispatch)} { Comp.statement.delegate method info \ using {::snit::RT.method.info %t %n %w %s} } else { Comp.statement.method info {args} { eval [linsert $args 0 \ ::snit::RT.method.info $type $selfns $win $self] } } } # Add the option handling stuff if there are any options. if {$compile(hasoptions)} { Comp.statement.variable options if {!$compile(-simpledispatch)} { Comp.statement.delegate method cget \ using {::snit::RT.method.cget %t %n %w %s} Comp.statement.delegate method configurelist \ using {::snit::RT.method.configurelist %t %n %w %s} Comp.statement.delegate method configure \ using {::snit::RT.method.configure %t %n %w %s} } else { Comp.statement.method cget {args} { eval [linsert $args 0 \ ::snit::RT.method.cget $type $selfns $win $self] } Comp.statement.method configurelist {args} { eval [linsert $args 0 \ ::snit::RT.method.configurelist $type $selfns $win $self] } Comp.statement.method configure {args} { eval [linsert $args 0 \ ::snit::RT.method.configure $type $selfns $win $self] } } } # Add a default constructor, if they haven't already defined one. # If there are options, it will configure args; otherwise it # will do nothing. if {!$compile(hasconstructor)} { if {$compile(hasoptions)} { Comp.statement.constructor {args} { $self configurelist $args } } else { Comp.statement.constructor {} {} } } if {!$isWidget} { if {!$compile(-simpledispatch)} { Comp.statement.delegate method destroy \ using {::snit::RT.method.destroy %t %n %w %s} } else { Comp.statement.method destroy {args} { eval [linsert $args 0 \ ::snit::RT.method.destroy $type $selfns $win $self] } } Comp.statement.delegate typemethod create \ using {::snit::RT.type.typemethod.create %t} } else { Comp.statement.delegate typemethod create \ using {::snit::RT.widget.typemethod.create %t} } # Save the list of method names, for -simpledispatch; otherwise, # save the method info. if {$compile(-simpledispatch)} { append compile(defs) \ "\nset %TYPE%::Snit_methods [list $compile(localmethods)]\n" } else { append compile(defs) \ "\narray set %TYPE%::Snit_methodInfo [list [array get methodInfo]]\n" } } else { append compile(defs) "\nset %TYPE%::Snit_info(hasinstances) 0\n" } # NEXT, compiling the type definition built up a set of information # about the type's locally defined options; add this information to # the compiled definition. Comp.SaveOptionInfo # NEXT, compiling the type definition built up a set of information # about the typemethods; save the typemethod info. append compile(defs) \ "\narray set %TYPE%::Snit_typemethodInfo [list [array get typemethodInfo]]\n" # NEXT, if this is a widget define the hull component if it isn't # already defined. if {$isWidget} { Comp.DefineComponent hull } # NEXT, substitute the compiled definition into the type template # to get the type definition script. set defscript [Expand $typeTemplate \ %COMPILEDDEFS% $compile(defs)] # NEXT, substitute the defined macros into the type definition script. # This is done as a separate step so that the compile(defs) can # contain the macros defined below. set defscript [Expand $defscript \ %TYPE% $type \ %IVARDECS% $compile(ivprocdec) \ %TVARDECS% $compile(tvprocdec) \ %TCONSTBODY% $compile(typeconstructor) \ %INSTANCEVARS% $compile(instancevars) \ %TYPEVARS% $compile(typevars) \ ] array unset compile return [list $type $defscript] } # Information about locally-defined options is accumulated during # compilation, but not added to the compiled definition--the option # statement can appear multiple times, so it's easier this way. # This proc fills in Snit_optionInfo with the accumulated information. # # It also computes the option's resource and class names if needed. # # Note that the information for delegated options was put in # Snit_optionInfo during compilation. proc ::snit::Comp.SaveOptionInfo {} { variable compile foreach option $compile(localoptions) { if {"" == $compile(resource-$option)} { set compile(resource-$option) [string range $option 1 end] } if {"" == $compile(class-$option)} { set compile(class-$option) [Capitalize $compile(resource-$option)] } # NOTE: Don't verify that the validate, configure, and cget # values name real methods; the methods might be defined outside # the typedefinition using snit::method. Mappend compile(defs) { # Option %OPTION% lappend %TYPE%::Snit_optionInfo(local) %OPTION% set %TYPE%::Snit_optionInfo(islocal-%OPTION%) 1 set %TYPE%::Snit_optionInfo(resource-%OPTION%) %RESOURCE% set %TYPE%::Snit_optionInfo(class-%OPTION%) %CLASS% set %TYPE%::Snit_optionInfo(default-%OPTION%) %DEFAULT% set %TYPE%::Snit_optionInfo(validate-%OPTION%) %VALIDATE% set %TYPE%::Snit_optionInfo(configure-%OPTION%) %CONFIGURE% set %TYPE%::Snit_optionInfo(cget-%OPTION%) %CGET% set %TYPE%::Snit_optionInfo(readonly-%OPTION%) %READONLY% set %TYPE%::Snit_optionInfo(typespec-%OPTION%) %TYPESPEC% } %OPTION% $option \ %RESOURCE% $compile(resource-$option) \ %CLASS% $compile(class-$option) \ %DEFAULT% [list $compile(-default-$option)] \ %VALIDATE% [list $compile(-validatemethod-$option)] \ %CONFIGURE% [list $compile(-configuremethod-$option)] \ %CGET% [list $compile(-cgetmethod-$option)] \ %READONLY% $compile(-readonly-$option) \ %TYPESPEC% [list $compile(-type-$option)] } } # Evaluates a compiled type definition, thus making the type available. proc ::snit::Comp.Define {compResult} { # The compilation result is a list containing the fully qualified # type name and a script to evaluate to define the type. set type [lindex $compResult 0] set defscript [lindex $compResult 1] # Execute the type definition script. # Consider using namespace eval %TYPE%. See if it's faster. if {[catch {eval $defscript} result]} { namespace delete $type catch {rename $type ""} error $result } return $type } # Sets pragma options which control how the type is defined. proc ::snit::Comp.statement.pragma {args} { variable compile set errRoot "Error in \"pragma...\"" foreach {opt val} $args { switch -exact -- $opt { -hastypeinfo - -hastypedestroy - -hastypemethods - -hasinstances - -simpledispatch - -hasinfo - -canreplace { if {![string is boolean -strict $val]} { error "$errRoot, \"$opt\" requires a boolean value" } set compile($opt) $val } default { error "$errRoot, unknown pragma" } } } } # Defines a widget's option class name. # This statement is only available for snit::widgets, # not for snit::types or snit::widgetadaptors. proc ::snit::Comp.statement.widgetclass {name} { variable compile # First, widgetclass can only be set for true widgets if {"widget" != $compile(which)} { error "widgetclass cannot be set for snit::$compile(which)s" } # Next, validate the option name. We'll require that it begin # with an uppercase letter. set initial [string index $name 0] if {![string is upper $initial]} { error "widgetclass \"$name\" does not begin with an uppercase letter" } if {"" != $compile(widgetclass)} { error "too many widgetclass statements" } # Next, save it. Mappend compile(defs) { set %TYPE%::Snit_info(widgetclass) %WIDGETCLASS% } %WIDGETCLASS% [list $name] set compile(widgetclass) $name } # Defines a widget's hull type. # This statement is only available for snit::widgets, # not for snit::types or snit::widgetadaptors. proc ::snit::Comp.statement.hulltype {name} { variable compile variable hulltypes # First, hulltype can only be set for true widgets if {"widget" != $compile(which)} { error "hulltype cannot be set for snit::$compile(which)s" } # Next, it must be one of the valid hulltypes (frame, toplevel, ...) if {[lsearch -exact $hulltypes [string trimleft $name :]] == -1} { error "invalid hulltype \"$name\", should be one of\ [join $hulltypes {, }]" } if {"" != $compile(hulltype)} { error "too many hulltype statements" } # Next, save it. Mappend compile(defs) { set %TYPE%::Snit_info(hulltype) %HULLTYPE% } %HULLTYPE% $name set compile(hulltype) $name } # Defines a constructor. proc ::snit::Comp.statement.constructor {arglist body} { variable compile CheckArgs "constructor" $arglist # Next, add a magic reference to self. set arglist [concat type selfns win self $arglist] # Next, add variable declarations to body: set body "%TVARDECS%%IVARDECS%\n$body" set compile(hasconstructor) yes append compile(defs) "proc %TYPE%::Snit_constructor [list $arglist] [list $body]\n" } # Defines a destructor. proc ::snit::Comp.statement.destructor {body} { variable compile # Next, add variable declarations to body: set body "%TVARDECS%%IVARDECS%\n$body" append compile(defs) "proc %TYPE%::Snit_destructor {type selfns win self} [list $body]\n\n" } # Defines a type option. The option value can be a triple, specifying # the option's -name, resource name, and class name. proc ::snit::Comp.statement.option {optionDef args} { variable compile # First, get the three option names. set option [lindex $optionDef 0] set resourceName [lindex $optionDef 1] set className [lindex $optionDef 2] set errRoot "Error in \"option [list $optionDef]...\"" # Next, validate the option name. if {![Comp.OptionNameIsValid $option]} { error "$errRoot, badly named option \"$option\"" } if {[Contains $option $compile(delegatedoptions)]} { error "$errRoot, cannot define \"$option\" locally, it has been delegated" } if {![Contains $option $compile(localoptions)]} { # Remember that we've seen this one. set compile(hasoptions) yes lappend compile(localoptions) $option # Initialize compilation info for this option. set compile(resource-$option) "" set compile(class-$option) "" set compile(-default-$option) "" set compile(-validatemethod-$option) "" set compile(-configuremethod-$option) "" set compile(-cgetmethod-$option) "" set compile(-readonly-$option) 0 set compile(-type-$option) "" } # NEXT, see if we have a resource name. If so, make sure it # isn't being redefined differently. if {"" != $resourceName} { if {"" == $compile(resource-$option)} { # If it's undefined, just save the value. set compile(resource-$option) $resourceName } elseif {![string equal $resourceName $compile(resource-$option)]} { # It's been redefined differently. error "$errRoot, resource name redefined from \"$compile(resource-$option)\" to \"$resourceName\"" } } # NEXT, see if we have a class name. If so, make sure it # isn't being redefined differently. if {"" != $className} { if {"" == $compile(class-$option)} { # If it's undefined, just save the value. set compile(class-$option) $className } elseif {![string equal $className $compile(class-$option)]} { # It's been redefined differently. error "$errRoot, class name redefined from \"$compile(class-$option)\" to \"$className\"" } } # NEXT, handle the args; it's not an error to redefine these. if {[llength $args] == 1} { set compile(-default-$option) [lindex $args 0] } else { foreach {optopt val} $args { switch -exact -- $optopt { -default - -validatemethod - -configuremethod - -cgetmethod { set compile($optopt-$option) $val } -type { set compile($optopt-$option) $val if {[llength $val] == 1} { # The type spec *is* the validation object append compile(defs) \ "\nset %TYPE%::Snit_optionInfo(typeobj-$option) [list $val]\n" } else { # Compilation the creation of the validation object set cmd [linsert $val 1 %TYPE%::Snit_TypeObj_%AUTO%] append compile(defs) \ "\nset %TYPE%::Snit_optionInfo(typeobj-$option) \[$cmd\]\n" } } -readonly { if {![string is boolean -strict $val]} { error "$errRoot, -readonly requires a boolean, got \"$val\"" } set compile($optopt-$option) $val } default { error "$errRoot, unknown option definition option \"$optopt\"" } } } } } # 1 if the option name is valid, 0 otherwise. proc ::snit::Comp.OptionNameIsValid {option} { if {![string match {-*} $option] || [string match {*[A-Z ]*} $option]} { return 0 } return 1 } # Defines an option's cget handler proc ::snit::Comp.statement.oncget {option body} { variable compile set errRoot "Error in \"oncget $option...\"" if {[lsearch -exact $compile(delegatedoptions) $option] != -1} { return -code error "$errRoot, option \"$option\" is delegated" } if {[lsearch -exact $compile(localoptions) $option] == -1} { return -code error "$errRoot, option \"$option\" unknown" } Comp.statement.method _cget$option {_option} $body Comp.statement.option $option -cgetmethod _cget$option } # Defines an option's configure handler. proc ::snit::Comp.statement.onconfigure {option arglist body} { variable compile if {[lsearch -exact $compile(delegatedoptions) $option] != -1} { return -code error "onconfigure $option: option \"$option\" is delegated" } if {[lsearch -exact $compile(localoptions) $option] == -1} { return -code error "onconfigure $option: option \"$option\" unknown" } if {[llength $arglist] != 1} { error \ "onconfigure $option handler should have one argument, got \"$arglist\"" } CheckArgs "onconfigure $option" $arglist # Next, add a magic reference to the option name set arglist [concat _option $arglist] Comp.statement.method _configure$option $arglist $body Comp.statement.option $option -configuremethod _configure$option } # Defines an instance method. proc ::snit::Comp.statement.method {method arglist body} { variable compile variable methodInfo # FIRST, check the method name against previously defined # methods. Comp.CheckMethodName $method 0 ::snit::methodInfo \ "Error in \"method [list $method]...\"" if {[llength $method] > 1} { set compile(hashierarchic) yes } # Remeber this method lappend compile(localmethods) $method CheckArgs "method [list $method]" $arglist # Next, add magic references to type and self. set arglist [concat type selfns win self $arglist] # Next, add variable declarations to body: set body "%TVARDECS%%IVARDECS%\n# END snit method prolog\n$body" # Next, save the definition script. if {[llength $method] == 1} { set methodInfo($method) {0 "%t::Snit_method%m %t %n %w %s" ""} Mappend compile(defs) { proc %TYPE%::Snit_method%METHOD% %ARGLIST% %BODY% } %METHOD% $method %ARGLIST% [list $arglist] %BODY% [list $body] } else { set methodInfo($method) {0 "%t::Snit_hmethod%j %t %n %w %s" ""} Mappend compile(defs) { proc %TYPE%::Snit_hmethod%JMETHOD% %ARGLIST% %BODY% } %JMETHOD% [join $method _] %ARGLIST% [list $arglist] \ %BODY% [list $body] } } # Check for name collisions; save prefix information. # # method The name of the method or typemethod. # delFlag 1 if delegated, 0 otherwise. # infoVar The fully qualified name of the array containing # information about the defined methods. # errRoot The root string for any error messages. proc ::snit::Comp.CheckMethodName {method delFlag infoVar errRoot} { upvar $infoVar methodInfo # FIRST, make sure the method name is a valid Tcl list. if {[catch {lindex $method 0}]} { error "$errRoot, the name \"$method\" must have list syntax." } # NEXT, check whether we can define it. if {![catch {set methodInfo($method)} data]} { # We can't redefine methods with submethods. if {[lindex $data 0] == 1} { error "$errRoot, \"$method\" has submethods." } # You can't delegate a method that's defined locally, # and you can't define a method locally if it's been delegated. if {$delFlag && "" == [lindex $data 2]} { error "$errRoot, \"$method\" has been defined locally." } elseif {!$delFlag && "" != [lindex $data 2]} { error "$errRoot, \"$method\" has been delegated" } } # Handle hierarchical case. if {[llength $method] > 1} { set prefix {} set tokens $method while {[llength $tokens] > 1} { lappend prefix [lindex $tokens 0] set tokens [lrange $tokens 1 end] if {![catch {set methodInfo($prefix)} result]} { # Prefix is known. If it's not a prefix, throw an # error. if {[lindex $result 0] == 0} { error "$errRoot, \"$prefix\" has no submethods." } } set methodInfo($prefix) [list 1] } } } # Defines a typemethod method. proc ::snit::Comp.statement.typemethod {method arglist body} { variable compile variable typemethodInfo # FIRST, check the typemethod name against previously defined # typemethods. Comp.CheckMethodName $method 0 ::snit::typemethodInfo \ "Error in \"typemethod [list $method]...\"" CheckArgs "typemethod $method" $arglist # First, add magic reference to type. set arglist [concat type $arglist] # Next, add typevariable declarations to body: set body "%TVARDECS%\n# END snit method prolog\n$body" # Next, save the definition script if {[llength $method] == 1} { set typemethodInfo($method) {0 "%t::Snit_typemethod%m %t" ""} Mappend compile(defs) { proc %TYPE%::Snit_typemethod%METHOD% %ARGLIST% %BODY% } %METHOD% $method %ARGLIST% [list $arglist] %BODY% [list $body] } else { set typemethodInfo($method) {0 "%t::Snit_htypemethod%j %t" ""} Mappend compile(defs) { proc %TYPE%::Snit_htypemethod%JMETHOD% %ARGLIST% %BODY% } %JMETHOD% [join $method _] \ %ARGLIST% [list $arglist] %BODY% [list $body] } } # Defines a type constructor. proc ::snit::Comp.statement.typeconstructor {body} { variable compile if {"" != $compile(typeconstructor)} { error "too many typeconstructors" } set compile(typeconstructor) $body } # Defines a static proc in the type's namespace. proc ::snit::Comp.statement.proc {proc arglist body} { variable compile # If "ns" is defined, the proc can see instance variables. if {[lsearch -exact $arglist selfns] != -1} { # Next, add instance variable declarations to body: set body "%IVARDECS%\n$body" } # The proc can always see typevariables. set body "%TVARDECS%\n$body" append compile(defs) " # Proc $proc proc [list %TYPE%::$proc $arglist $body] " } # Defines a static variable in the type's namespace. proc ::snit::Comp.statement.typevariable {name args} { variable compile set errRoot "Error in \"typevariable $name...\"" set len [llength $args] if {$len > 2 || ($len == 2 && "-array" != [lindex $args 0])} { error "$errRoot, too many initializers" } if {[lsearch -exact $compile(varnames) $name] != -1} { error "$errRoot, \"$name\" is already an instance variable" } lappend compile(typevarnames) $name if {$len == 1} { append compile(typevars) \ "\n\t [list ::variable $name [lindex $args 0]]" } elseif {$len == 2} { append compile(typevars) \ "\n\t [list ::variable $name]" append compile(typevars) \ "\n\t [list array set $name [lindex $args 1]]" } else { append compile(typevars) \ "\n\t [list ::variable $name]" } append compile(tvprocdec) "\n\t typevariable ${name}" } # Defines an instance variable; the definition will go in the # type's create typemethod. proc ::snit::Comp.statement.variable {name args} { variable compile set errRoot "Error in \"variable $name...\"" set len [llength $args] if {$len > 2 || ($len == 2 && "-array" != [lindex $args 0])} { error "$errRoot, too many initializers" } if {[lsearch -exact $compile(typevarnames) $name] != -1} { error "$errRoot, \"$name\" is already a typevariable" } lappend compile(varnames) $name if {$len == 1} { append compile(instancevars) \ "\nset \${selfns}::$name [list [lindex $args 0]]\n" } elseif {$len == 2} { append compile(instancevars) \ "\narray set \${selfns}::$name [list [lindex $args 1]]\n" } append compile(ivprocdec) "\n\t " Mappend compile(ivprocdec) {::variable ${selfns}::%N} %N $name } # Defines a typecomponent, and handles component options. # # component The logical name of the delegate # args options. proc ::snit::Comp.statement.typecomponent {component args} { variable compile set errRoot "Error in \"typecomponent $component...\"" # FIRST, define the component Comp.DefineTypecomponent $component $errRoot # NEXT, handle the options. set publicMethod "" set inheritFlag 0 foreach {opt val} $args { switch -exact -- $opt { -public { set publicMethod $val } -inherit { set inheritFlag $val if {![string is boolean $inheritFlag]} { error "typecomponent $component -inherit: expected boolean value, got \"$val\"" } } default { error "typecomponent $component: Invalid option \"$opt\"" } } } # NEXT, if -public specified, define the method. if {"" != $publicMethod} { Comp.statement.delegate typemethod [list $publicMethod *] to $component } # NEXT, if "-inherit 1" is specified, delegate typemethod * to # this component. if {$inheritFlag} { Comp.statement.delegate typemethod "*" to $component } } # Defines a name to be a typecomponent # # The name becomes a typevariable; in addition, it gets a # write trace so that when it is set, all of the component mechanisms # get updated. # # component The component name proc ::snit::Comp.DefineTypecomponent {component {errRoot "Error"}} { variable compile if {[lsearch -exact $compile(varnames) $component] != -1} { error "$errRoot, \"$component\" is already an instance variable" } if {[lsearch -exact $compile(typecomponents) $component] == -1} { # Remember we've done this. lappend compile(typecomponents) $component # Make it a type variable with no initial value Comp.statement.typevariable $component "" # Add a write trace to do the component thing. Mappend compile(typevars) { trace add variable %COMP% write \ [list ::snit::RT.TypecomponentTrace [list %TYPE%] %COMP%] } %TYPE% $compile(type) %COMP% $component } } # Defines a component, and handles component options. # # component The logical name of the delegate # args options. # # TBD: Ideally, it should be possible to call this statement multiple # times, possibly changing the option values. To do that, I'd need # to cache the option values and not act on them until *after* I'd # read the entire type definition. proc ::snit::Comp.statement.component {component args} { variable compile set errRoot "Error in \"component $component...\"" # FIRST, define the component Comp.DefineComponent $component $errRoot # NEXT, handle the options. set publicMethod "" set inheritFlag 0 foreach {opt val} $args { switch -exact -- $opt { -public { set publicMethod $val } -inherit { set inheritFlag $val if {![string is boolean $inheritFlag]} { error "component $component -inherit: expected boolean value, got \"$val\"" } } default { error "component $component: Invalid option \"$opt\"" } } } # NEXT, if -public specified, define the method. if {"" != $publicMethod} { Comp.statement.delegate method [list $publicMethod *] to $component } # NEXT, if -inherit is specified, delegate method/option * to # this component. if {$inheritFlag} { Comp.statement.delegate method "*" to $component Comp.statement.delegate option "*" to $component } } # Defines a name to be a component # # The name becomes an instance variable; in addition, it gets a # write trace so that when it is set, all of the component mechanisms # get updated. # # component The component name proc ::snit::Comp.DefineComponent {component {errRoot "Error"}} { variable compile if {[lsearch -exact $compile(typevarnames) $component] != -1} { error "$errRoot, \"$component\" is already a typevariable" } if {[lsearch -exact $compile(components) $component] == -1} { # Remember we've done this. lappend compile(components) $component # Make it an instance variable with no initial value Comp.statement.variable $component "" # Add a write trace to do the component thing. Mappend compile(instancevars) { trace add variable ${selfns}::%COMP% write \ [list ::snit::RT.ComponentTrace [list %TYPE%] $selfns %COMP%] } %TYPE% $compile(type) %COMP% $component } } # Creates a delegated method, typemethod, or option. proc ::snit::Comp.statement.delegate {what name args} { # FIRST, dispatch to correct handler. switch $what { typemethod { Comp.DelegatedTypemethod $name $args } method { Comp.DelegatedMethod $name $args } option { Comp.DelegatedOption $name $args } default { error "Error in \"delegate $what $name...\", \"$what\"?" } } if {([llength $args] % 2) != 0} { error "Error in \"delegate $what $name...\", invalid syntax" } } # Creates a delegated typemethod delegating it to a particular # typecomponent or an arbitrary command. # # method The name of the method # arglist Delegation options proc ::snit::Comp.DelegatedTypemethod {method arglist} { variable compile variable typemethodInfo set errRoot "Error in \"delegate typemethod [list $method]...\"" # Next, parse the delegation options. set component "" set target "" set exceptions {} set pattern "" set methodTail [lindex $method end] foreach {opt value} $arglist { switch -exact $opt { to { set component $value } as { set target $value } except { set exceptions $value } using { set pattern $value } default { error "$errRoot, unknown delegation option \"$opt\"" } } } if {"" == $component && "" == $pattern} { error "$errRoot, missing \"to\"" } if {"*" == $methodTail && "" != $target} { error "$errRoot, cannot specify \"as\" with \"*\"" } if {"*" != $methodTail && "" != $exceptions} { error "$errRoot, can only specify \"except\" with \"*\"" } if {"" != $pattern && "" != $target} { error "$errRoot, cannot specify both \"as\" and \"using\"" } foreach token [lrange $method 1 end-1] { if {"*" == $token} { error "$errRoot, \"*\" must be the last token." } } # NEXT, define the component if {"" != $component} { Comp.DefineTypecomponent $component $errRoot } # NEXT, define the pattern. if {"" == $pattern} { if {"*" == $methodTail} { set pattern "%c %m" } elseif {"" != $target} { set pattern "%c $target" } else { set pattern "%c %m" } } # Make sure the pattern is a valid list. if {[catch {lindex $pattern 0} result]} { error "$errRoot, the using pattern, \"$pattern\", is not a valid list" } # NEXT, check the method name against previously defined # methods. Comp.CheckMethodName $method 1 ::snit::typemethodInfo $errRoot set typemethodInfo($method) [list 0 $pattern $component] if {[string equal $methodTail "*"]} { Mappend compile(defs) { set %TYPE%::Snit_info(excepttypemethods) %EXCEPT% } %EXCEPT% [list $exceptions] } } # Creates a delegated method delegating it to a particular # component or command. # # method The name of the method # arglist Delegation options. proc ::snit::Comp.DelegatedMethod {method arglist} { variable compile variable methodInfo set errRoot "Error in \"delegate method [list $method]...\"" # Next, parse the delegation options. set component "" set target "" set exceptions {} set pattern "" set methodTail [lindex $method end] foreach {opt value} $arglist { switch -exact $opt { to { set component $value } as { set target $value } except { set exceptions $value } using { set pattern $value } default { error "$errRoot, unknown delegation option \"$opt\"" } } } if {"" == $component && "" == $pattern} { error "$errRoot, missing \"to\"" } if {"*" == $methodTail && "" != $target} { error "$errRoot, cannot specify \"as\" with \"*\"" } if {"*" != $methodTail && "" != $exceptions} { error "$errRoot, can only specify \"except\" with \"*\"" } if {"" != $pattern && "" != $target} { error "$errRoot, cannot specify both \"as\" and \"using\"" } foreach token [lrange $method 1 end-1] { if {"*" == $token} { error "$errRoot, \"*\" must be the last token." } } # NEXT, we delegate some methods set compile(delegatesmethods) yes # NEXT, define the component. Allow typecomponents. if {"" != $component} { if {[lsearch -exact $compile(typecomponents) $component] == -1} { Comp.DefineComponent $component $errRoot } } # NEXT, define the pattern. if {"" == $pattern} { if {"*" == $methodTail} { set pattern "%c %m" } elseif {"" != $target} { set pattern "%c $target" } else { set pattern "%c %m" } } # Make sure the pattern is a valid list. if {[catch {lindex $pattern 0} result]} { error "$errRoot, the using pattern, \"$pattern\", is not a valid list" } # NEXT, check the method name against previously defined # methods. Comp.CheckMethodName $method 1 ::snit::methodInfo $errRoot # NEXT, save the method info. set methodInfo($method) [list 0 $pattern $component] if {[string equal $methodTail "*"]} { Mappend compile(defs) { set %TYPE%::Snit_info(exceptmethods) %EXCEPT% } %EXCEPT% [list $exceptions] } } # Creates a delegated option, delegating it to a particular # component and, optionally, to a particular option of that # component. # # optionDef The option definition # args definition arguments. proc ::snit::Comp.DelegatedOption {optionDef arglist} { variable compile # First, get the three option names. set option [lindex $optionDef 0] set resourceName [lindex $optionDef 1] set className [lindex $optionDef 2] set errRoot "Error in \"delegate option [list $optionDef]...\"" # Next, parse the delegation options. set component "" set target "" set exceptions {} foreach {opt value} $arglist { switch -exact $opt { to { set component $value } as { set target $value } except { set exceptions $value } default { error "$errRoot, unknown delegation option \"$opt\"" } } } if {"" == $component} { error "$errRoot, missing \"to\"" } if {"*" == $option && "" != $target} { error "$errRoot, cannot specify \"as\" with \"delegate option *\"" } if {"*" != $option && "" != $exceptions} { error "$errRoot, can only specify \"except\" with \"delegate option *\"" } # Next, validate the option name if {"*" != $option} { if {![Comp.OptionNameIsValid $option]} { error "$errRoot, badly named option \"$option\"" } } if {[Contains $option $compile(localoptions)]} { error "$errRoot, \"$option\" has been defined locally" } if {[Contains $option $compile(delegatedoptions)]} { error "$errRoot, \"$option\" is multiply delegated" } # NEXT, define the component Comp.DefineComponent $component $errRoot # Next, define the target option, if not specified. if {![string equal $option "*"] && [string equal $target ""]} { set target $option } # NEXT, save the delegation data. set compile(hasoptions) yes if {![string equal $option "*"]} { lappend compile(delegatedoptions) $option # Next, compute the resource and class names, if they aren't # already defined. if {"" == $resourceName} { set resourceName [string range $option 1 end] } if {"" == $className} { set className [Capitalize $resourceName] } Mappend compile(defs) { set %TYPE%::Snit_optionInfo(islocal-%OPTION%) 0 set %TYPE%::Snit_optionInfo(resource-%OPTION%) %RES% set %TYPE%::Snit_optionInfo(class-%OPTION%) %CLASS% lappend %TYPE%::Snit_optionInfo(delegated) %OPTION% set %TYPE%::Snit_optionInfo(target-%OPTION%) [list %COMP% %TARGET%] lappend %TYPE%::Snit_optionInfo(delegated-%COMP%) %OPTION% } %OPTION% $option \ %COMP% $component \ %TARGET% $target \ %RES% $resourceName \ %CLASS% $className } else { Mappend compile(defs) { set %TYPE%::Snit_optionInfo(starcomp) %COMP% set %TYPE%::Snit_optionInfo(except) %EXCEPT% } %COMP% $component %EXCEPT% [list $exceptions] } } # Exposes a component, effectively making the component's command an # instance method. # # component The logical name of the delegate # "as" sugar; if not "", must be "as" # methodname The desired method name for the component's command, or "" proc ::snit::Comp.statement.expose {component {"as" ""} {methodname ""}} { variable compile # FIRST, define the component Comp.DefineComponent $component # NEXT, define the method just as though it were in the type # definition. if {[string equal $methodname ""]} { set methodname $component } Comp.statement.method $methodname args [Expand { if {[llength $args] == 0} { return $%COMPONENT% } if {[string equal $%COMPONENT% ""]} { error "undefined component \"%COMPONENT%\"" } set cmd [linsert $args 0 $%COMPONENT%] return [uplevel 1 $cmd] } %COMPONENT% $component] } #----------------------------------------------------------------------- # Public commands # Compile a type definition, and return the results as a list of two # items: the fully-qualified type name, and a script that will define # the type when executed. # # which type, widget, or widgetadaptor # type the type name # body the type definition proc ::snit::compile {which type body} { return [Comp.Compile $which $type $body] } proc ::snit::type {type body} { return [Comp.Define [Comp.Compile type $type $body]] } proc ::snit::widget {type body} { return [Comp.Define [Comp.Compile widget $type $body]] } proc ::snit::widgetadaptor {type body} { return [Comp.Define [Comp.Compile widgetadaptor $type $body]] } proc ::snit::typemethod {type method arglist body} { # Make sure the type exists. if {![info exists ${type}::Snit_info]} { error "no such type: \"$type\"" } upvar ${type}::Snit_info Snit_info upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo # FIRST, check the typemethod name against previously defined # typemethods. Comp.CheckMethodName $method 0 ${type}::Snit_typemethodInfo \ "Cannot define \"$method\"" # NEXT, check the arguments CheckArgs "snit::typemethod $type $method" $arglist # Next, add magic reference to type. set arglist [concat type $arglist] # Next, add typevariable declarations to body: set body "$Snit_info(tvardecs)\n$body" # Next, define it. if {[llength $method] == 1} { set Snit_typemethodInfo($method) {0 "%t::Snit_typemethod%m %t" ""} uplevel 1 [list proc ${type}::Snit_typemethod$method $arglist $body] } else { set Snit_typemethodInfo($method) {0 "%t::Snit_htypemethod%j %t" ""} set suffix [join $method _] uplevel 1 [list proc ${type}::Snit_htypemethod$suffix $arglist $body] } } proc ::snit::method {type method arglist body} { # Make sure the type exists. if {![info exists ${type}::Snit_info]} { error "no such type: \"$type\"" } upvar ${type}::Snit_methodInfo Snit_methodInfo upvar ${type}::Snit_info Snit_info # FIRST, check the method name against previously defined # methods. Comp.CheckMethodName $method 0 ${type}::Snit_methodInfo \ "Cannot define \"$method\"" # NEXT, check the arguments CheckArgs "snit::method $type $method" $arglist # Next, add magic references to type and self. set arglist [concat type selfns win self $arglist] # Next, add variable declarations to body: set body "$Snit_info(tvardecs)$Snit_info(ivardecs)\n$body" # Next, define it. if {[llength $method] == 1} { set Snit_methodInfo($method) {0 "%t::Snit_method%m %t %n %w %s" ""} uplevel 1 [list proc ${type}::Snit_method$method $arglist $body] } else { set Snit_methodInfo($method) {0 "%t::Snit_hmethod%j %t %n %w %s" ""} set suffix [join $method _] uplevel 1 [list proc ${type}::Snit_hmethod$suffix $arglist $body] } } # Defines a proc within the compiler; this proc can call other # type definition statements, and thus can be used for meta-programming. proc ::snit::macro {name arglist body} { variable compiler variable reservedwords # FIRST, make sure the compiler is defined. Comp.Init # NEXT, check the macro name against the reserved words if {[lsearch -exact $reservedwords $name] != -1} { error "invalid macro name \"$name\"" } # NEXT, see if the name has a namespace; if it does, define the # namespace. set ns [namespace qualifiers $name] if {"" != $ns} { $compiler eval "namespace eval $ns {}" } # NEXT, define the macro $compiler eval [list _proc $name $arglist $body] } #----------------------------------------------------------------------- # Utility Functions # # These are utility functions used while compiling Snit types. # Builds a template from a tagged list of text blocks, then substitutes # all symbols in the mapTable, returning the expanded template. proc ::snit::Expand {template args} { return [string map $args $template] } # Expands a template and appends it to a variable. proc ::snit::Mappend {varname template args} { upvar $varname myvar append myvar [string map $args $template] } # Checks argument list against reserved args proc ::snit::CheckArgs {which arglist} { variable reservedArgs foreach name $reservedArgs { if {[Contains $name $arglist]} { error "$which's arglist may not contain \"$name\" explicitly" } } } # Returns 1 if a value is in a list, and 0 otherwise. proc ::snit::Contains {value list} { if {[lsearch -exact $list $value] != -1} { return 1 } else { return 0 } } # Capitalizes the first letter of a string. proc ::snit::Capitalize {text} { return [string toupper $text 0] } # Converts an arbitrary white-space-delimited string into a list # by splitting on white-space and deleting empty tokens. proc ::snit::Listify {str} { set result {} foreach token [split [string trim $str]] { if {[string length $token] > 0} { lappend result $token } } return $result } #======================================================================= # Snit Runtime Library # # These are procs used by Snit types and widgets at runtime. #----------------------------------------------------------------------- # Object Creation # Creates a new instance of the snit::type given its name and the args. # # type The snit::type # name The instance name # args Args to pass to the constructor proc ::snit::RT.type.typemethod.create {type name args} { variable ${type}::Snit_info variable ${type}::Snit_optionInfo # FIRST, qualify the name. if {![string match "::*" $name]} { # Get caller's namespace; # append :: if not global namespace. set ns [uplevel 1 [list namespace current]] if {"::" != $ns} { append ns "::" } set name "$ns$name" } # NEXT, if %AUTO% appears in the name, generate a unique # command name. Otherwise, ensure that the name isn't in use. if {[string match "*%AUTO%*" $name]} { set name [::snit::RT.UniqueName Snit_info(counter) $type $name] } elseif {!$Snit_info(canreplace) && [llength [info commands $name]]} { error "command \"$name\" already exists" } # NEXT, create the instance's namespace. set selfns \ [::snit::RT.UniqueInstanceNamespace Snit_info(counter) $type] namespace eval $selfns {} # NEXT, install the dispatcher RT.MakeInstanceCommand $type $selfns $name # Initialize the options to their defaults. upvar ${selfns}::options options foreach opt $Snit_optionInfo(local) { set options($opt) $Snit_optionInfo(default-$opt) } # Initialize the instance vars to their defaults. # selfns must be defined, as it is used implicitly. ${type}::Snit_instanceVars $selfns # Execute the type's constructor. set errcode [catch { RT.ConstructInstance $type $selfns $name $args } result] if {$errcode} { global errorInfo global errorCode set theInfo $errorInfo set theCode $errorCode ::snit::RT.DestroyObject $type $selfns $name error "Error in constructor: $result" $theInfo $theCode } # NEXT, return the object's name. return $name } # Creates a new instance of the snit::widget or snit::widgetadaptor # given its name and the args. # # type The snit::widget or snit::widgetadaptor # name The instance name # args Args to pass to the constructor proc ::snit::RT.widget.typemethod.create {type name args} { variable ${type}::Snit_info variable ${type}::Snit_optionInfo # FIRST, if %AUTO% appears in the name, generate a unique # command name. if {[string match "*%AUTO%*" $name]} { set name [::snit::RT.UniqueName Snit_info(counter) $type $name] } # NEXT, create the instance's namespace. set selfns \ [::snit::RT.UniqueInstanceNamespace Snit_info(counter) $type] namespace eval $selfns { } # NEXT, Initialize the widget's own options to their defaults. upvar ${selfns}::options options foreach opt $Snit_optionInfo(local) { set options($opt) $Snit_optionInfo(default-$opt) } # Initialize the instance vars to their defaults. ${type}::Snit_instanceVars $selfns # NEXT, if this is a normal widget (not a widget adaptor) then create a # frame as its hull. We set the frame's -class to the user's widgetclass, # or, if none, search for -class in the args list, otherwise default to # the basename of the $type with an initial upper case letter. if {!$Snit_info(isWidgetAdaptor)} { # FIRST, determine the class name set wclass $Snit_info(widgetclass) if {$Snit_info(widgetclass) eq ""} { set idx [lsearch -exact $args -class] if {$idx >= 0 && ($idx%2 == 0)} { # -class exists and is in the -option position set wclass [lindex $args [expr {$idx+1}]] set args [lreplace $args $idx [expr {$idx+1}]] } else { set wclass [::snit::Capitalize [namespace tail $type]] } } # NEXT, create the widget set self $name package require Tk ${type}::installhull using $Snit_info(hulltype) -class $wclass # NEXT, let's query the option database for our # widget, now that we know that it exists. foreach opt $Snit_optionInfo(local) { set dbval [RT.OptionDbGet $type $name $opt] if {"" != $dbval} { set options($opt) $dbval } } } # Execute the type's constructor, and verify that it # has a hull. set errcode [catch { RT.ConstructInstance $type $selfns $name $args ::snit::RT.Component $type $selfns hull # Prepare to call the object's destructor when the # event is received. Use a Snit-specific bindtag # so that the widget name's tag is unencumbered. bind Snit$type$name [::snit::Expand { ::snit::RT.DestroyObject %TYPE% %NS% %W } %TYPE% $type %NS% $selfns] # Insert the bindtag into the list of bindtags right # after the widget name. set taglist [bindtags $name] set ndx [lsearch -exact $taglist $name] incr ndx bindtags $name [linsert $taglist $ndx Snit$type$name] } result] if {$errcode} { global errorInfo global errorCode set theInfo $errorInfo set theCode $errorCode ::snit::RT.DestroyObject $type $selfns $name error "Error in constructor: $result" $theInfo $theCode } # NEXT, return the object's name. return $name } # RT.MakeInstanceCommand type selfns instance # # type The object type # selfns The instance namespace # instance The instance name # # Creates the instance proc. proc ::snit::RT.MakeInstanceCommand {type selfns instance} { variable ${type}::Snit_info # FIRST, remember the instance name. The Snit_instance variable # allows the instance to figure out its current name given the # instance namespace. upvar ${selfns}::Snit_instance Snit_instance set Snit_instance $instance # NEXT, qualify the proc name if it's a widget. if {$Snit_info(isWidget)} { set procname ::$instance } else { set procname $instance } # NEXT, install the new proc if {!$Snit_info(simpledispatch)} { set instanceProc $::snit::nominalInstanceProc } else { set instanceProc $::snit::simpleInstanceProc } proc $procname {method args} \ [string map \ [list %SELFNS% $selfns %WIN% $instance %TYPE% $type] \ $instanceProc] # NEXT, add the trace. trace add command $procname {rename delete} \ [list ::snit::RT.InstanceTrace $type $selfns $instance] } # This proc is called when the instance command is renamed. # If op is delete, then new will always be "", so op is redundant. # # type The fully-qualified type name # selfns The instance namespace # win The original instance/tk window name. # old old instance command name # new new instance command name # op rename or delete # # If the op is delete, we need to clean up the object; otherwise, # we need to track the change. # # NOTE: In Tcl 8.4.2 there's a bug: errors in rename and delete # traces aren't propagated correctly. Instead, they silently # vanish. Add a catch to output any error message. proc ::snit::RT.InstanceTrace {type selfns win old new op} { variable ${type}::Snit_info # Note to developers ... # For Tcl 8.4.0, errors thrown in trace handlers vanish silently. # Therefore we catch them here and create some output to help in # debugging such problems. if {[catch { # FIRST, clean up if necessary if {"" == $new} { if {$Snit_info(isWidget)} { destroy $win } else { ::snit::RT.DestroyObject $type $selfns $win } } else { # Otherwise, track the change. variable ${selfns}::Snit_instance set Snit_instance [uplevel 1 [list namespace which -command $new]] # Also, clear the instance caches, as many cached commands # might be invalid. RT.ClearInstanceCaches $selfns } } result]} { global errorInfo # Pop up the console on Windows wish, to enable stdout. # This clobbers errorInfo on unix, so save it so we can print it. set ei $errorInfo catch {console show} puts "Error in ::snit::RT.InstanceTrace $type $selfns $win $old $new $op:" puts $ei } } # Calls the instance constructor and handles related housekeeping. proc ::snit::RT.ConstructInstance {type selfns instance arglist} { variable ${type}::Snit_optionInfo variable ${selfns}::Snit_iinfo # Track whether we are constructed or not. set Snit_iinfo(constructed) 0 # Call the user's constructor eval [linsert $arglist 0 \ ${type}::Snit_constructor $type $selfns $instance $instance] set Snit_iinfo(constructed) 1 # Validate the initial set of options (including defaults) foreach option $Snit_optionInfo(local) { set value [set ${selfns}::options($option)] if {"" != $Snit_optionInfo(typespec-$option)} { if {[catch { $Snit_optionInfo(typeobj-$option) validate $value } result]} { return -code error "invalid $option default: $result" } } } # Unset the configure cache for all -readonly options. # This ensures that the next time anyone tries to # configure it, an error is thrown. foreach opt $Snit_optionInfo(local) { if {$Snit_optionInfo(readonly-$opt)} { unset -nocomplain ${selfns}::Snit_configureCache($opt) } } return } # Returns a unique command name. # # REQUIRE: type is a fully qualified name. # REQUIRE: name contains "%AUTO%" # PROMISE: the returned command name is unused. proc ::snit::RT.UniqueName {countervar type name} { upvar $countervar counter while 1 { # FIRST, bump the counter and define the %AUTO% instance name; # then substitute it into the specified name. Wrap around at # 2^31 - 2 to prevent overflow problems. incr counter if {$counter > 2147483646} { set counter 0 } set auto "[namespace tail $type]$counter" set candidate [Expand $name %AUTO% $auto] if {![llength [info commands $candidate]]} { return $candidate } } } # Returns a unique instance namespace, fully qualified. # # countervar The name of a counter variable # type The instance's type # # REQUIRE: type is fully qualified # PROMISE: The returned namespace name is unused. proc ::snit::RT.UniqueInstanceNamespace {countervar type} { upvar $countervar counter while 1 { # FIRST, bump the counter and define the namespace name. # Then see if it already exists. Wrap around at # 2^31 - 2 to prevent overflow problems. incr counter if {$counter > 2147483646} { set counter 0 } set ins "${type}::Snit_inst${counter}" if {![namespace exists $ins]} { return $ins } } } # Retrieves an option's value from the option database. # Returns "" if no value is found. proc ::snit::RT.OptionDbGet {type self opt} { variable ${type}::Snit_optionInfo return [option get $self \ $Snit_optionInfo(resource-$opt) \ $Snit_optionInfo(class-$opt)] } #----------------------------------------------------------------------- # Object Destruction # Implements the standard "destroy" method # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name proc ::snit::RT.method.destroy {type selfns win self} { variable ${selfns}::Snit_iinfo # Can't destroy the object if it isn't complete constructed. if {!$Snit_iinfo(constructed)} { return -code error "Called 'destroy' method in constructor" } # Calls Snit_cleanup, which (among other things) calls the # user's destructor. ::snit::RT.DestroyObject $type $selfns $win } # This is the function that really cleans up; it's automatically # called when any instance is destroyed, e.g., by "$object destroy" # for types, and by the event for widgets. # # type The fully-qualified type name. # selfns The instance namespace # win The original instance command name. proc ::snit::RT.DestroyObject {type selfns win} { variable ${type}::Snit_info # If the variable Snit_instance doesn't exist then there's no # instance command for this object -- it's most likely a # widgetadaptor. Consequently, there are some things that # we don't need to do. if {[info exists ${selfns}::Snit_instance]} { upvar ${selfns}::Snit_instance instance # First, remove the trace on the instance name, so that we # don't call RT.DestroyObject recursively. RT.RemoveInstanceTrace $type $selfns $win $instance # Next, call the user's destructor ${type}::Snit_destructor $type $selfns $win $instance # Next, if this isn't a widget, delete the instance command. # If it is a widget, get the hull component's name, and rename # it back to the widget name # Next, delete the hull component's instance command, # if there is one. if {$Snit_info(isWidget)} { set hullcmd [::snit::RT.Component $type $selfns hull] catch {rename $instance ""} # Clear the bind event bind Snit$type$win "" if {[llength [info commands $hullcmd]]} { # FIRST, rename the hull back to its original name. # If the hull is itself a megawidget, it will have its # own cleanup to do, and it might not do it properly # if it doesn't have the right name. rename $hullcmd ::$instance # NEXT, destroy it. destroy $instance } } else { catch {rename $instance ""} } } # Next, delete the instance's namespace. This kills any # instance variables. namespace delete $selfns return } # Remove instance trace # # type The fully qualified type name # selfns The instance namespace # win The original instance name/Tk window name # instance The current instance name proc ::snit::RT.RemoveInstanceTrace {type selfns win instance} { variable ${type}::Snit_info if {$Snit_info(isWidget)} { set procname ::$instance } else { set procname $instance } # NEXT, remove any trace on this name catch { trace remove command $procname {rename delete} \ [list ::snit::RT.InstanceTrace $type $selfns $win] } } #----------------------------------------------------------------------- # Typecomponent Management and Method Caching # Typecomponent trace; used for write trace on typecomponent # variables. Saves the new component object name, provided # that certain conditions are met. Also clears the typemethod # cache. proc ::snit::RT.TypecomponentTrace {type component n1 n2 op} { upvar ${type}::Snit_info Snit_info upvar ${type}::${component} cvar upvar ${type}::Snit_typecomponents Snit_typecomponents # Save the new component value. set Snit_typecomponents($component) $cvar # Clear the typemethod cache. # TBD: can we unset just the elements related to # this component? unset -nocomplain -- ${type}::Snit_typemethodCache } # Generates and caches the command for a typemethod. # # type The type # method The name of the typemethod to call. # # The return value is one of the following lists: # # {} There's no such method. # {1} The method has submethods; look again. # {0 } Here's the command to execute. proc snit::RT.CacheTypemethodCommand {type method} { upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo upvar ${type}::Snit_typecomponents Snit_typecomponents upvar ${type}::Snit_typemethodCache Snit_typemethodCache upvar ${type}::Snit_info Snit_info # FIRST, get the pattern data and the typecomponent name. set implicitCreate 0 set instanceName "" set starredMethod [lreplace $method end end *] set methodTail [lindex $method end] if {[info exists Snit_typemethodInfo($method)]} { set key $method } elseif {[info exists Snit_typemethodInfo($starredMethod)]} { if {[lsearch -exact $Snit_info(excepttypemethods) $methodTail] == -1} { set key $starredMethod } else { return [list ] } } elseif {$Snit_info(hasinstances)} { # Assume the unknown name is an instance name to create, unless # this is a widget and the style of the name is wrong, or the # name mimics a standard typemethod. if {[set ${type}::Snit_info(isWidget)] && ![string match ".*" $method]} { return [list ] } # Without this check, the call "$type info" will redefine the # standard "::info" command, with disastrous results. Since it's # a likely thing to do if !-typeinfo, put in an explicit check. if {"info" == $method || "destroy" == $method} { return [list ] } set implicitCreate 1 set instanceName $method set key create set method create } else { return [list ] } foreach {flag pattern compName} $Snit_typemethodInfo($key) {} if {$flag == 1} { return [list 1] } # NEXT, build the substitution list set subList [list \ %% % \ %t $type \ %M $method \ %m [lindex $method end] \ %j [join $method _]] if {"" != $compName} { if {![info exists Snit_typecomponents($compName)]} { error "$type delegates typemethod \"$method\" to undefined typecomponent \"$compName\"" } lappend subList %c [list $Snit_typecomponents($compName)] } set command {} foreach subpattern $pattern { lappend command [string map $subList $subpattern] } if {$implicitCreate} { # In this case, $method is the name of the instance to # create. Don't cache, as we usually won't do this one # again. lappend command $instanceName } else { set Snit_typemethodCache($method) [list 0 $command] } return [list 0 $command] } #----------------------------------------------------------------------- # Component Management and Method Caching # Retrieves the object name given the component name. proc ::snit::RT.Component {type selfns name} { variable ${selfns}::Snit_components if {[catch {set Snit_components($name)} result]} { variable ${selfns}::Snit_instance error "component \"$name\" is undefined in $type $Snit_instance" } return $result } # Component trace; used for write trace on component instance # variables. Saves the new component object name, provided # that certain conditions are met. Also clears the method # cache. proc ::snit::RT.ComponentTrace {type selfns component n1 n2 op} { upvar ${type}::Snit_info Snit_info upvar ${selfns}::${component} cvar upvar ${selfns}::Snit_components Snit_components # If they try to redefine the hull component after # it's been defined, that's an error--but only if # this is a widget or widget adaptor. if {"hull" == $component && $Snit_info(isWidget) && [info exists Snit_components($component)]} { set cvar $Snit_components($component) error "The hull component cannot be redefined" } # Save the new component value. set Snit_components($component) $cvar # Clear the instance caches. # TBD: can we unset just the elements related to # this component? RT.ClearInstanceCaches $selfns } # Generates and caches the command for a method. # # type: The instance's type # selfns: The instance's private namespace # win: The instance's original name (a Tk widget name, for # snit::widgets. # self: The instance's current name. # method: The name of the method to call. # # The return value is one of the following lists: # # {} There's no such method. # {1} The method has submethods; look again. # {0 } Here's the command to execute. proc ::snit::RT.CacheMethodCommand {type selfns win self method} { variable ${type}::Snit_info variable ${type}::Snit_methodInfo variable ${type}::Snit_typecomponents variable ${selfns}::Snit_components variable ${selfns}::Snit_methodCache # FIRST, get the pattern data and the component name. set starredMethod [lreplace $method end end *] set methodTail [lindex $method end] if {[info exists Snit_methodInfo($method)]} { set key $method } elseif {[info exists Snit_methodInfo($starredMethod)] && [lsearch -exact $Snit_info(exceptmethods) $methodTail] == -1} { set key $starredMethod } else { return [list ] } foreach {flag pattern compName} $Snit_methodInfo($key) {} if {$flag == 1} { return [list 1] } # NEXT, build the substitution list set subList [list \ %% % \ %t $type \ %M $method \ %m [lindex $method end] \ %j [join $method _] \ %n [list $selfns] \ %w [list $win] \ %s [list $self]] if {"" != $compName} { if {[info exists Snit_components($compName)]} { set compCmd $Snit_components($compName) } elseif {[info exists Snit_typecomponents($compName)]} { set compCmd $Snit_typecomponents($compName) } else { error "$type $self delegates method \"$method\" to undefined component \"$compName\"" } lappend subList %c [list $compCmd] } # Note: The cached command will executed faster if it's # already a list. set command {} foreach subpattern $pattern { lappend command [string map $subList $subpattern] } set commandRec [list 0 $command] set Snit_methodCache($method) $commandRec return $commandRec } # Looks up a method's command. # # type: The instance's type # selfns: The instance's private namespace # win: The instance's original name (a Tk widget name, for # snit::widgets. # self: The instance's current name. # method: The name of the method to call. # errPrefix: Prefix for any error method proc ::snit::RT.LookupMethodCommand {type selfns win self method errPrefix} { set commandRec [snit::RT.CacheMethodCommand \ $type $selfns $win $self \ $method] if {[llength $commandRec] == 0} { return -code error \ "$errPrefix, \"$self $method\" is not defined" } elseif {[lindex $commandRec 0] == 1} { return -code error \ "$errPrefix, wrong number args: should be \"$self\" $method method args" } return [lindex $commandRec 1] } # Clears all instance command caches proc ::snit::RT.ClearInstanceCaches {selfns} { unset -nocomplain -- ${selfns}::Snit_methodCache unset -nocomplain -- ${selfns}::Snit_cgetCache unset -nocomplain -- ${selfns}::Snit_configureCache unset -nocomplain -- ${selfns}::Snit_validateCache } #----------------------------------------------------------------------- # Component Installation # Implements %TYPE%::installhull. The variables self and selfns # must be defined in the caller's context. # # Installs the named widget as the hull of a # widgetadaptor. Once the widget is hijacked, its new name # is assigned to the hull component. proc ::snit::RT.installhull {type {using "using"} {widgetType ""} args} { variable ${type}::Snit_info variable ${type}::Snit_optionInfo upvar self self upvar selfns selfns upvar ${selfns}::hull hull upvar ${selfns}::options options # FIRST, make sure we can do it. if {!$Snit_info(isWidget)} { error "installhull is valid only for snit::widgetadaptors" } if {[info exists ${selfns}::Snit_instance]} { error "hull already installed for $type $self" } # NEXT, has it been created yet? If not, create it using # the specified arguments. if {"using" == $using} { # FIRST, create the widget set cmd [linsert $args 0 $widgetType $self] set obj [uplevel 1 $cmd] # NEXT, for each option explicitly delegated to the hull # that doesn't appear in the usedOpts list, get the # option database value and apply it--provided that the # real option name and the target option name are different. # (If they are the same, then the option database was # already queried as part of the normal widget creation.) # # Also, we don't need to worry about implicitly delegated # options, as the option and target option names must be # the same. if {[info exists Snit_optionInfo(delegated-hull)]} { # FIRST, extract all option names from args set usedOpts {} set ndx [lsearch -glob $args "-*"] foreach {opt val} [lrange $args $ndx end] { lappend usedOpts $opt } foreach opt $Snit_optionInfo(delegated-hull) { set target [lindex $Snit_optionInfo(target-$opt) 1] if {"$target" == $opt} { continue } set result [lsearch -exact $usedOpts $target] if {$result != -1} { continue } set dbval [RT.OptionDbGet $type $self $opt] $obj configure $target $dbval } } } else { set obj $using if {![string equal $obj $self]} { error \ "hull name mismatch: \"$obj\" != \"$self\"" } } # NEXT, get the local option defaults. foreach opt $Snit_optionInfo(local) { set dbval [RT.OptionDbGet $type $self $opt] if {"" != $dbval} { set options($opt) $dbval } } # NEXT, do the magic set i 0 while 1 { incr i set newName "::hull${i}$self" if {![llength [info commands $newName]]} { break } } rename ::$self $newName RT.MakeInstanceCommand $type $selfns $self # Note: this relies on RT.ComponentTrace to do the dirty work. set hull $newName return } # Implements %TYPE%::install. # # Creates a widget and installs it as the named component. # It expects self and selfns to be defined in the caller's context. proc ::snit::RT.install {type compName "using" widgetType winPath args} { variable ${type}::Snit_optionInfo variable ${type}::Snit_info upvar self self upvar selfns selfns upvar ${selfns}::$compName comp upvar ${selfns}::hull hull # We do the magic option database stuff only if $self is # a widget. if {$Snit_info(isWidget)} { if {"" == $hull} { error "tried to install \"$compName\" before the hull exists" } # FIRST, query the option database and save the results # into args. Insert them before the first option in the # list, in case there are any non-standard parameters. # # Note: there might not be any delegated options; if so, # don't bother. if {[info exists Snit_optionInfo(delegated-$compName)]} { set ndx [lsearch -glob $args "-*"] foreach opt $Snit_optionInfo(delegated-$compName) { set dbval [RT.OptionDbGet $type $self $opt] if {"" != $dbval} { set target [lindex $Snit_optionInfo(target-$opt) 1] set args [linsert $args $ndx $target $dbval] } } } } # NEXT, create the component and save it. set cmd [concat [list $widgetType $winPath] $args] set comp [uplevel 1 $cmd] # NEXT, handle the option database for "delegate option *", # in widgets only. if {$Snit_info(isWidget) && [string equal $Snit_optionInfo(starcomp) $compName]} { # FIRST, get the list of option specs from the widget. # If configure doesn't work, skip it. if {[catch {$comp configure} specs]} { return } # NEXT, get the set of explicitly used options from args set usedOpts {} set ndx [lsearch -glob $args "-*"] foreach {opt val} [lrange $args $ndx end] { lappend usedOpts $opt } # NEXT, "delegate option *" matches all options defined # by this widget that aren't defined by the widget as a whole, # and that aren't excepted. Plus, we skip usedOpts. So build # a list of the options it can't match. set skiplist [concat \ $usedOpts \ $Snit_optionInfo(except) \ $Snit_optionInfo(local) \ $Snit_optionInfo(delegated)] # NEXT, loop over all of the component's options, and set # any not in the skip list for which there is an option # database value. foreach spec $specs { # Skip aliases if {[llength $spec] != 5} { continue } set opt [lindex $spec 0] if {[lsearch -exact $skiplist $opt] != -1} { continue } set res [lindex $spec 1] set cls [lindex $spec 2] set dbvalue [option get $self $res $cls] if {"" != $dbvalue} { $comp configure $opt $dbvalue } } } return } #----------------------------------------------------------------------- # Method/Variable Name Qualification # Implements %TYPE%::variable. Requires selfns. proc ::snit::RT.variable {varname} { upvar selfns selfns if {![string match "::*" $varname]} { uplevel 1 [list upvar 1 ${selfns}::$varname $varname] } else { # varname is fully qualified; let the standard # "variable" command handle it. uplevel 1 [list ::variable $varname] } } # Fully qualifies a typevariable name. # # This is used to implement the mytypevar command. proc ::snit::RT.mytypevar {type name} { return ${type}::$name } # Fully qualifies an instance variable name. # # This is used to implement the myvar command. proc ::snit::RT.myvar {name} { upvar selfns selfns return ${selfns}::$name } # Use this like "list" to convert a proc call into a command # string to pass to another object (e.g., as a -command). # Qualifies the proc name properly. # # This is used to implement the "myproc" command. proc ::snit::RT.myproc {type procname args} { set procname "${type}::$procname" return [linsert $args 0 $procname] } # DEPRECATED proc ::snit::RT.codename {type name} { return "${type}::$name" } # Use this like "list" to convert a typemethod call into a command # string to pass to another object (e.g., as a -command). # Inserts the type command at the beginning. # # This is used to implement the "mytypemethod" command. proc ::snit::RT.mytypemethod {type args} { return [linsert $args 0 $type] } # Use this like "list" to convert a method call into a command # string to pass to another object (e.g., as a -command). # Inserts the code at the beginning to call the right object, even if # the object's name has changed. Requires that selfns be defined # in the calling context, eg. can only be called in instance # code. # # This is used to implement the "mymethod" command. proc ::snit::RT.mymethod {args} { upvar selfns selfns return [linsert $args 0 ::snit::RT.CallInstance ${selfns}] } # Calls an instance method for an object given its # instance namespace and remaining arguments (the first of which # will be the method name. # # selfns The instance namespace # args The arguments # # Uses the selfns to determine $self, and calls the method # in the normal way. # # This is used to implement the "mymethod" command. proc ::snit::RT.CallInstance {selfns args} { upvar ${selfns}::Snit_instance self set retval [catch {uplevel 1 [linsert $args 0 $self]} result] if {$retval} { if {$retval == 1} { global errorInfo global errorCode return -code error -errorinfo $errorInfo \ -errorcode $errorCode $result } else { return -code $retval $result } } return $result } # Looks for the named option in the named variable. If found, # it and its value are removed from the list, and the value # is returned. Otherwise, the default value is returned. # If the option is undelegated, it's own default value will be # used if none is specified. # # Implements the "from" command. proc ::snit::RT.from {type argvName option {defvalue ""}} { variable ${type}::Snit_optionInfo upvar $argvName argv set ioption [lsearch -exact $argv $option] if {$ioption == -1} { if {"" == $defvalue && [info exists Snit_optionInfo(default-$option)]} { return $Snit_optionInfo(default-$option) } else { return $defvalue } } set ivalue [expr {$ioption + 1}] set value [lindex $argv $ivalue] set argv [lreplace $argv $ioption $ivalue] return $value } #----------------------------------------------------------------------- # Type Destruction # Implements the standard "destroy" typemethod: # Destroys a type completely. # # type The snit type proc ::snit::RT.typemethod.destroy {type} { variable ${type}::Snit_info # FIRST, destroy all instances foreach selfns [namespace children $type] { if {![namespace exists $selfns]} { continue } upvar ${selfns}::Snit_instance obj if {$Snit_info(isWidget)} { destroy $obj } else { if {[llength [info commands $obj]]} { $obj destroy } } } # NEXT, destroy the type's data. namespace delete $type # NEXT, get rid of the type command. rename $type "" } #----------------------------------------------------------------------- # Option Handling # Implements the standard "cget" method # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # option The name of the option proc ::snit::RT.method.cget {type selfns win self option} { if {[catch {set ${selfns}::Snit_cgetCache($option)} command]} { set command [snit::RT.CacheCgetCommand $type $selfns $win $self $option] if {[llength $command] == 0} { return -code error "unknown option \"$option\"" } } uplevel 1 $command } # Retrieves and caches the command that implements "cget" for the # specified option. # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # option The name of the option proc ::snit::RT.CacheCgetCommand {type selfns win self option} { variable ${type}::Snit_optionInfo variable ${selfns}::Snit_cgetCache if {[info exists Snit_optionInfo(islocal-$option)]} { # We know the item; it's either local, or explicitly delegated. if {$Snit_optionInfo(islocal-$option)} { # It's a local option. If it has a cget method defined, # use it; otherwise just return the value. if {"" == $Snit_optionInfo(cget-$option)} { set command [list set ${selfns}::options($option)] } else { set command [snit::RT.LookupMethodCommand \ $type $selfns $win $self \ $Snit_optionInfo(cget-$option) \ "can't cget $option"] lappend command $option } set Snit_cgetCache($option) $command return $command } # Explicitly delegated option; get target set comp [lindex $Snit_optionInfo(target-$option) 0] set target [lindex $Snit_optionInfo(target-$option) 1] } elseif {"" != $Snit_optionInfo(starcomp) && [lsearch -exact $Snit_optionInfo(except) $option] == -1} { # Unknown option, but unknowns are delegated; get target. set comp $Snit_optionInfo(starcomp) set target $option } else { return "" } # Get the component's object. set obj [RT.Component $type $selfns $comp] set command [list $obj cget $target] set Snit_cgetCache($option) $command return $command } # Implements the standard "configurelist" method # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # optionlist A list of options and their values. proc ::snit::RT.method.configurelist {type selfns win self optionlist} { variable ${type}::Snit_optionInfo foreach {option value} $optionlist { # FIRST, get the configure command, caching it if need be. if {[catch {set ${selfns}::Snit_configureCache($option)} command]} { set command [snit::RT.CacheConfigureCommand \ $type $selfns $win $self $option] if {[llength $command] == 0} { return -code error "unknown option \"$option\"" } } # NEXT, if we have a type-validation object, use it. # TBD: Should test (islocal-$option) here, but islocal # isn't defined for implicitly delegated options. if {[info exists Snit_optionInfo(typeobj-$option)] && "" != $Snit_optionInfo(typeobj-$option)} { if {[catch { $Snit_optionInfo(typeobj-$option) validate $value } result]} { return -code error "invalid $option value: $result" } } # NEXT, the caching the configure command also cached the # validate command, if any. If we have one, run it. set valcommand [set ${selfns}::Snit_validateCache($option)] if {[llength $valcommand]} { lappend valcommand $value uplevel 1 $valcommand } # NEXT, configure the option with the value. lappend command $value uplevel 1 $command } return } # Retrieves and caches the command that stores the named option. # Also stores the command that validates the name option if any; # If none, the validate command is "", so that the cache is always # populated. # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # option An option name proc ::snit::RT.CacheConfigureCommand {type selfns win self option} { variable ${type}::Snit_optionInfo variable ${selfns}::Snit_configureCache variable ${selfns}::Snit_validateCache if {[info exist Snit_optionInfo(islocal-$option)]} { # We know the item; it's either local, or explicitly delegated. if {$Snit_optionInfo(islocal-$option)} { # It's a local option. # If it's readonly, it throws an error if we're already # constructed. if {$Snit_optionInfo(readonly-$option)} { if {[set ${selfns}::Snit_iinfo(constructed)]} { error "option $option can only be set at instance creation" } } # If it has a validate method, cache that for later. if {"" != $Snit_optionInfo(validate-$option)} { set command [snit::RT.LookupMethodCommand \ $type $selfns $win $self \ $Snit_optionInfo(validate-$option) \ "can't validate $option"] lappend command $option set Snit_validateCache($option) $command } else { set Snit_validateCache($option) "" } # If it has a configure method defined, # cache it; otherwise, just set the value. if {"" == $Snit_optionInfo(configure-$option)} { set command [list set ${selfns}::options($option)] } else { set command [snit::RT.LookupMethodCommand \ $type $selfns $win $self \ $Snit_optionInfo(configure-$option) \ "can't configure $option"] lappend command $option } set Snit_configureCache($option) $command return $command } # Delegated option: get target. set comp [lindex $Snit_optionInfo(target-$option) 0] set target [lindex $Snit_optionInfo(target-$option) 1] } elseif {$Snit_optionInfo(starcomp) != "" && [lsearch -exact $Snit_optionInfo(except) $option] == -1} { # Unknown option, but unknowns are delegated. set comp $Snit_optionInfo(starcomp) set target $option } else { return "" } # There is no validate command in this case; save an empty string. set Snit_validateCache($option) "" # Get the component's object set obj [RT.Component $type $selfns $comp] set command [list $obj configure $target] set Snit_configureCache($option) $command return $command } # Implements the standard "configure" method # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # args A list of options and their values, possibly empty. proc ::snit::RT.method.configure {type selfns win self args} { # If two or more arguments, set values as usual. if {[llength $args] >= 2} { ::snit::RT.method.configurelist $type $selfns $win $self $args return } # If zero arguments, acquire data for each known option # and return the list if {[llength $args] == 0} { set result {} foreach opt [RT.method.info.options $type $selfns $win $self] { # Refactor this, so that we don't need to call via $self. lappend result [RT.GetOptionDbSpec \ $type $selfns $win $self $opt] } return $result } # They want it for just one. set opt [lindex $args 0] return [RT.GetOptionDbSpec $type $selfns $win $self $opt] } # Retrieves the option database spec for a single option. # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # option The name of an option # # TBD: This is a bad name. What it's returning is the # result of the configure query. proc ::snit::RT.GetOptionDbSpec {type selfns win self opt} { variable ${type}::Snit_optionInfo upvar ${selfns}::Snit_components Snit_components upvar ${selfns}::options options if {[info exists options($opt)]} { # This is a locally-defined option. Just build the # list and return it. set res $Snit_optionInfo(resource-$opt) set cls $Snit_optionInfo(class-$opt) set def $Snit_optionInfo(default-$opt) return [list $opt $res $cls $def \ [RT.method.cget $type $selfns $win $self $opt]] } elseif {[info exists Snit_optionInfo(target-$opt)]} { # This is an explicitly delegated option. The only # thing we don't have is the default. set res $Snit_optionInfo(resource-$opt) set cls $Snit_optionInfo(class-$opt) # Get the default set logicalName [lindex $Snit_optionInfo(target-$opt) 0] set comp $Snit_components($logicalName) set target [lindex $Snit_optionInfo(target-$opt) 1] if {[catch {$comp configure $target} result]} { set defValue {} } else { set defValue [lindex $result 3] } return [list $opt $res $cls $defValue [$self cget $opt]] } elseif {"" != $Snit_optionInfo(starcomp) && [lsearch -exact $Snit_optionInfo(except) $opt] == -1} { set logicalName $Snit_optionInfo(starcomp) set target $opt set comp $Snit_components($logicalName) if {[catch {set value [$comp cget $target]} result]} { error "unknown option \"$opt\"" } if {![catch {$comp configure $target} result]} { # Replace the delegated option name with the local name. return [::snit::Expand $result $target $opt] } # configure didn't work; return simple form. return [list $opt "" "" "" $value] } else { error "unknown option \"$opt\"" } } #----------------------------------------------------------------------- # Type Introspection # Implements the standard "info" typemethod. # # type The snit type # command The info subcommand # args All other arguments. proc ::snit::RT.typemethod.info {type command args} { global errorInfo global errorCode switch -exact $command { args - body - default - typevars - typemethods - instances { # TBD: it should be possible to delete this error # handling. set errflag [catch { uplevel 1 [linsert $args 0 \ ::snit::RT.typemethod.info.$command $type] } result] if {$errflag} { return -code error -errorinfo $errorInfo \ -errorcode $errorCode $result } else { return $result } } default { error "\"$type info $command\" is not defined" } } } # Returns a list of the type's typevariables whose names match a # pattern, excluding Snit internal variables. # # type A Snit type # pattern Optional. The glob pattern to match. Defaults # to *. proc ::snit::RT.typemethod.info.typevars {type {pattern *}} { set result {} foreach name [info vars "${type}::$pattern"] { set tail [namespace tail $name] if {![string match "Snit_*" $tail]} { lappend result $name } } return $result } # Returns a list of the type's methods whose names match a # pattern. If "delegate typemethod *" is used, the list may # not be complete. # # type A Snit type # pattern Optional. The glob pattern to match. Defaults # to *. proc ::snit::RT.typemethod.info.typemethods {type {pattern *}} { variable ${type}::Snit_typemethodInfo variable ${type}::Snit_typemethodCache # FIRST, get the explicit names, skipping prefixes. set result {} foreach name [array names Snit_typemethodInfo $pattern] { if {[lindex $Snit_typemethodInfo($name) 0] != 1} { lappend result $name } } # NEXT, add any from the cache that aren't explicit. if {[info exists Snit_typemethodInfo(*)]} { # First, remove "*" from the list. set ndx [lsearch -exact $result "*"] if {$ndx != -1} { set result [lreplace $result $ndx $ndx] } foreach name [array names Snit_typemethodCache $pattern] { if {[lsearch -exact $result $name] == -1} { lappend result $name } } } return $result } # $type info args # # Returns a method's list of arguments. does not work for delegated # methods, nor for the internal dispatch methods of multi-word # methods. proc ::snit::RT.typemethod.info.args {type method} { upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo # Snit_methodInfo: method -> list (flag cmd component) # flag : 1 -> internal dispatcher for multi-word method. # 0 -> regular method # # cmd : template mapping from method to command prefix, may # contain placeholders for various pieces of information. # # component : is empty for normal methods. #parray Snit_typemethodInfo if {![info exists Snit_typemethodInfo($method)]} { return -code error "Unknown typemethod \"$method\"" } foreach {flag cmd component} $Snit_typemethodInfo($method) break if {$flag} { return -code error "Unknown typemethod \"$method\"" } if {$component != ""} { return -code error "Delegated typemethod \"$method\"" } set map [list %m $method %j [join $method _] %t $type] set theproc [lindex [string map $map $cmd] 0] return [lrange [::info args $theproc] 1 end] } # $type info body # # Returns a method's body. does not work for delegated # methods, nor for the internal dispatch methods of multi-word # methods. proc ::snit::RT.typemethod.info.body {type method} { upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo # Snit_methodInfo: method -> list (flag cmd component) # flag : 1 -> internal dispatcher for multi-word method. # 0 -> regular method # # cmd : template mapping from method to command prefix, may # contain placeholders for various pieces of information. # # component : is empty for normal methods. #parray Snit_typemethodInfo if {![info exists Snit_typemethodInfo($method)]} { return -code error "Unknown typemethod \"$method\"" } foreach {flag cmd component} $Snit_typemethodInfo($method) break if {$flag} { return -code error "Unknown typemethod \"$method\"" } if {$component != ""} { return -code error "Delegated typemethod \"$method\"" } set map [list %m $method %j [join $method _] %t $type] set theproc [lindex [string map $map $cmd] 0] return [RT.body [::info body $theproc]] } # $type info default # # Returns a method's list of arguments. does not work for delegated # methods, nor for the internal dispatch methods of multi-word # methods. proc ::snit::RT.typemethod.info.default {type method aname dvar} { upvar 1 $dvar def upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo # Snit_methodInfo: method -> list (flag cmd component) # flag : 1 -> internal dispatcher for multi-word method. # 0 -> regular method # # cmd : template mapping from method to command prefix, may # contain placeholders for various pieces of information. # # component : is empty for normal methods. #parray Snit_methodInfo if {![info exists Snit_typemethodInfo($method)]} { return -code error "Unknown typemethod \"$method\"" } foreach {flag cmd component} $Snit_typemethodInfo($method) break if {$flag} { return -code error "Unknown typemethod \"$method\"" } if {$component != ""} { return -code error "Delegated typemethod \"$method\"" } set map [list %m $method %j [join $method _] %t $type] set theproc [lindex [string map $map $cmd] 0] return [::info default $theproc $aname def] } # Returns a list of the type's instances whose names match # a pattern. # # type A Snit type # pattern Optional. The glob pattern to match # Defaults to * # # REQUIRE: type is fully qualified. proc ::snit::RT.typemethod.info.instances {type {pattern *}} { set result {} foreach selfns [namespace children $type] { upvar ${selfns}::Snit_instance instance if {[string match $pattern $instance]} { lappend result $instance } } return $result } #----------------------------------------------------------------------- # Instance Introspection # Implements the standard "info" method. # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # command The info subcommand # args All other arguments. proc ::snit::RT.method.info {type selfns win self command args} { switch -exact $command { args - body - default - type - vars - options - methods - typevars - typemethods { set errflag [catch { uplevel 1 [linsert $args 0 ::snit::RT.method.info.$command \ $type $selfns $win $self] } result] if {$errflag} { global errorInfo return -code error -errorinfo $errorInfo $result } else { return $result } } default { # error "\"$self info $command\" is not defined" return -code error "\"$self info $command\" is not defined" } } } # $self info type # # Returns the instance's type proc ::snit::RT.method.info.type {type selfns win self} { return $type } # $self info typevars # # Returns the instance's type's typevariables proc ::snit::RT.method.info.typevars {type selfns win self {pattern *}} { return [RT.typemethod.info.typevars $type $pattern] } # $self info typemethods # # Returns the instance's type's typemethods proc ::snit::RT.method.info.typemethods {type selfns win self {pattern *}} { return [RT.typemethod.info.typemethods $type $pattern] } # Returns a list of the instance's methods whose names match a # pattern. If "delegate method *" is used, the list may # not be complete. # # type A Snit type # selfns The instance namespace # win The original instance name # self The current instance name # pattern Optional. The glob pattern to match. Defaults # to *. proc ::snit::RT.method.info.methods {type selfns win self {pattern *}} { variable ${type}::Snit_methodInfo variable ${selfns}::Snit_methodCache # FIRST, get the explicit names, skipping prefixes. set result {} foreach name [array names Snit_methodInfo $pattern] { if {[lindex $Snit_methodInfo($name) 0] != 1} { lappend result $name } } # NEXT, add any from the cache that aren't explicit. if {[info exists Snit_methodInfo(*)]} { # First, remove "*" from the list. set ndx [lsearch -exact $result "*"] if {$ndx != -1} { set result [lreplace $result $ndx $ndx] } foreach name [array names Snit_methodCache $pattern] { if {[lsearch -exact $result $name] == -1} { lappend result $name } } } return $result } # $self info args # # Returns a method's list of arguments. does not work for delegated # methods, nor for the internal dispatch methods of multi-word # methods. proc ::snit::RT.method.info.args {type selfns win self method} { upvar ${type}::Snit_methodInfo Snit_methodInfo # Snit_methodInfo: method -> list (flag cmd component) # flag : 1 -> internal dispatcher for multi-word method. # 0 -> regular method # # cmd : template mapping from method to command prefix, may # contain placeholders for various pieces of information. # # component : is empty for normal methods. #parray Snit_methodInfo if {![info exists Snit_methodInfo($method)]} { return -code error "Unknown method \"$method\"" } foreach {flag cmd component} $Snit_methodInfo($method) break if {$flag} { return -code error "Unknown method \"$method\"" } if {$component != ""} { return -code error "Delegated method \"$method\"" } set map [list %m $method %j [join $method _] %t $type %n $selfns %w $win %s $self] set theproc [lindex [string map $map $cmd] 0] return [lrange [::info args $theproc] 4 end] } # $self info body # # Returns a method's body. does not work for delegated # methods, nor for the internal dispatch methods of multi-word # methods. proc ::snit::RT.method.info.body {type selfns win self method} { upvar ${type}::Snit_methodInfo Snit_methodInfo # Snit_methodInfo: method -> list (flag cmd component) # flag : 1 -> internal dispatcher for multi-word method. # 0 -> regular method # # cmd : template mapping from method to command prefix, may # contain placeholders for various pieces of information. # # component : is empty for normal methods. #parray Snit_methodInfo if {![info exists Snit_methodInfo($method)]} { return -code error "Unknown method \"$method\"" } foreach {flag cmd component} $Snit_methodInfo($method) break if {$flag} { return -code error "Unknown method \"$method\"" } if {$component != ""} { return -code error "Delegated method \"$method\"" } set map [list %m $method %j [join $method _] %t $type %n $selfns %w $win %s $self] set theproc [lindex [string map $map $cmd] 0] return [RT.body [::info body $theproc]] } # $self info default # # Returns a method's list of arguments. does not work for delegated # methods, nor for the internal dispatch methods of multi-word # methods. proc ::snit::RT.method.info.default {type selfns win self method aname dvar} { upvar 1 $dvar def upvar ${type}::Snit_methodInfo Snit_methodInfo # Snit_methodInfo: method -> list (flag cmd component) # flag : 1 -> internal dispatcher for multi-word method. # 0 -> regular method # # cmd : template mapping from method to command prefix, may # contain placeholders for various pieces of information. # # component : is empty for normal methods. if {![info exists Snit_methodInfo($method)]} { return -code error "Unknown method \"$method\"" } foreach {flag cmd component} $Snit_methodInfo($method) break if {$flag} { return -code error "Unknown method \"$method\"" } if {$component != ""} { return -code error "Delegated method \"$method\"" } set map [list %m $method %j [join $method _] %t $type %n $selfns %w $win %s $self] set theproc [lindex [string map $map $cmd] 0] return [::info default $theproc $aname def] } # $self info vars # # Returns the instance's instance variables proc ::snit::RT.method.info.vars {type selfns win self {pattern *}} { set result {} foreach name [info vars "${selfns}::$pattern"] { set tail [namespace tail $name] if {![string match "Snit_*" $tail]} { lappend result $name } } return $result } # $self info options # # Returns a list of the names of the instance's options proc ::snit::RT.method.info.options {type selfns win self {pattern *}} { variable ${type}::Snit_optionInfo # First, get the local and explicitly delegated options set result [concat $Snit_optionInfo(local) $Snit_optionInfo(delegated)] # If "configure" works as for Tk widgets, add the resulting # options to the list. Skip excepted options if {"" != $Snit_optionInfo(starcomp)} { upvar ${selfns}::Snit_components Snit_components set logicalName $Snit_optionInfo(starcomp) set comp $Snit_components($logicalName) if {![catch {$comp configure} records]} { foreach record $records { set opt [lindex $record 0] if {[lsearch -exact $result $opt] == -1 && [lsearch -exact $Snit_optionInfo(except) $opt] == -1} { lappend result $opt } } } } # Next, apply the pattern set names {} foreach name $result { if {[string match $pattern $name]} { lappend names $name } } return $names } proc ::snit::RT.body {body} { regsub -all ".*# END snit method prolog\n" $body {} body return $body } amsn-0.98.9/utils/snit/snit2.tcl0000644000175000017500000000140111020317540016236 0ustar billiobbilliob#----------------------------------------------------------------------- # TITLE: # snit2.tcl # # AUTHOR: # Will Duquette # # DESCRIPTION: # Snit's Not Incr Tcl, a simple object system in Pure Tcl. # # Snit 2.x Loader # # Copyright (C) 2003-2006 by William H. Duquette # This code is licensed as described in license.txt. # #----------------------------------------------------------------------- package require Tcl 8.5 # Define the snit namespace and save the library directory namespace eval ::snit:: { set library [file dirname [info script]] } # Load the kernel. source [file join $::snit::library main2.tcl] # Load the library of Snit validation types. source [file join $::snit::library validate.tcl] package provide snit 2.2.1 amsn-0.98.9/utils/snit/main1_83.tcl0000644000175000017500000037264011020317540016536 0ustar billiobbilliob#----------------------------------------------------------------------- # TITLE: # main1_83.tcl # # AUTHOR: # Will Duquette # # DESCRIPTION: # Snit's Not Incr Tcl, a simple object system in Pure Tcl. # # Snit 1.x Compiler and Run-Time Library, Tcl 8.3 and later # # Copyright (C) 2003-2006 by William H. Duquette # This code is licensed as described in license.txt. # #----------------------------------------------------------------------- # Back-port to Tcl8.3 by Kenneth Green (kmg) # Modified by Andreas Kupries. # Further modified by Will Duquette 12 Aug 2006 # # Local changes marked with "#kmg-tcl83" # # Global changes: # " trace add variable " -> "trace variable " # " write " -> "w" in all calls to 'trace variable' # " unset -nocomplain " -> "::snit83::unset -nocomplain" #----------------------------------------------------------------------- #----------------------------------------------------------------------- # Namespace namespace eval ::snit:: { namespace export \ compile type widget widgetadaptor typemethod method macro } #----------------------------------------------------------------------- # Some Snit variables namespace eval ::snit:: { variable reservedArgs {type selfns win self} # Widget classes which can be hulls (must have -class) variable hulltypes { toplevel tk::toplevel frame tk::frame ttk::frame labelframe tk::labelframe ttk::labelframe } } #----------------------------------------------------------------------- # Snit Type Implementation template namespace eval ::snit:: { # Template type definition: All internal and user-visible Snit # implementation code. # # The following placeholders will automatically be replaced with # the client's code, in two passes: # # First pass: # %COMPILEDDEFS% The compiled type definition. # # Second pass: # %TYPE% The fully qualified type name. # %IVARDECS% Instance variable declarations # %TVARDECS% Type variable declarations # %TCONSTBODY% Type constructor body # %INSTANCEVARS% The compiled instance variable initialization code. # %TYPEVARS% The compiled type variable initialization code. # This is the overall type template. variable typeTemplate # This is the normal type proc variable nominalTypeProc # This is the "-hastypemethods no" type proc variable simpleTypeProc } set ::snit::typeTemplate { #------------------------------------------------------------------- # The type's namespace definition and the user's type variables namespace eval %TYPE% {%TYPEVARS% } #---------------------------------------------------------------- # Commands for use in methods, typemethods, etc. # # These are implemented as aliases into the Snit runtime library. interp alias {} %TYPE%::installhull {} ::snit::RT.installhull %TYPE% interp alias {} %TYPE%::install {} ::snit::RT.install %TYPE% interp alias {} %TYPE%::typevariable {} ::variable interp alias {} %TYPE%::variable {} ::snit::RT.variable interp alias {} %TYPE%::mytypevar {} ::snit::RT.mytypevar %TYPE% interp alias {} %TYPE%::typevarname {} ::snit::RT.mytypevar %TYPE% interp alias {} %TYPE%::myvar {} ::snit::RT.myvar interp alias {} %TYPE%::varname {} ::snit::RT.myvar interp alias {} %TYPE%::codename {} ::snit::RT.codename %TYPE% interp alias {} %TYPE%::myproc {} ::snit::RT.myproc %TYPE% interp alias {} %TYPE%::mymethod {} ::snit::RT.mymethod interp alias {} %TYPE%::mytypemethod {} ::snit::RT.mytypemethod %TYPE% interp alias {} %TYPE%::from {} ::snit::RT.from %TYPE% #------------------------------------------------------------------- # Snit's internal variables namespace eval %TYPE% { # Array: General Snit Info # # ns: The type's namespace # hasinstances: T or F, from pragma -hasinstances. # simpledispatch: T or F, from pragma -hasinstances. # canreplace: T or F, from pragma -canreplace. # counter: Count of instances created so far. # widgetclass: Set by widgetclass statement. # hulltype: Hull type (frame or toplevel) for widgets only. # exceptmethods: Methods explicitly not delegated to * # excepttypemethods: Methods explicitly not delegated to * # tvardecs: Type variable declarations--for dynamic methods # ivardecs: Instance variable declarations--for dyn. methods typevariable Snit_info set Snit_info(ns) %TYPE%:: set Snit_info(hasinstances) 1 set Snit_info(simpledispatch) 0 set Snit_info(canreplace) 0 set Snit_info(counter) 0 set Snit_info(widgetclass) {} set Snit_info(hulltype) frame set Snit_info(exceptmethods) {} set Snit_info(excepttypemethods) {} set Snit_info(tvardecs) {%TVARDECS%} set Snit_info(ivardecs) {%IVARDECS%} # Array: Public methods of this type. # The index is the method name, or "*". # The value is [list $pattern $componentName], where # $componentName is "" for normal methods. typevariable Snit_typemethodInfo array unset Snit_typemethodInfo # Array: Public methods of instances of this type. # The index is the method name, or "*". # The value is [list $pattern $componentName], where # $componentName is "" for normal methods. typevariable Snit_methodInfo array unset Snit_methodInfo # Array: option information. See dictionary.txt. typevariable Snit_optionInfo array unset Snit_optionInfo set Snit_optionInfo(local) {} set Snit_optionInfo(delegated) {} set Snit_optionInfo(starcomp) {} set Snit_optionInfo(except) {} } #---------------------------------------------------------------- # Compiled Procs # # These commands are created or replaced during compilation: # Snit_instanceVars selfns # # Initializes the instance variables, if any. Called during # instance creation. proc %TYPE%::Snit_instanceVars {selfns} { %INSTANCEVARS% } # Type Constructor proc %TYPE%::Snit_typeconstructor {type} { %TVARDECS% %TCONSTBODY% } #---------------------------------------------------------------- # Default Procs # # These commands might be replaced during compilation: # Snit_destructor type selfns win self # # Default destructor for the type. By default, it does # nothing. It's replaced by any user destructor. # For types, it's called by method destroy; for widgettypes, # it's called by a destroy event handler. proc %TYPE%::Snit_destructor {type selfns win self} { } #---------------------------------------------------------- # Compiled Definitions %COMPILEDDEFS% #---------------------------------------------------------- # Finally, call the Type Constructor %TYPE%::Snit_typeconstructor %TYPE% } #----------------------------------------------------------------------- # Type procs # # These procs expect the fully-qualified type name to be # substituted in for %TYPE%. # This is the nominal type proc. It supports typemethods and # delegated typemethods. set ::snit::nominalTypeProc { # Type dispatcher function. Note: This function lives # in the parent of the %TYPE% namespace! All accesses to # %TYPE% variables and methods must be qualified! proc %TYPE% {{method ""} args} { # First, if there's no method, and no args, and there's a create # method, and this isn't a widget, then method is "create" and # "args" is %AUTO%. if {"" == $method && [llength $args] == 0} { ::variable %TYPE%::Snit_info if {$Snit_info(hasinstances) && !$Snit_info(isWidget)} { set method create lappend args %AUTO% } else { error "wrong \# args: should be \"%TYPE% method args\"" } } # Next, retrieve the command. variable %TYPE%::Snit_typemethodCache while 1 { if {[catch {set Snit_typemethodCache($method)} commandRec]} { set commandRec [::snit::RT.CacheTypemethodCommand %TYPE% $method] if {[llength $commandRec] == 0} { return -code error "\"%TYPE% $method\" is not defined" } } # If we've got a real command, break. if {[lindex $commandRec 0] == 0} { break } # Otherwise, we need to look up again...if we can. if {[llength $args] == 0} { return -code error \ "wrong number args: should be \"%TYPE% $method method args\"" } lappend method [lindex $args 0] set args [lrange $args 1 end] } set command [lindex $commandRec 1] # Pass along the return code unchanged. set retval [catch {uplevel 1 $command $args} result] if {$retval} { if {$retval == 1} { global errorInfo global errorCode return -code error -errorinfo $errorInfo \ -errorcode $errorCode $result } else { return -code $retval $result } } return $result } } # This is the simplified type proc for when there are no typemethods # except create. In this case, it doesn't take a method argument; # the method is always "create". set ::snit::simpleTypeProc { # Type dispatcher function. Note: This function lives # in the parent of the %TYPE% namespace! All accesses to # %TYPE% variables and methods must be qualified! proc %TYPE% {args} { ::variable %TYPE%::Snit_info # FIRST, if the are no args, the single arg is %AUTO% if {[llength $args] == 0} { if {$Snit_info(isWidget)} { error "wrong \# args: should be \"%TYPE% name args\"" } lappend args %AUTO% } # NEXT, we're going to call the create method. # Pass along the return code unchanged. if {$Snit_info(isWidget)} { set command [list ::snit::RT.widget.typemethod.create %TYPE%] } else { set command [list ::snit::RT.type.typemethod.create %TYPE%] } set retval [catch {uplevel 1 $command $args} result] if {$retval} { if {$retval == 1} { global errorInfo global errorCode return -code error -errorinfo $errorInfo \ -errorcode $errorCode $result } else { return -code $retval $result } } return $result } } #----------------------------------------------------------------------- # Instance procs # # The following must be substituted into these proc bodies: # # %SELFNS% The instance namespace # %WIN% The original instance name # %TYPE% The fully-qualified type name # # Nominal instance proc body: supports method caching and delegation. # # proc $instanceName {method args} .... set ::snit::nominalInstanceProc { set self [set %SELFNS%::Snit_instance] while {1} { if {[catch {set %SELFNS%::Snit_methodCache($method)} commandRec]} { set commandRec [snit::RT.CacheMethodCommand %TYPE% %SELFNS% %WIN% $self $method] if {[llength $commandRec] == 0} { return -code error \ "\"$self $method\" is not defined" } } # If we've got a real command, break. if {[lindex $commandRec 0] == 0} { break } # Otherwise, we need to look up again...if we can. if {[llength $args] == 0} { return -code error \ "wrong number args: should be \"$self $method method args\"" } lappend method [lindex $args 0] set args [lrange $args 1 end] } set command [lindex $commandRec 1] # Pass along the return code unchanged. set retval [catch {uplevel 1 $command $args} result] if {$retval} { if {$retval == 1} { global errorInfo global errorCode return -code error -errorinfo $errorInfo \ -errorcode $errorCode $result } else { return -code $retval $result } } return $result } # Simplified method proc body: No delegation allowed; no support for # upvar or exotic return codes or hierarchical methods. Designed for # max speed for simple types. # # proc $instanceName {method args} .... set ::snit::simpleInstanceProc { set self [set %SELFNS%::Snit_instance] if {[lsearch -exact ${%TYPE%::Snit_methods} $method] == -1} { set optlist [join ${%TYPE%::Snit_methods} ", "] set optlist [linsert $optlist "end-1" "or"] error "bad option \"$method\": must be $optlist" } eval [linsert $args 0 \ %TYPE%::Snit_method$method %TYPE% %SELFNS% %WIN% $self] } #======================================================================= # Snit Type Definition # # These are the procs used to define Snit types, widgets, and # widgetadaptors. #----------------------------------------------------------------------- # Snit Compilation Variables # # The following variables are used while Snit is compiling a type, # and are disposed afterwards. namespace eval ::snit:: { # The compiler variable contains the name of the slave interpreter # used to compile type definitions. variable compiler "" # The compile array accumulates information about the type or # widgettype being compiled. It is cleared before and after each # compilation. It has these indices: # # type: The name of the type being compiled, for use # in compilation procs. # defs: Compiled definitions, both standard and client. # which: type, widget, widgetadaptor # instancevars: Instance variable definitions and initializations. # ivprocdec: Instance variable proc declarations. # tvprocdec: Type variable proc declarations. # typeconstructor: Type constructor body. # widgetclass: The widgetclass, for snit::widgets, only # hasoptions: False, initially; set to true when first # option is defined. # localoptions: Names of local options. # delegatedoptions: Names of delegated options. # localmethods: Names of locally defined methods. # delegatesmethods: no if no delegated methods, yes otherwise. # hashierarchic : no if no hierarchic methods, yes otherwise. # components: Names of defined components. # typecomponents: Names of defined typecomponents. # typevars: Typevariable definitions and initializations. # varnames: Names of instance variables # typevarnames Names of type variables # hasconstructor False, initially; true when constructor is # defined. # resource-$opt The option's resource name # class-$opt The option's class # -default-$opt The option's default value # -validatemethod-$opt The option's validate method # -configuremethod-$opt The option's configure method # -cgetmethod-$opt The option's cget method. # -hastypeinfo The -hastypeinfo pragma # -hastypedestroy The -hastypedestroy pragma # -hastypemethods The -hastypemethods pragma # -hasinfo The -hasinfo pragma # -hasinstances The -hasinstances pragma # -simpledispatch The -simpledispatch pragma # -canreplace The -canreplace pragma variable compile # This variable accumulates method dispatch information; it has # the same structure as the %TYPE%::Snit_methodInfo array, and is # used to initialize it. variable methodInfo # This variable accumulates typemethod dispatch information; it has # the same structure as the %TYPE%::Snit_typemethodInfo array, and is # used to initialize it. variable typemethodInfo # The following variable lists the reserved type definition statement # names, e.g., the names you can't use as macros. It's built at # compiler definition time using "info commands". variable reservedwords {} } #----------------------------------------------------------------------- # type compilation commands # # The type and widgettype commands use a slave interpreter to compile # the type definition. These are the procs # that are aliased into it. # Initialize the compiler proc ::snit::Comp.Init {} { variable compiler variable reservedwords if {"" == $compiler} { # Create the compiler's interpreter set compiler [interp create] # Initialize the interpreter $compiler eval { # Load package information # TBD: see if this can be moved outside. # @mdgen NODEP: ::snit::__does_not_exist__ catch {package require ::snit::__does_not_exist__} # Protect some Tcl commands our type definitions # will shadow. rename proc _proc rename variable _variable } # Define compilation aliases. $compiler alias pragma ::snit::Comp.statement.pragma $compiler alias widgetclass ::snit::Comp.statement.widgetclass $compiler alias hulltype ::snit::Comp.statement.hulltype $compiler alias constructor ::snit::Comp.statement.constructor $compiler alias destructor ::snit::Comp.statement.destructor $compiler alias option ::snit::Comp.statement.option $compiler alias oncget ::snit::Comp.statement.oncget $compiler alias onconfigure ::snit::Comp.statement.onconfigure $compiler alias method ::snit::Comp.statement.method $compiler alias typemethod ::snit::Comp.statement.typemethod $compiler alias typeconstructor ::snit::Comp.statement.typeconstructor $compiler alias proc ::snit::Comp.statement.proc $compiler alias typevariable ::snit::Comp.statement.typevariable $compiler alias variable ::snit::Comp.statement.variable $compiler alias typecomponent ::snit::Comp.statement.typecomponent $compiler alias component ::snit::Comp.statement.component $compiler alias delegate ::snit::Comp.statement.delegate $compiler alias expose ::snit::Comp.statement.expose # Get the list of reserved words set reservedwords [$compiler eval {info commands}] } } # Compile a type definition, and return the results as a list of two # items: the fully-qualified type name, and a script that will define # the type when executed. # # which type, widget, or widgetadaptor # type the type name # body the type definition proc ::snit::Comp.Compile {which type body} { variable typeTemplate variable nominalTypeProc variable simpleTypeProc variable compile variable compiler variable methodInfo variable typemethodInfo # FIRST, qualify the name. if {![string match "::*" $type]} { # Get caller's namespace; # append :: if not global namespace. set ns [uplevel 2 [list namespace current]] if {"::" != $ns} { append ns "::" } set type "$ns$type" } # NEXT, create and initialize the compiler, if needed. Comp.Init # NEXT, initialize the class data array unset methodInfo array unset typemethodInfo array unset compile set compile(type) $type set compile(defs) {} set compile(which) $which set compile(hasoptions) no set compile(localoptions) {} set compile(instancevars) {} set compile(typevars) {} set compile(delegatedoptions) {} set compile(ivprocdec) {} set compile(tvprocdec) {} set compile(typeconstructor) {} set compile(widgetclass) {} set compile(hulltype) {} set compile(localmethods) {} set compile(delegatesmethods) no set compile(hashierarchic) no set compile(components) {} set compile(typecomponents) {} set compile(varnames) {} set compile(typevarnames) {} set compile(hasconstructor) no set compile(-hastypedestroy) yes set compile(-hastypeinfo) yes set compile(-hastypemethods) yes set compile(-hasinfo) yes set compile(-hasinstances) yes set compile(-simpledispatch) no set compile(-canreplace) no set isWidget [string match widget* $which] set isWidgetAdaptor [string match widgetadaptor $which] # NEXT, Evaluate the type's definition in the class interpreter. $compiler eval $body # NEXT, Add the standard definitions append compile(defs) \ "\nset %TYPE%::Snit_info(isWidget) $isWidget\n" append compile(defs) \ "\nset %TYPE%::Snit_info(isWidgetAdaptor) $isWidgetAdaptor\n" # Indicate whether the type can create instances that replace # existing commands. append compile(defs) "\nset %TYPE%::Snit_info(canreplace) $compile(-canreplace)\n" # Check pragmas for conflict. if {!$compile(-hastypemethods) && !$compile(-hasinstances)} { error "$which $type has neither typemethods nor instances" } if {$compile(-simpledispatch) && $compile(delegatesmethods)} { error "$which $type requests -simpledispatch but delegates methods." } if {$compile(-simpledispatch) && $compile(hashierarchic)} { error "$which $type requests -simpledispatch but defines hierarchical methods." } # If there are typemethods, define the standard typemethods and # the nominal type proc. Otherwise define the simple type proc. if {$compile(-hastypemethods)} { # Add the info typemethod unless the pragma forbids it. if {$compile(-hastypeinfo)} { Comp.statement.delegate typemethod info \ using {::snit::RT.typemethod.info %t} } # Add the destroy typemethod unless the pragma forbids it. if {$compile(-hastypedestroy)} { Comp.statement.delegate typemethod destroy \ using {::snit::RT.typemethod.destroy %t} } # Add the nominal type proc. append compile(defs) $nominalTypeProc } else { # Add the simple type proc. append compile(defs) $simpleTypeProc } # Add standard methods/typemethods that only make sense if the # type has instances. if {$compile(-hasinstances)} { # If we're using simple dispatch, remember that. if {$compile(-simpledispatch)} { append compile(defs) "\nset %TYPE%::Snit_info(simpledispatch) 1\n" } # Add the info method unless the pragma forbids it. if {$compile(-hasinfo)} { if {!$compile(-simpledispatch)} { Comp.statement.delegate method info \ using {::snit::RT.method.info %t %n %w %s} } else { Comp.statement.method info {args} { eval [linsert $args 0 \ ::snit::RT.method.info $type $selfns $win $self] } } } # Add the option handling stuff if there are any options. if {$compile(hasoptions)} { Comp.statement.variable options if {!$compile(-simpledispatch)} { Comp.statement.delegate method cget \ using {::snit::RT.method.cget %t %n %w %s} Comp.statement.delegate method configurelist \ using {::snit::RT.method.configurelist %t %n %w %s} Comp.statement.delegate method configure \ using {::snit::RT.method.configure %t %n %w %s} } else { Comp.statement.method cget {args} { eval [linsert $args 0 \ ::snit::RT.method.cget $type $selfns $win $self] } Comp.statement.method configurelist {args} { eval [linsert $args 0 \ ::snit::RT.method.configurelist $type $selfns $win $self] } Comp.statement.method configure {args} { eval [linsert $args 0 \ ::snit::RT.method.configure $type $selfns $win $self] } } } # Add a default constructor, if they haven't already defined one. # If there are options, it will configure args; otherwise it # will do nothing. if {!$compile(hasconstructor)} { if {$compile(hasoptions)} { Comp.statement.constructor {args} { $self configurelist $args } } else { Comp.statement.constructor {} {} } } if {!$isWidget} { if {!$compile(-simpledispatch)} { Comp.statement.delegate method destroy \ using {::snit::RT.method.destroy %t %n %w %s} } else { Comp.statement.method destroy {args} { eval [linsert $args 0 \ ::snit::RT.method.destroy $type $selfns $win $self] } } Comp.statement.delegate typemethod create \ using {::snit::RT.type.typemethod.create %t} } else { Comp.statement.delegate typemethod create \ using {::snit::RT.widget.typemethod.create %t} } # Save the list of method names, for -simpledispatch; otherwise, # save the method info. if {$compile(-simpledispatch)} { append compile(defs) \ "\nset %TYPE%::Snit_methods [list $compile(localmethods)]\n" } else { append compile(defs) \ "\narray set %TYPE%::Snit_methodInfo [list [array get methodInfo]]\n" } } else { append compile(defs) "\nset %TYPE%::Snit_info(hasinstances) 0\n" } # NEXT, compiling the type definition built up a set of information # about the type's locally defined options; add this information to # the compiled definition. Comp.SaveOptionInfo # NEXT, compiling the type definition built up a set of information # about the typemethods; save the typemethod info. append compile(defs) \ "\narray set %TYPE%::Snit_typemethodInfo [list [array get typemethodInfo]]\n" # NEXT, if this is a widget define the hull component if it isn't # already defined. if {$isWidget} { Comp.DefineComponent hull } # NEXT, substitute the compiled definition into the type template # to get the type definition script. set defscript [Expand $typeTemplate \ %COMPILEDDEFS% $compile(defs)] # NEXT, substitute the defined macros into the type definition script. # This is done as a separate step so that the compile(defs) can # contain the macros defined below. set defscript [Expand $defscript \ %TYPE% $type \ %IVARDECS% $compile(ivprocdec) \ %TVARDECS% $compile(tvprocdec) \ %TCONSTBODY% $compile(typeconstructor) \ %INSTANCEVARS% $compile(instancevars) \ %TYPEVARS% $compile(typevars) \ ] array unset compile return [list $type $defscript] } # Information about locally-defined options is accumulated during # compilation, but not added to the compiled definition--the option # statement can appear multiple times, so it's easier this way. # This proc fills in Snit_optionInfo with the accumulated information. # # It also computes the option's resource and class names if needed. # # Note that the information for delegated options was put in # Snit_optionInfo during compilation. proc ::snit::Comp.SaveOptionInfo {} { variable compile foreach option $compile(localoptions) { if {"" == $compile(resource-$option)} { set compile(resource-$option) [string range $option 1 end] } if {"" == $compile(class-$option)} { set compile(class-$option) [Capitalize $compile(resource-$option)] } # NOTE: Don't verify that the validate, configure, and cget # values name real methods; the methods might be defined outside # the typedefinition using snit::method. Mappend compile(defs) { # Option %OPTION% lappend %TYPE%::Snit_optionInfo(local) %OPTION% set %TYPE%::Snit_optionInfo(islocal-%OPTION%) 1 set %TYPE%::Snit_optionInfo(resource-%OPTION%) %RESOURCE% set %TYPE%::Snit_optionInfo(class-%OPTION%) %CLASS% set %TYPE%::Snit_optionInfo(default-%OPTION%) %DEFAULT% set %TYPE%::Snit_optionInfo(validate-%OPTION%) %VALIDATE% set %TYPE%::Snit_optionInfo(configure-%OPTION%) %CONFIGURE% set %TYPE%::Snit_optionInfo(cget-%OPTION%) %CGET% set %TYPE%::Snit_optionInfo(readonly-%OPTION%) %READONLY% set %TYPE%::Snit_optionInfo(typespec-%OPTION%) %TYPESPEC% } %OPTION% $option \ %RESOURCE% $compile(resource-$option) \ %CLASS% $compile(class-$option) \ %DEFAULT% [list $compile(-default-$option)] \ %VALIDATE% [list $compile(-validatemethod-$option)] \ %CONFIGURE% [list $compile(-configuremethod-$option)] \ %CGET% [list $compile(-cgetmethod-$option)] \ %READONLY% $compile(-readonly-$option) \ %TYPESPEC% [list $compile(-type-$option)] } } # Evaluates a compiled type definition, thus making the type available. proc ::snit::Comp.Define {compResult} { # The compilation result is a list containing the fully qualified # type name and a script to evaluate to define the type. set type [lindex $compResult 0] set defscript [lindex $compResult 1] # Execute the type definition script. # Consider using namespace eval %TYPE%. See if it's faster. if {[catch {eval $defscript} result]} { namespace delete $type catch {rename $type ""} error $result } return $type } # Sets pragma options which control how the type is defined. proc ::snit::Comp.statement.pragma {args} { variable compile set errRoot "Error in \"pragma...\"" foreach {opt val} $args { switch -exact -- $opt { -hastypeinfo - -hastypedestroy - -hastypemethods - -hasinstances - -simpledispatch - -hasinfo - -canreplace { if {![string is boolean -strict $val]} { error "$errRoot, \"$opt\" requires a boolean value" } set compile($opt) $val } default { error "$errRoot, unknown pragma" } } } } # Defines a widget's option class name. # This statement is only available for snit::widgets, # not for snit::types or snit::widgetadaptors. proc ::snit::Comp.statement.widgetclass {name} { variable compile # First, widgetclass can only be set for true widgets if {"widget" != $compile(which)} { error "widgetclass cannot be set for snit::$compile(which)s" } # Next, validate the option name. We'll require that it begin # with an uppercase letter. set initial [string index $name 0] if {![string is upper $initial]} { error "widgetclass \"$name\" does not begin with an uppercase letter" } if {"" != $compile(widgetclass)} { error "too many widgetclass statements" } # Next, save it. Mappend compile(defs) { set %TYPE%::Snit_info(widgetclass) %WIDGETCLASS% } %WIDGETCLASS% [list $name] set compile(widgetclass) $name } # Defines a widget's hull type. # This statement is only available for snit::widgets, # not for snit::types or snit::widgetadaptors. proc ::snit::Comp.statement.hulltype {name} { variable compile variable hulltypes # First, hulltype can only be set for true widgets if {"widget" != $compile(which)} { error "hulltype cannot be set for snit::$compile(which)s" } # Next, it must be one of the valid hulltypes (frame, toplevel, ...) if {[lsearch -exact $hulltypes [string trimleft $name :]] == -1} { error "invalid hulltype \"$name\", should be one of\ [join $hulltypes {, }]" } if {"" != $compile(hulltype)} { error "too many hulltype statements" } # Next, save it. Mappend compile(defs) { set %TYPE%::Snit_info(hulltype) %HULLTYPE% } %HULLTYPE% $name set compile(hulltype) $name } # Defines a constructor. proc ::snit::Comp.statement.constructor {arglist body} { variable compile CheckArgs "constructor" $arglist # Next, add a magic reference to self. set arglist [concat type selfns win self $arglist] # Next, add variable declarations to body: set body "%TVARDECS%%IVARDECS%\n$body" set compile(hasconstructor) yes append compile(defs) "proc %TYPE%::Snit_constructor [list $arglist] [list $body]\n" } # Defines a destructor. proc ::snit::Comp.statement.destructor {body} { variable compile # Next, add variable declarations to body: set body "%TVARDECS%%IVARDECS%\n$body" append compile(defs) "proc %TYPE%::Snit_destructor {type selfns win self} [list $body]\n\n" } # Defines a type option. The option value can be a triple, specifying # the option's -name, resource name, and class name. proc ::snit::Comp.statement.option {optionDef args} { variable compile # First, get the three option names. set option [lindex $optionDef 0] set resourceName [lindex $optionDef 1] set className [lindex $optionDef 2] set errRoot "Error in \"option [list $optionDef]...\"" # Next, validate the option name. if {![Comp.OptionNameIsValid $option]} { error "$errRoot, badly named option \"$option\"" } if {[Contains $option $compile(delegatedoptions)]} { error "$errRoot, cannot define \"$option\" locally, it has been delegated" } if {![Contains $option $compile(localoptions)]} { # Remember that we've seen this one. set compile(hasoptions) yes lappend compile(localoptions) $option # Initialize compilation info for this option. set compile(resource-$option) "" set compile(class-$option) "" set compile(-default-$option) "" set compile(-validatemethod-$option) "" set compile(-configuremethod-$option) "" set compile(-cgetmethod-$option) "" set compile(-readonly-$option) 0 set compile(-type-$option) "" } # NEXT, see if we have a resource name. If so, make sure it # isn't being redefined differently. if {"" != $resourceName} { if {"" == $compile(resource-$option)} { # If it's undefined, just save the value. set compile(resource-$option) $resourceName } elseif {![string equal $resourceName $compile(resource-$option)]} { # It's been redefined differently. error "$errRoot, resource name redefined from \"$compile(resource-$option)\" to \"$resourceName\"" } } # NEXT, see if we have a class name. If so, make sure it # isn't being redefined differently. if {"" != $className} { if {"" == $compile(class-$option)} { # If it's undefined, just save the value. set compile(class-$option) $className } elseif {![string equal $className $compile(class-$option)]} { # It's been redefined differently. error "$errRoot, class name redefined from \"$compile(class-$option)\" to \"$className\"" } } # NEXT, handle the args; it's not an error to redefine these. if {[llength $args] == 1} { set compile(-default-$option) [lindex $args 0] } else { foreach {optopt val} $args { switch -exact -- $optopt { -default - -validatemethod - -configuremethod - -cgetmethod { set compile($optopt-$option) $val } -type { set compile($optopt-$option) $val if {[llength $val] == 1} { # The type spec *is* the validation object append compile(defs) \ "\nset %TYPE%::Snit_optionInfo(typeobj-$option) [list $val]\n" } else { # Compilation the creation of the validation object set cmd [linsert $val 1 %TYPE%::Snit_TypeObj_%AUTO%] append compile(defs) \ "\nset %TYPE%::Snit_optionInfo(typeobj-$option) \[$cmd\]\n" } } -readonly { if {![string is boolean -strict $val]} { error "$errRoot, -readonly requires a boolean, got \"$val\"" } set compile($optopt-$option) $val } default { error "$errRoot, unknown option definition option \"$optopt\"" } } } } } # 1 if the option name is valid, 0 otherwise. proc ::snit::Comp.OptionNameIsValid {option} { if {![string match {-*} $option] || [string match {*[A-Z ]*} $option]} { return 0 } return 1 } # Defines an option's cget handler proc ::snit::Comp.statement.oncget {option body} { variable compile set errRoot "Error in \"oncget $option...\"" if {[lsearch -exact $compile(delegatedoptions) $option] != -1} { return -code error "$errRoot, option \"$option\" is delegated" } if {[lsearch -exact $compile(localoptions) $option] == -1} { return -code error "$errRoot, option \"$option\" unknown" } Comp.statement.method _cget$option {_option} $body Comp.statement.option $option -cgetmethod _cget$option } # Defines an option's configure handler. proc ::snit::Comp.statement.onconfigure {option arglist body} { variable compile if {[lsearch -exact $compile(delegatedoptions) $option] != -1} { return -code error "onconfigure $option: option \"$option\" is delegated" } if {[lsearch -exact $compile(localoptions) $option] == -1} { return -code error "onconfigure $option: option \"$option\" unknown" } if {[llength $arglist] != 1} { error \ "onconfigure $option handler should have one argument, got \"$arglist\"" } CheckArgs "onconfigure $option" $arglist # Next, add a magic reference to the option name set arglist [concat _option $arglist] Comp.statement.method _configure$option $arglist $body Comp.statement.option $option -configuremethod _configure$option } # Defines an instance method. proc ::snit::Comp.statement.method {method arglist body} { variable compile variable methodInfo # FIRST, check the method name against previously defined # methods. Comp.CheckMethodName $method 0 ::snit::methodInfo \ "Error in \"method [list $method]...\"" if {[llength $method] > 1} { set compile(hashierarchic) yes } # Remeber this method lappend compile(localmethods) $method CheckArgs "method [list $method]" $arglist # Next, add magic references to type and self. set arglist [concat type selfns win self $arglist] # Next, add variable declarations to body: set body "%TVARDECS%%IVARDECS%\n# END snit method prolog\n$body" # Next, save the definition script. if {[llength $method] == 1} { set methodInfo($method) {0 "%t::Snit_method%m %t %n %w %s" ""} Mappend compile(defs) { proc %TYPE%::Snit_method%METHOD% %ARGLIST% %BODY% } %METHOD% $method %ARGLIST% [list $arglist] %BODY% [list $body] } else { set methodInfo($method) {0 "%t::Snit_hmethod%j %t %n %w %s" ""} Mappend compile(defs) { proc %TYPE%::Snit_hmethod%JMETHOD% %ARGLIST% %BODY% } %JMETHOD% [join $method _] %ARGLIST% [list $arglist] \ %BODY% [list $body] } } # Check for name collisions; save prefix information. # # method The name of the method or typemethod. # delFlag 1 if delegated, 0 otherwise. # infoVar The fully qualified name of the array containing # information about the defined methods. # errRoot The root string for any error messages. proc ::snit::Comp.CheckMethodName {method delFlag infoVar errRoot} { upvar $infoVar methodInfo # FIRST, make sure the method name is a valid Tcl list. if {[catch {lindex $method 0}]} { error "$errRoot, the name \"$method\" must have list syntax." } # NEXT, check whether we can define it. if {![catch {set methodInfo($method)} data]} { # We can't redefine methods with submethods. if {[lindex $data 0] == 1} { error "$errRoot, \"$method\" has submethods." } # You can't delegate a method that's defined locally, # and you can't define a method locally if it's been delegated. if {$delFlag && "" == [lindex $data 2]} { error "$errRoot, \"$method\" has been defined locally." } elseif {!$delFlag && "" != [lindex $data 2]} { error "$errRoot, \"$method\" has been delegated" } } # Handle hierarchical case. if {[llength $method] > 1} { set prefix {} set tokens $method while {[llength $tokens] > 1} { lappend prefix [lindex $tokens 0] set tokens [lrange $tokens 1 end] if {![catch {set methodInfo($prefix)} result]} { # Prefix is known. If it's not a prefix, throw an # error. if {[lindex $result 0] == 0} { error "$errRoot, \"$prefix\" has no submethods." } } set methodInfo($prefix) [list 1] } } } # Defines a typemethod method. proc ::snit::Comp.statement.typemethod {method arglist body} { variable compile variable typemethodInfo # FIRST, check the typemethod name against previously defined # typemethods. Comp.CheckMethodName $method 0 ::snit::typemethodInfo \ "Error in \"typemethod [list $method]...\"" CheckArgs "typemethod $method" $arglist # First, add magic reference to type. set arglist [concat type $arglist] # Next, add typevariable declarations to body: set body "%TVARDECS%\n# END snit method prolog\n$body" # Next, save the definition script if {[llength $method] == 1} { set typemethodInfo($method) {0 "%t::Snit_typemethod%m %t" ""} Mappend compile(defs) { proc %TYPE%::Snit_typemethod%METHOD% %ARGLIST% %BODY% } %METHOD% $method %ARGLIST% [list $arglist] %BODY% [list $body] } else { set typemethodInfo($method) {0 "%t::Snit_htypemethod%j %t" ""} Mappend compile(defs) { proc %TYPE%::Snit_htypemethod%JMETHOD% %ARGLIST% %BODY% } %JMETHOD% [join $method _] \ %ARGLIST% [list $arglist] %BODY% [list $body] } } # Defines a type constructor. proc ::snit::Comp.statement.typeconstructor {body} { variable compile if {"" != $compile(typeconstructor)} { error "too many typeconstructors" } set compile(typeconstructor) $body } # Defines a static proc in the type's namespace. proc ::snit::Comp.statement.proc {proc arglist body} { variable compile # If "ns" is defined, the proc can see instance variables. if {[lsearch -exact $arglist selfns] != -1} { # Next, add instance variable declarations to body: set body "%IVARDECS%\n$body" } # The proc can always see typevariables. set body "%TVARDECS%\n$body" append compile(defs) " # Proc $proc proc [list %TYPE%::$proc $arglist $body] " } # Defines a static variable in the type's namespace. proc ::snit::Comp.statement.typevariable {name args} { variable compile set errRoot "Error in \"typevariable $name...\"" set len [llength $args] if {$len > 2 || ($len == 2 && "-array" != [lindex $args 0])} { error "$errRoot, too many initializers" } if {[lsearch -exact $compile(varnames) $name] != -1} { error "$errRoot, \"$name\" is already an instance variable" } lappend compile(typevarnames) $name if {$len == 1} { append compile(typevars) \ "\n\t [list ::variable $name [lindex $args 0]]" } elseif {$len == 2} { append compile(typevars) \ "\n\t [list ::variable $name]" append compile(typevars) \ "\n\t [list array set $name [lindex $args 1]]" } else { append compile(typevars) \ "\n\t [list ::variable $name]" } append compile(tvprocdec) "\n\t typevariable ${name}" } # Defines an instance variable; the definition will go in the # type's create typemethod. proc ::snit::Comp.statement.variable {name args} { variable compile set errRoot "Error in \"variable $name...\"" set len [llength $args] if {$len > 2 || ($len == 2 && "-array" != [lindex $args 0])} { error "$errRoot, too many initializers" } if {[lsearch -exact $compile(typevarnames) $name] != -1} { error "$errRoot, \"$name\" is already a typevariable" } lappend compile(varnames) $name if {$len == 1} { append compile(instancevars) \ "\nset \${selfns}::$name [list [lindex $args 0]]\n" } elseif {$len == 2} { append compile(instancevars) \ "\narray set \${selfns}::$name [list [lindex $args 1]]\n" } append compile(ivprocdec) "\n\t " Mappend compile(ivprocdec) {::variable ${selfns}::%N} %N $name } # Defines a typecomponent, and handles component options. # # component The logical name of the delegate # args options. proc ::snit::Comp.statement.typecomponent {component args} { variable compile set errRoot "Error in \"typecomponent $component...\"" # FIRST, define the component Comp.DefineTypecomponent $component $errRoot # NEXT, handle the options. set publicMethod "" set inheritFlag 0 foreach {opt val} $args { switch -exact -- $opt { -public { set publicMethod $val } -inherit { set inheritFlag $val if {![string is boolean $inheritFlag]} { error "typecomponent $component -inherit: expected boolean value, got \"$val\"" } } default { error "typecomponent $component: Invalid option \"$opt\"" } } } # NEXT, if -public specified, define the method. if {"" != $publicMethod} { Comp.statement.delegate typemethod [list $publicMethod *] to $component } # NEXT, if "-inherit 1" is specified, delegate typemethod * to # this component. if {$inheritFlag} { Comp.statement.delegate typemethod "*" to $component } } # Defines a name to be a typecomponent # # The name becomes a typevariable; in addition, it gets a # write trace so that when it is set, all of the component mechanisms # get updated. # # component The component name proc ::snit::Comp.DefineTypecomponent {component {errRoot "Error"}} { variable compile if {[lsearch -exact $compile(varnames) $component] != -1} { error "$errRoot, \"$component\" is already an instance variable" } if {[lsearch -exact $compile(typecomponents) $component] == -1} { # Remember we've done this. lappend compile(typecomponents) $component # Make it a type variable with no initial value Comp.statement.typevariable $component "" # Add a write trace to do the component thing. Mappend compile(typevars) { trace variable %COMP% w \ [list ::snit::RT.TypecomponentTrace [list %TYPE%] %COMP%] } %TYPE% $compile(type) %COMP% $component } } # Defines a component, and handles component options. # # component The logical name of the delegate # args options. # # TBD: Ideally, it should be possible to call this statement multiple # times, possibly changing the option values. To do that, I'd need # to cache the option values and not act on them until *after* I'd # read the entire type definition. proc ::snit::Comp.statement.component {component args} { variable compile set errRoot "Error in \"component $component...\"" # FIRST, define the component Comp.DefineComponent $component $errRoot # NEXT, handle the options. set publicMethod "" set inheritFlag 0 foreach {opt val} $args { switch -exact -- $opt { -public { set publicMethod $val } -inherit { set inheritFlag $val if {![string is boolean $inheritFlag]} { error "component $component -inherit: expected boolean value, got \"$val\"" } } default { error "component $component: Invalid option \"$opt\"" } } } # NEXT, if -public specified, define the method. if {"" != $publicMethod} { Comp.statement.delegate method [list $publicMethod *] to $component } # NEXT, if -inherit is specified, delegate method/option * to # this component. if {$inheritFlag} { Comp.statement.delegate method "*" to $component Comp.statement.delegate option "*" to $component } } # Defines a name to be a component # # The name becomes an instance variable; in addition, it gets a # write trace so that when it is set, all of the component mechanisms # get updated. # # component The component name proc ::snit::Comp.DefineComponent {component {errRoot "Error"}} { variable compile if {[lsearch -exact $compile(typevarnames) $component] != -1} { error "$errRoot, \"$component\" is already a typevariable" } if {[lsearch -exact $compile(components) $component] == -1} { # Remember we've done this. lappend compile(components) $component # Make it an instance variable with no initial value Comp.statement.variable $component "" # Add a write trace to do the component thing. Mappend compile(instancevars) { trace variable ${selfns}::%COMP% w \ [list ::snit::RT.ComponentTrace [list %TYPE%] $selfns %COMP%] } %TYPE% $compile(type) %COMP% $component } } # Creates a delegated method, typemethod, or option. proc ::snit::Comp.statement.delegate {what name args} { # FIRST, dispatch to correct handler. switch $what { typemethod { Comp.DelegatedTypemethod $name $args } method { Comp.DelegatedMethod $name $args } option { Comp.DelegatedOption $name $args } default { error "Error in \"delegate $what $name...\", \"$what\"?" } } if {([llength $args] % 2) != 0} { error "Error in \"delegate $what $name...\", invalid syntax" } } # Creates a delegated typemethod delegating it to a particular # typecomponent or an arbitrary command. # # method The name of the method # arglist Delegation options proc ::snit::Comp.DelegatedTypemethod {method arglist} { variable compile variable typemethodInfo set errRoot "Error in \"delegate typemethod [list $method]...\"" # Next, parse the delegation options. set component "" set target "" set exceptions {} set pattern "" set methodTail [lindex $method end] foreach {opt value} $arglist { switch -exact $opt { to { set component $value } as { set target $value } except { set exceptions $value } using { set pattern $value } default { error "$errRoot, unknown delegation option \"$opt\"" } } } if {"" == $component && "" == $pattern} { error "$errRoot, missing \"to\"" } if {"*" == $methodTail && "" != $target} { error "$errRoot, cannot specify \"as\" with \"*\"" } if {"*" != $methodTail && "" != $exceptions} { error "$errRoot, can only specify \"except\" with \"*\"" } if {"" != $pattern && "" != $target} { error "$errRoot, cannot specify both \"as\" and \"using\"" } foreach token [lrange $method 1 end-1] { if {"*" == $token} { error "$errRoot, \"*\" must be the last token." } } # NEXT, define the component if {"" != $component} { Comp.DefineTypecomponent $component $errRoot } # NEXT, define the pattern. if {"" == $pattern} { if {"*" == $methodTail} { set pattern "%c %m" } elseif {"" != $target} { set pattern "%c $target" } else { set pattern "%c %m" } } # Make sure the pattern is a valid list. if {[catch {lindex $pattern 0} result]} { error "$errRoot, the using pattern, \"$pattern\", is not a valid list" } # NEXT, check the method name against previously defined # methods. Comp.CheckMethodName $method 1 ::snit::typemethodInfo $errRoot set typemethodInfo($method) [list 0 $pattern $component] if {[string equal $methodTail "*"]} { Mappend compile(defs) { set %TYPE%::Snit_info(excepttypemethods) %EXCEPT% } %EXCEPT% [list $exceptions] } } # Creates a delegated method delegating it to a particular # component or command. # # method The name of the method # arglist Delegation options. proc ::snit::Comp.DelegatedMethod {method arglist} { variable compile variable methodInfo set errRoot "Error in \"delegate method [list $method]...\"" # Next, parse the delegation options. set component "" set target "" set exceptions {} set pattern "" set methodTail [lindex $method end] foreach {opt value} $arglist { switch -exact $opt { to { set component $value } as { set target $value } except { set exceptions $value } using { set pattern $value } default { error "$errRoot, unknown delegation option \"$opt\"" } } } if {"" == $component && "" == $pattern} { error "$errRoot, missing \"to\"" } if {"*" == $methodTail && "" != $target} { error "$errRoot, cannot specify \"as\" with \"*\"" } if {"*" != $methodTail && "" != $exceptions} { error "$errRoot, can only specify \"except\" with \"*\"" } if {"" != $pattern && "" != $target} { error "$errRoot, cannot specify both \"as\" and \"using\"" } foreach token [lrange $method 1 end-1] { if {"*" == $token} { error "$errRoot, \"*\" must be the last token." } } # NEXT, we delegate some methods set compile(delegatesmethods) yes # NEXT, define the component. Allow typecomponents. if {"" != $component} { if {[lsearch -exact $compile(typecomponents) $component] == -1} { Comp.DefineComponent $component $errRoot } } # NEXT, define the pattern. if {"" == $pattern} { if {"*" == $methodTail} { set pattern "%c %m" } elseif {"" != $target} { set pattern "%c $target" } else { set pattern "%c %m" } } # Make sure the pattern is a valid list. if {[catch {lindex $pattern 0} result]} { error "$errRoot, the using pattern, \"$pattern\", is not a valid list" } # NEXT, check the method name against previously defined # methods. Comp.CheckMethodName $method 1 ::snit::methodInfo $errRoot # NEXT, save the method info. set methodInfo($method) [list 0 $pattern $component] if {[string equal $methodTail "*"]} { Mappend compile(defs) { set %TYPE%::Snit_info(exceptmethods) %EXCEPT% } %EXCEPT% [list $exceptions] } } # Creates a delegated option, delegating it to a particular # component and, optionally, to a particular option of that # component. # # optionDef The option definition # args definition arguments. proc ::snit::Comp.DelegatedOption {optionDef arglist} { variable compile # First, get the three option names. set option [lindex $optionDef 0] set resourceName [lindex $optionDef 1] set className [lindex $optionDef 2] set errRoot "Error in \"delegate option [list $optionDef]...\"" # Next, parse the delegation options. set component "" set target "" set exceptions {} foreach {opt value} $arglist { switch -exact $opt { to { set component $value } as { set target $value } except { set exceptions $value } default { error "$errRoot, unknown delegation option \"$opt\"" } } } if {"" == $component} { error "$errRoot, missing \"to\"" } if {"*" == $option && "" != $target} { error "$errRoot, cannot specify \"as\" with \"delegate option *\"" } if {"*" != $option && "" != $exceptions} { error "$errRoot, can only specify \"except\" with \"delegate option *\"" } # Next, validate the option name if {"*" != $option} { if {![Comp.OptionNameIsValid $option]} { error "$errRoot, badly named option \"$option\"" } } if {[Contains $option $compile(localoptions)]} { error "$errRoot, \"$option\" has been defined locally" } if {[Contains $option $compile(delegatedoptions)]} { error "$errRoot, \"$option\" is multiply delegated" } # NEXT, define the component Comp.DefineComponent $component $errRoot # Next, define the target option, if not specified. if {![string equal $option "*"] && [string equal $target ""]} { set target $option } # NEXT, save the delegation data. set compile(hasoptions) yes if {![string equal $option "*"]} { lappend compile(delegatedoptions) $option # Next, compute the resource and class names, if they aren't # already defined. if {"" == $resourceName} { set resourceName [string range $option 1 end] } if {"" == $className} { set className [Capitalize $resourceName] } Mappend compile(defs) { set %TYPE%::Snit_optionInfo(islocal-%OPTION%) 0 set %TYPE%::Snit_optionInfo(resource-%OPTION%) %RES% set %TYPE%::Snit_optionInfo(class-%OPTION%) %CLASS% lappend %TYPE%::Snit_optionInfo(delegated) %OPTION% set %TYPE%::Snit_optionInfo(target-%OPTION%) [list %COMP% %TARGET%] lappend %TYPE%::Snit_optionInfo(delegated-%COMP%) %OPTION% } %OPTION% $option \ %COMP% $component \ %TARGET% $target \ %RES% $resourceName \ %CLASS% $className } else { Mappend compile(defs) { set %TYPE%::Snit_optionInfo(starcomp) %COMP% set %TYPE%::Snit_optionInfo(except) %EXCEPT% } %COMP% $component %EXCEPT% [list $exceptions] } } # Exposes a component, effectively making the component's command an # instance method. # # component The logical name of the delegate # "as" sugar; if not "", must be "as" # methodname The desired method name for the component's command, or "" proc ::snit::Comp.statement.expose {component {"as" ""} {methodname ""}} { variable compile # FIRST, define the component Comp.DefineComponent $component # NEXT, define the method just as though it were in the type # definition. if {[string equal $methodname ""]} { set methodname $component } Comp.statement.method $methodname args [Expand { if {[llength $args] == 0} { return $%COMPONENT% } if {[string equal $%COMPONENT% ""]} { error "undefined component \"%COMPONENT%\"" } set cmd [linsert $args 0 $%COMPONENT%] return [uplevel 1 $cmd] } %COMPONENT% $component] } #----------------------------------------------------------------------- # Public commands # Compile a type definition, and return the results as a list of two # items: the fully-qualified type name, and a script that will define # the type when executed. # # which type, widget, or widgetadaptor # type the type name # body the type definition proc ::snit::compile {which type body} { return [Comp.Compile $which $type $body] } proc ::snit::type {type body} { return [Comp.Define [Comp.Compile type $type $body]] } proc ::snit::widget {type body} { return [Comp.Define [Comp.Compile widget $type $body]] } proc ::snit::widgetadaptor {type body} { return [Comp.Define [Comp.Compile widgetadaptor $type $body]] } proc ::snit::typemethod {type method arglist body} { # Make sure the type exists. if {![info exists ${type}::Snit_info]} { error "no such type: \"$type\"" } upvar ${type}::Snit_info Snit_info upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo # FIRST, check the typemethod name against previously defined # typemethods. Comp.CheckMethodName $method 0 ${type}::Snit_typemethodInfo \ "Cannot define \"$method\"" # NEXT, check the arguments CheckArgs "snit::typemethod $type $method" $arglist # Next, add magic reference to type. set arglist [concat type $arglist] # Next, add typevariable declarations to body: set body "$Snit_info(tvardecs)\n$body" # Next, define it. if {[llength $method] == 1} { set Snit_typemethodInfo($method) {0 "%t::Snit_typemethod%m %t" ""} uplevel 1 [list proc ${type}::Snit_typemethod$method $arglist $body] } else { set Snit_typemethodInfo($method) {0 "%t::Snit_htypemethod%j %t" ""} set suffix [join $method _] uplevel 1 [list proc ${type}::Snit_htypemethod$suffix $arglist $body] } } proc ::snit::method {type method arglist body} { # Make sure the type exists. if {![info exists ${type}::Snit_info]} { error "no such type: \"$type\"" } upvar ${type}::Snit_methodInfo Snit_methodInfo upvar ${type}::Snit_info Snit_info # FIRST, check the method name against previously defined # methods. Comp.CheckMethodName $method 0 ${type}::Snit_methodInfo \ "Cannot define \"$method\"" # NEXT, check the arguments CheckArgs "snit::method $type $method" $arglist # Next, add magic references to type and self. set arglist [concat type selfns win self $arglist] # Next, add variable declarations to body: set body "$Snit_info(tvardecs)$Snit_info(ivardecs)\n$body" # Next, define it. if {[llength $method] == 1} { set Snit_methodInfo($method) {0 "%t::Snit_method%m %t %n %w %s" ""} uplevel 1 [list proc ${type}::Snit_method$method $arglist $body] } else { set Snit_methodInfo($method) {0 "%t::Snit_hmethod%j %t %n %w %s" ""} set suffix [join $method _] uplevel 1 [list proc ${type}::Snit_hmethod$suffix $arglist $body] } } # Defines a proc within the compiler; this proc can call other # type definition statements, and thus can be used for meta-programming. proc ::snit::macro {name arglist body} { variable compiler variable reservedwords # FIRST, make sure the compiler is defined. Comp.Init # NEXT, check the macro name against the reserved words if {[lsearch -exact $reservedwords $name] != -1} { error "invalid macro name \"$name\"" } # NEXT, see if the name has a namespace; if it does, define the # namespace. set ns [namespace qualifiers $name] if {"" != $ns} { $compiler eval "namespace eval $ns {}" } # NEXT, define the macro $compiler eval [list _proc $name $arglist $body] } #----------------------------------------------------------------------- # Utility Functions # # These are utility functions used while compiling Snit types. # Builds a template from a tagged list of text blocks, then substitutes # all symbols in the mapTable, returning the expanded template. proc ::snit::Expand {template args} { return [string map $args $template] } # Expands a template and appends it to a variable. proc ::snit::Mappend {varname template args} { upvar $varname myvar append myvar [string map $args $template] } # Checks argument list against reserved args proc ::snit::CheckArgs {which arglist} { variable reservedArgs foreach name $reservedArgs { if {[Contains $name $arglist]} { error "$which's arglist may not contain \"$name\" explicitly" } } } # Returns 1 if a value is in a list, and 0 otherwise. proc ::snit::Contains {value list} { if {[lsearch -exact $list $value] != -1} { return 1 } else { return 0 } } # Capitalizes the first letter of a string. proc ::snit::Capitalize {text} { set first [string index $text 0] set rest [string range $text 1 end] return "[string toupper $first]$rest" } # Converts an arbitrary white-space-delimited string into a list # by splitting on white-space and deleting empty tokens. proc ::snit::Listify {str} { set result {} foreach token [split [string trim $str]] { if {[string length $token] > 0} { lappend result $token } } return $result } #======================================================================= # Snit Runtime Library # # These are procs used by Snit types and widgets at runtime. #----------------------------------------------------------------------- # Object Creation # Creates a new instance of the snit::type given its name and the args. # # type The snit::type # name The instance name # args Args to pass to the constructor proc ::snit::RT.type.typemethod.create {type name args} { variable ${type}::Snit_info variable ${type}::Snit_optionInfo # FIRST, qualify the name. if {![string match "::*" $name]} { # Get caller's namespace; # append :: if not global namespace. set ns [uplevel 1 [list namespace current]] if {"::" != $ns} { append ns "::" } set name "$ns$name" } # NEXT, if %AUTO% appears in the name, generate a unique # command name. Otherwise, ensure that the name isn't in use. if {[string match "*%AUTO%*" $name]} { set name [::snit::RT.UniqueName Snit_info(counter) $type $name] } elseif {$Snit_info(canreplace) && [llength [info commands $name]]} { #kmg-tcl83 # # Had to add this elseif branch to pass test rename-1.5 # # Allowed to replace so must first destroy the prior instance $name destroy } elseif {!$Snit_info(canreplace) && [llength [info commands $name]]} { error "command \"$name\" already exists" } # NEXT, create the instance's namespace. set selfns \ [::snit::RT.UniqueInstanceNamespace Snit_info(counter) $type] namespace eval $selfns {} # NEXT, install the dispatcher RT.MakeInstanceCommand $type $selfns $name # Initialize the options to their defaults. upvar ${selfns}::options options foreach opt $Snit_optionInfo(local) { set options($opt) $Snit_optionInfo(default-$opt) } # Initialize the instance vars to their defaults. # selfns must be defined, as it is used implicitly. ${type}::Snit_instanceVars $selfns # Execute the type's constructor. set errcode [catch { RT.ConstructInstance $type $selfns $name $args } result] if {$errcode} { global errorInfo global errorCode set theInfo $errorInfo set theCode $errorCode ::snit::RT.DestroyObject $type $selfns $name error "Error in constructor: $result" $theInfo $theCode } # NEXT, return the object's name. return $name } # Creates a new instance of the snit::widget or snit::widgetadaptor # given its name and the args. # # type The snit::widget or snit::widgetadaptor # name The instance name # args Args to pass to the constructor proc ::snit::RT.widget.typemethod.create {type name args} { variable ${type}::Snit_info variable ${type}::Snit_optionInfo # FIRST, if %AUTO% appears in the name, generate a unique # command name. if {[string match "*%AUTO%*" $name]} { set name [::snit::RT.UniqueName Snit_info(counter) $type $name] } # NEXT, create the instance's namespace. set selfns \ [::snit::RT.UniqueInstanceNamespace Snit_info(counter) $type] namespace eval $selfns { } # NEXT, Initialize the widget's own options to their defaults. upvar ${selfns}::options options foreach opt $Snit_optionInfo(local) { set options($opt) $Snit_optionInfo(default-$opt) } # Initialize the instance vars to their defaults. ${type}::Snit_instanceVars $selfns # NEXT, if this is a normal widget (not a widget adaptor) then create a # frame as its hull. We set the frame's -class to the user's widgetclass, # or, if none, search for -class in the args list, otherwise default to # the basename of the $type with an initial upper case letter. if {!$Snit_info(isWidgetAdaptor)} { # FIRST, determine the class name set wclass $Snit_info(widgetclass) if {$Snit_info(widgetclass) == ""} { set idx [lsearch -exact $args -class] if {$idx >= 0 && ($idx%2 == 0)} { # -class exists and is in the -option position set wclass [lindex $args [expr {$idx+1}]] set args [lreplace $args $idx [expr {$idx+1}]] } else { set wclass [::snit::Capitalize [namespace tail $type]] } } # NEXT, create the widget set self $name package require Tk ${type}::installhull using $Snit_info(hulltype) -class $wclass # NEXT, let's query the option database for our # widget, now that we know that it exists. foreach opt $Snit_optionInfo(local) { set dbval [RT.OptionDbGet $type $name $opt] if {"" != $dbval} { set options($opt) $dbval } } } # Execute the type's constructor, and verify that it # has a hull. set errcode [catch { RT.ConstructInstance $type $selfns $name $args ::snit::RT.Component $type $selfns hull # Prepare to call the object's destructor when the # event is received. Use a Snit-specific bindtag # so that the widget name's tag is unencumbered. bind Snit$type$name [::snit::Expand { ::snit::RT.DestroyObject %TYPE% %NS% %W } %TYPE% $type %NS% $selfns] # Insert the bindtag into the list of bindtags right # after the widget name. set taglist [bindtags $name] set ndx [lsearch -exact $taglist $name] incr ndx bindtags $name [linsert $taglist $ndx Snit$type$name] } result] if {$errcode} { global errorInfo global errorCode set theInfo $errorInfo set theCode $errorCode ::snit::RT.DestroyObject $type $selfns $name error "Error in constructor: $result" $theInfo $theCode } # NEXT, return the object's name. return $name } # RT.MakeInstanceCommand type selfns instance # # type The object type # selfns The instance namespace # instance The instance name # # Creates the instance proc. proc ::snit::RT.MakeInstanceCommand {type selfns instance} { variable ${type}::Snit_info # FIRST, remember the instance name. The Snit_instance variable # allows the instance to figure out its current name given the # instance namespace. upvar ${selfns}::Snit_instance Snit_instance set Snit_instance $instance # NEXT, qualify the proc name if it's a widget. if {$Snit_info(isWidget)} { set procname ::$instance } else { set procname $instance } # NEXT, install the new proc if {!$Snit_info(simpledispatch)} { set instanceProc $::snit::nominalInstanceProc } else { set instanceProc $::snit::simpleInstanceProc } proc $procname {method args} \ [string map \ [list %SELFNS% $selfns %WIN% $instance %TYPE% $type] \ $instanceProc] #kmg-tcl83 # NEXT, add the trace. ::snit83::traceAddCommand $procname {rename delete} \ [list ::snit::RT.InstanceTrace $type $selfns $instance] } # This proc is called when the instance command is renamed. # If op is delete, then new will always be "", so op is redundant. # # type The fully-qualified type name # selfns The instance namespace # win The original instance/tk window name. # old old instance command name # new new instance command name # op rename or delete # # If the op is delete, we need to clean up the object; otherwise, # we need to track the change. # # NOTE: In Tcl 8.4.2 there's a bug: errors in rename and delete # traces aren't propagated correctly. Instead, they silently # vanish. Add a catch to output any error message. proc ::snit::RT.InstanceTrace {type selfns win old new op} { variable ${type}::Snit_info # Note to developers ... # For Tcl 8.4.0, errors thrown in trace handlers vanish silently. # Therefore we catch them here and create some output to help in # debugging such problems. if {[catch { # FIRST, clean up if necessary if {"" == $new} { if {$Snit_info(isWidget)} { destroy $win } else { ::snit::RT.DestroyObject $type $selfns $win } } else { # Otherwise, track the change. variable ${selfns}::Snit_instance set Snit_instance [uplevel 1 [list namespace which -command $new]] # Also, clear the instance caches, as many cached commands # might be invalid. RT.ClearInstanceCaches $selfns } } result]} { global errorInfo # Pop up the console on Windows wish, to enable stdout. # This clobbers errorInfo on unix, so save it so we can print it. set ei $errorInfo catch {console show} puts "Error in ::snit::RT.InstanceTrace $type $selfns $win $old $new $op:" puts $ei } } # Calls the instance constructor and handles related housekeeping. proc ::snit::RT.ConstructInstance {type selfns instance arglist} { variable ${type}::Snit_optionInfo variable ${selfns}::Snit_iinfo # Track whether we are constructed or not. set Snit_iinfo(constructed) 0 # Call the user's constructor eval [linsert $arglist 0 \ ${type}::Snit_constructor $type $selfns $instance $instance] set Snit_iinfo(constructed) 1 # Validate the initial set of options (including defaults) foreach option $Snit_optionInfo(local) { set value [set ${selfns}::options($option)] if {"" != $Snit_optionInfo(typespec-$option)} { if {[catch { $Snit_optionInfo(typeobj-$option) validate $value } result]} { return -code error "invalid $option default: $result" } } } # Unset the configure cache for all -readonly options. # This ensures that the next time anyone tries to # configure it, an error is thrown. foreach opt $Snit_optionInfo(local) { if {$Snit_optionInfo(readonly-$opt)} { ::snit83::unset -nocomplain ${selfns}::Snit_configureCache($opt) } } return } # Returns a unique command name. # # REQUIRE: type is a fully qualified name. # REQUIRE: name contains "%AUTO%" # PROMISE: the returned command name is unused. proc ::snit::RT.UniqueName {countervar type name} { upvar $countervar counter while 1 { # FIRST, bump the counter and define the %AUTO% instance name; # then substitute it into the specified name. Wrap around at # 2^31 - 2 to prevent overflow problems. incr counter if {$counter > 2147483646} { set counter 0 } set auto "[namespace tail $type]$counter" set candidate [Expand $name %AUTO% $auto] if {![llength [info commands $candidate]]} { return $candidate } } } # Returns a unique instance namespace, fully qualified. # # countervar The name of a counter variable # type The instance's type # # REQUIRE: type is fully qualified # PROMISE: The returned namespace name is unused. proc ::snit::RT.UniqueInstanceNamespace {countervar type} { upvar $countervar counter while 1 { # FIRST, bump the counter and define the namespace name. # Then see if it already exists. Wrap around at # 2^31 - 2 to prevent overflow problems. incr counter if {$counter > 2147483646} { set counter 0 } set ins "${type}::Snit_inst${counter}" if {![namespace exists $ins]} { return $ins } } } # Retrieves an option's value from the option database. # Returns "" if no value is found. proc ::snit::RT.OptionDbGet {type self opt} { variable ${type}::Snit_optionInfo return [option get $self \ $Snit_optionInfo(resource-$opt) \ $Snit_optionInfo(class-$opt)] } #----------------------------------------------------------------------- # Object Destruction # Implements the standard "destroy" method # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name proc ::snit::RT.method.destroy {type selfns win self} { variable ${selfns}::Snit_iinfo # Can't destroy the object if it isn't complete constructed. if {!$Snit_iinfo(constructed)} { return -code error "Called 'destroy' method in constructor" } # Calls Snit_cleanup, which (among other things) calls the # user's destructor. ::snit::RT.DestroyObject $type $selfns $win } # This is the function that really cleans up; it's automatically # called when any instance is destroyed, e.g., by "$object destroy" # for types, and by the event for widgets. # # type The fully-qualified type name. # selfns The instance namespace # win The original instance command name. proc ::snit::RT.DestroyObject {type selfns win} { variable ${type}::Snit_info # If the variable Snit_instance doesn't exist then there's no # instance command for this object -- it's most likely a # widgetadaptor. Consequently, there are some things that # we don't need to do. if {[info exists ${selfns}::Snit_instance]} { upvar ${selfns}::Snit_instance instance # First, remove the trace on the instance name, so that we # don't call RT.DestroyObject recursively. RT.RemoveInstanceTrace $type $selfns $win $instance # Next, call the user's destructor ${type}::Snit_destructor $type $selfns $win $instance # Next, if this isn't a widget, delete the instance command. # If it is a widget, get the hull component's name, and rename # it back to the widget name # Next, delete the hull component's instance command, # if there is one. if {$Snit_info(isWidget)} { set hullcmd [::snit::RT.Component $type $selfns hull] catch {rename $instance ""} # Clear the bind event bind Snit$type$win "" if {[llength [info commands $hullcmd]]} { # FIRST, rename the hull back to its original name. # If the hull is itself a megawidget, it will have its # own cleanup to do, and it might not do it properly # if it doesn't have the right name. rename $hullcmd ::$instance # NEXT, destroy it. destroy $instance } } else { catch {rename $instance ""} } } # Next, delete the instance's namespace. This kills any # instance variables. namespace delete $selfns return } # Remove instance trace # # type The fully qualified type name # selfns The instance namespace # win The original instance name/Tk window name # instance The current instance name proc ::snit::RT.RemoveInstanceTrace {type selfns win instance} { variable ${type}::Snit_info if {$Snit_info(isWidget)} { set procname ::$instance } else { set procname $instance } # NEXT, remove any trace on this name catch { #kmg-tcl83 ::snit83::traceRemoveCommand $procname {rename delete} \ [list ::snit::RT.InstanceTrace $type $selfns $win] } } #----------------------------------------------------------------------- # Typecomponent Management and Method Caching # Typecomponent trace; used for write trace on typecomponent # variables. Saves the new component object name, provided # that certain conditions are met. Also clears the typemethod # cache. proc ::snit::RT.TypecomponentTrace {type component n1 n2 op} { upvar ${type}::Snit_info Snit_info upvar ${type}::${component} cvar upvar ${type}::Snit_typecomponents Snit_typecomponents # Save the new component value. set Snit_typecomponents($component) $cvar # Clear the typemethod cache. # TBD: can we unset just the elements related to # this component? ::snit83::unset -nocomplain -- ${type}::Snit_typemethodCache } # Generates and caches the command for a typemethod. # # type The type # method The name of the typemethod to call. # # The return value is one of the following lists: # # {} There's no such method. # {1} The method has submethods; look again. # {0 } Here's the command to execute. proc snit::RT.CacheTypemethodCommand {type method} { upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo upvar ${type}::Snit_typecomponents Snit_typecomponents upvar ${type}::Snit_typemethodCache Snit_typemethodCache upvar ${type}::Snit_info Snit_info # FIRST, get the pattern data and the typecomponent name. set implicitCreate 0 set instanceName "" set starredMethod [lreplace $method end end *] set methodTail [lindex $method end] if {[info exists Snit_typemethodInfo($method)]} { set key $method } elseif {[info exists Snit_typemethodInfo($starredMethod)]} { if {[lsearch -exact $Snit_info(excepttypemethods) $methodTail] == -1} { set key $starredMethod } else { return [list ] } } elseif {$Snit_info(hasinstances)} { # Assume the unknown name is an instance name to create, unless # this is a widget and the style of the name is wrong, or the # name mimics a standard typemethod. if {[set ${type}::Snit_info(isWidget)] && ![string match ".*" $method]} { return [list ] } # Without this check, the call "$type info" will redefine the # standard "::info" command, with disastrous results. Since it's # a likely thing to do if !-typeinfo, put in an explicit check. if {"info" == $method || "destroy" == $method} { return [list ] } set implicitCreate 1 set instanceName $method set key create set method create } else { return [list ] } foreach {flag pattern compName} $Snit_typemethodInfo($key) {} if {$flag == 1} { return [list 1] } # NEXT, build the substitution list set subList [list \ %% % \ %t $type \ %M $method \ %m [lindex $method end] \ %j [join $method _]] if {"" != $compName} { if {![info exists Snit_typecomponents($compName)]} { error "$type delegates typemethod \"$method\" to undefined typecomponent \"$compName\"" } lappend subList %c [list $Snit_typecomponents($compName)] } set command {} foreach subpattern $pattern { lappend command [string map $subList $subpattern] } if {$implicitCreate} { # In this case, $method is the name of the instance to # create. Don't cache, as we usually won't do this one # again. lappend command $instanceName } else { set Snit_typemethodCache($method) [list 0 $command] } return [list 0 $command] } #----------------------------------------------------------------------- # Component Management and Method Caching # Retrieves the object name given the component name. proc ::snit::RT.Component {type selfns name} { variable ${selfns}::Snit_components if {[catch {set Snit_components($name)} result]} { variable ${selfns}::Snit_instance error "component \"$name\" is undefined in $type $Snit_instance" } return $result } # Component trace; used for write trace on component instance # variables. Saves the new component object name, provided # that certain conditions are met. Also clears the method # cache. proc ::snit::RT.ComponentTrace {type selfns component n1 n2 op} { upvar ${type}::Snit_info Snit_info upvar ${selfns}::${component} cvar upvar ${selfns}::Snit_components Snit_components # If they try to redefine the hull component after # it's been defined, that's an error--but only if # this is a widget or widget adaptor. if {"hull" == $component && $Snit_info(isWidget) && [info exists Snit_components($component)]} { set cvar $Snit_components($component) error "The hull component cannot be redefined" } # Save the new component value. set Snit_components($component) $cvar # Clear the instance caches. # TBD: can we unset just the elements related to # this component? RT.ClearInstanceCaches $selfns } # Generates and caches the command for a method. # # type: The instance's type # selfns: The instance's private namespace # win: The instance's original name (a Tk widget name, for # snit::widgets. # self: The instance's current name. # method: The name of the method to call. # # The return value is one of the following lists: # # {} There's no such method. # {1} The method has submethods; look again. # {0 } Here's the command to execute. proc ::snit::RT.CacheMethodCommand {type selfns win self method} { variable ${type}::Snit_info variable ${type}::Snit_methodInfo variable ${type}::Snit_typecomponents variable ${selfns}::Snit_components variable ${selfns}::Snit_methodCache # FIRST, get the pattern data and the component name. set starredMethod [lreplace $method end end *] set methodTail [lindex $method end] if {[info exists Snit_methodInfo($method)]} { set key $method } elseif {[info exists Snit_methodInfo($starredMethod)] && [lsearch -exact $Snit_info(exceptmethods) $methodTail] == -1} { set key $starredMethod } else { return [list ] } foreach {flag pattern compName} $Snit_methodInfo($key) {} if {$flag == 1} { return [list 1] } # NEXT, build the substitution list set subList [list \ %% % \ %t $type \ %M $method \ %m [lindex $method end] \ %j [join $method _] \ %n [list $selfns] \ %w [list $win] \ %s [list $self]] if {"" != $compName} { if {[info exists Snit_components($compName)]} { set compCmd $Snit_components($compName) } elseif {[info exists Snit_typecomponents($compName)]} { set compCmd $Snit_typecomponents($compName) } else { error "$type $self delegates method \"$method\" to undefined component \"$compName\"" } lappend subList %c [list $compCmd] } # Note: The cached command will executed faster if it's # already a list. set command {} foreach subpattern $pattern { lappend command [string map $subList $subpattern] } set commandRec [list 0 $command] set Snit_methodCache($method) $commandRec return $commandRec } # Looks up a method's command. # # type: The instance's type # selfns: The instance's private namespace # win: The instance's original name (a Tk widget name, for # snit::widgets. # self: The instance's current name. # method: The name of the method to call. # errPrefix: Prefix for any error method proc ::snit::RT.LookupMethodCommand {type selfns win self method errPrefix} { set commandRec [snit::RT.CacheMethodCommand \ $type $selfns $win $self \ $method] if {[llength $commandRec] == 0} { return -code error \ "$errPrefix, \"$self $method\" is not defined" } elseif {[lindex $commandRec 0] == 1} { return -code error \ "$errPrefix, wrong number args: should be \"$self\" $method method args" } return [lindex $commandRec 1] } # Clears all instance command caches proc ::snit::RT.ClearInstanceCaches {selfns} { ::snit83::unset -nocomplain -- ${selfns}::Snit_methodCache ::snit83::unset -nocomplain -- ${selfns}::Snit_cgetCache ::snit83::unset -nocomplain -- ${selfns}::Snit_configureCache ::snit83::unset -nocomplain -- ${selfns}::Snit_validateCache } #----------------------------------------------------------------------- # Component Installation # Implements %TYPE%::installhull. The variables self and selfns # must be defined in the caller's context. # # Installs the named widget as the hull of a # widgetadaptor. Once the widget is hijacked, its new name # is assigned to the hull component. proc ::snit::RT.installhull {type {using "using"} {widgetType ""} args} { variable ${type}::Snit_info variable ${type}::Snit_optionInfo upvar self self upvar selfns selfns upvar ${selfns}::hull hull upvar ${selfns}::options options # FIRST, make sure we can do it. if {!$Snit_info(isWidget)} { error "installhull is valid only for snit::widgetadaptors" } if {[info exists ${selfns}::Snit_instance]} { error "hull already installed for $type $self" } # NEXT, has it been created yet? If not, create it using # the specified arguments. if {"using" == $using} { # FIRST, create the widget set cmd [linsert $args 0 $widgetType $self] set obj [uplevel 1 $cmd] # NEXT, for each option explicitly delegated to the hull # that doesn't appear in the usedOpts list, get the # option database value and apply it--provided that the # real option name and the target option name are different. # (If they are the same, then the option database was # already queried as part of the normal widget creation.) # # Also, we don't need to worry about implicitly delegated # options, as the option and target option names must be # the same. if {[info exists Snit_optionInfo(delegated-hull)]} { # FIRST, extract all option names from args set usedOpts {} set ndx [lsearch -glob $args "-*"] foreach {opt val} [lrange $args $ndx end] { lappend usedOpts $opt } foreach opt $Snit_optionInfo(delegated-hull) { set target [lindex $Snit_optionInfo(target-$opt) 1] if {"$target" == $opt} { continue } set result [lsearch -exact $usedOpts $target] if {$result != -1} { continue } set dbval [RT.OptionDbGet $type $self $opt] $obj configure $target $dbval } } } else { set obj $using if {![string equal $obj $self]} { error \ "hull name mismatch: \"$obj\" != \"$self\"" } } # NEXT, get the local option defaults. foreach opt $Snit_optionInfo(local) { set dbval [RT.OptionDbGet $type $self $opt] if {"" != $dbval} { set options($opt) $dbval } } # NEXT, do the magic set i 0 while 1 { incr i set newName "::hull${i}$self" if {![llength [info commands $newName]]} { break } } rename ::$self $newName RT.MakeInstanceCommand $type $selfns $self # Note: this relies on RT.ComponentTrace to do the dirty work. set hull $newName return } # Implements %TYPE%::install. # # Creates a widget and installs it as the named component. # It expects self and selfns to be defined in the caller's context. proc ::snit::RT.install {type compName "using" widgetType winPath args} { variable ${type}::Snit_optionInfo variable ${type}::Snit_info upvar self self upvar selfns selfns upvar ${selfns}::$compName comp upvar ${selfns}::hull hull # We do the magic option database stuff only if $self is # a widget. if {$Snit_info(isWidget)} { if {"" == $hull} { error "tried to install \"$compName\" before the hull exists" } # FIRST, query the option database and save the results # into args. Insert them before the first option in the # list, in case there are any non-standard parameters. # # Note: there might not be any delegated options; if so, # don't bother. if {[info exists Snit_optionInfo(delegated-$compName)]} { set ndx [lsearch -glob $args "-*"] foreach opt $Snit_optionInfo(delegated-$compName) { set dbval [RT.OptionDbGet $type $self $opt] if {"" != $dbval} { set target [lindex $Snit_optionInfo(target-$opt) 1] set args [linsert $args $ndx $target $dbval] } } } } # NEXT, create the component and save it. set cmd [concat [list $widgetType $winPath] $args] set comp [uplevel 1 $cmd] # NEXT, handle the option database for "delegate option *", # in widgets only. if {$Snit_info(isWidget) && [string equal $Snit_optionInfo(starcomp) $compName]} { # FIRST, get the list of option specs from the widget. # If configure doesn't work, skip it. if {[catch {$comp configure} specs]} { return } # NEXT, get the set of explicitly used options from args set usedOpts {} set ndx [lsearch -glob $args "-*"] foreach {opt val} [lrange $args $ndx end] { lappend usedOpts $opt } # NEXT, "delegate option *" matches all options defined # by this widget that aren't defined by the widget as a whole, # and that aren't excepted. Plus, we skip usedOpts. So build # a list of the options it can't match. set skiplist [concat \ $usedOpts \ $Snit_optionInfo(except) \ $Snit_optionInfo(local) \ $Snit_optionInfo(delegated)] # NEXT, loop over all of the component's options, and set # any not in the skip list for which there is an option # database value. foreach spec $specs { # Skip aliases if {[llength $spec] != 5} { continue } set opt [lindex $spec 0] if {[lsearch -exact $skiplist $opt] != -1} { continue } set res [lindex $spec 1] set cls [lindex $spec 2] set dbvalue [option get $self $res $cls] if {"" != $dbvalue} { $comp configure $opt $dbvalue } } } return } #----------------------------------------------------------------------- # Method/Variable Name Qualification # Implements %TYPE%::variable. Requires selfns. proc ::snit::RT.variable {varname} { upvar selfns selfns if {![string match "::*" $varname]} { uplevel 1 [list upvar 1 ${selfns}::$varname $varname] } else { # varname is fully qualified; let the standard # "variable" command handle it. uplevel 1 [list ::variable $varname] } } # Fully qualifies a typevariable name. # # This is used to implement the mytypevar command. proc ::snit::RT.mytypevar {type name} { return ${type}::$name } # Fully qualifies an instance variable name. # # This is used to implement the myvar command. proc ::snit::RT.myvar {name} { upvar selfns selfns return ${selfns}::$name } # Use this like "list" to convert a proc call into a command # string to pass to another object (e.g., as a -command). # Qualifies the proc name properly. # # This is used to implement the "myproc" command. proc ::snit::RT.myproc {type procname args} { set procname "${type}::$procname" return [linsert $args 0 $procname] } # DEPRECATED proc ::snit::RT.codename {type name} { return "${type}::$name" } # Use this like "list" to convert a typemethod call into a command # string to pass to another object (e.g., as a -command). # Inserts the type command at the beginning. # # This is used to implement the "mytypemethod" command. proc ::snit::RT.mytypemethod {type args} { return [linsert $args 0 $type] } # Use this like "list" to convert a method call into a command # string to pass to another object (e.g., as a -command). # Inserts the code at the beginning to call the right object, even if # the object's name has changed. Requires that selfns be defined # in the calling context, eg. can only be called in instance # code. # # This is used to implement the "mymethod" command. proc ::snit::RT.mymethod {args} { upvar selfns selfns return [linsert $args 0 ::snit::RT.CallInstance ${selfns}] } # Calls an instance method for an object given its # instance namespace and remaining arguments (the first of which # will be the method name. # # selfns The instance namespace # args The arguments # # Uses the selfns to determine $self, and calls the method # in the normal way. # # This is used to implement the "mymethod" command. proc ::snit::RT.CallInstance {selfns args} { upvar ${selfns}::Snit_instance self set retval [catch {uplevel 1 [linsert $args 0 $self]} result] if {$retval} { if {$retval == 1} { global errorInfo global errorCode return -code error -errorinfo $errorInfo \ -errorcode $errorCode $result } else { return -code $retval $result } } return $result } # Looks for the named option in the named variable. If found, # it and its value are removed from the list, and the value # is returned. Otherwise, the default value is returned. # If the option is undelegated, it's own default value will be # used if none is specified. # # Implements the "from" command. proc ::snit::RT.from {type argvName option {defvalue ""}} { variable ${type}::Snit_optionInfo upvar $argvName argv set ioption [lsearch -exact $argv $option] if {$ioption == -1} { if {"" == $defvalue && [info exists Snit_optionInfo(default-$option)]} { return $Snit_optionInfo(default-$option) } else { return $defvalue } } set ivalue [expr {$ioption + 1}] set value [lindex $argv $ivalue] set argv [lreplace $argv $ioption $ivalue] return $value } #----------------------------------------------------------------------- # Type Destruction # Implements the standard "destroy" typemethod: # Destroys a type completely. # # type The snit type proc ::snit::RT.typemethod.destroy {type} { variable ${type}::Snit_info # FIRST, destroy all instances foreach selfns [namespace children $type] { if {![namespace exists $selfns]} { continue } upvar ${selfns}::Snit_instance obj if {$Snit_info(isWidget)} { destroy $obj } else { if {[llength [info commands $obj]]} { $obj destroy } } } # NEXT, destroy the type's data. namespace delete $type # NEXT, get rid of the type command. rename $type "" } #----------------------------------------------------------------------- # Option Handling # Implements the standard "cget" method # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # option The name of the option proc ::snit::RT.method.cget {type selfns win self option} { if {[catch {set ${selfns}::Snit_cgetCache($option)} command]} { set command [snit::RT.CacheCgetCommand $type $selfns $win $self $option] if {[llength $command] == 0} { return -code error "unknown option \"$option\"" } } uplevel 1 $command } # Retrieves and caches the command that implements "cget" for the # specified option. # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # option The name of the option proc ::snit::RT.CacheCgetCommand {type selfns win self option} { variable ${type}::Snit_optionInfo variable ${selfns}::Snit_cgetCache if {[info exists Snit_optionInfo(islocal-$option)]} { # We know the item; it's either local, or explicitly delegated. if {$Snit_optionInfo(islocal-$option)} { # It's a local option. If it has a cget method defined, # use it; otherwise just return the value. if {"" == $Snit_optionInfo(cget-$option)} { set command [list set ${selfns}::options($option)] } else { set command [snit::RT.LookupMethodCommand \ $type $selfns $win $self \ $Snit_optionInfo(cget-$option) \ "can't cget $option"] lappend command $option } set Snit_cgetCache($option) $command return $command } # Explicitly delegated option; get target set comp [lindex $Snit_optionInfo(target-$option) 0] set target [lindex $Snit_optionInfo(target-$option) 1] } elseif {"" != $Snit_optionInfo(starcomp) && [lsearch -exact $Snit_optionInfo(except) $option] == -1} { # Unknown option, but unknowns are delegated; get target. set comp $Snit_optionInfo(starcomp) set target $option } else { return "" } # Get the component's object. set obj [RT.Component $type $selfns $comp] set command [list $obj cget $target] set Snit_cgetCache($option) $command return $command } # Implements the standard "configurelist" method # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # optionlist A list of options and their values. proc ::snit::RT.method.configurelist {type selfns win self optionlist} { variable ${type}::Snit_optionInfo foreach {option value} $optionlist { # FIRST, get the configure command, caching it if need be. if {[catch {set ${selfns}::Snit_configureCache($option)} command]} { set command [snit::RT.CacheConfigureCommand \ $type $selfns $win $self $option] if {[llength $command] == 0} { return -code error "unknown option \"$option\"" } } # NEXT, if we have a type-validation object, use it. # TBD: Should test (islocal-$option) here, but islocal # isn't defined for implicitly delegated options. if {[info exists Snit_optionInfo(typeobj-$option)] && "" != $Snit_optionInfo(typeobj-$option)} { if {[catch { $Snit_optionInfo(typeobj-$option) validate $value } result]} { return -code error "invalid $option value: $result" } } # NEXT, the caching the configure command also cached the # validate command, if any. If we have one, run it. set valcommand [set ${selfns}::Snit_validateCache($option)] if {[llength $valcommand]} { lappend valcommand $value uplevel 1 $valcommand } # NEXT, configure the option with the value. lappend command $value uplevel 1 $command } return } # Retrieves and caches the command that stores the named option. # Also stores the command that validates the name option if any; # If none, the validate command is "", so that the cache is always # populated. # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # option An option name proc ::snit::RT.CacheConfigureCommand {type selfns win self option} { variable ${type}::Snit_optionInfo variable ${selfns}::Snit_configureCache variable ${selfns}::Snit_validateCache if {[info exist Snit_optionInfo(islocal-$option)]} { # We know the item; it's either local, or explicitly delegated. if {$Snit_optionInfo(islocal-$option)} { # It's a local option. # If it's readonly, it throws an error if we're already # constructed. if {$Snit_optionInfo(readonly-$option)} { if {[set ${selfns}::Snit_iinfo(constructed)]} { error "option $option can only be set at instance creation" } } # If it has a validate method, cache that for later. if {"" != $Snit_optionInfo(validate-$option)} { set command [snit::RT.LookupMethodCommand \ $type $selfns $win $self \ $Snit_optionInfo(validate-$option) \ "can't validate $option"] lappend command $option set Snit_validateCache($option) $command } else { set Snit_validateCache($option) "" } # If it has a configure method defined, # cache it; otherwise, just set the value. if {"" == $Snit_optionInfo(configure-$option)} { set command [list set ${selfns}::options($option)] } else { set command [snit::RT.LookupMethodCommand \ $type $selfns $win $self \ $Snit_optionInfo(configure-$option) \ "can't configure $option"] lappend command $option } set Snit_configureCache($option) $command return $command } # Delegated option: get target. set comp [lindex $Snit_optionInfo(target-$option) 0] set target [lindex $Snit_optionInfo(target-$option) 1] } elseif {$Snit_optionInfo(starcomp) != "" && [lsearch -exact $Snit_optionInfo(except) $option] == -1} { # Unknown option, but unknowns are delegated. set comp $Snit_optionInfo(starcomp) set target $option } else { return "" } # There is no validate command in this case; save an empty string. set Snit_validateCache($option) "" # Get the component's object set obj [RT.Component $type $selfns $comp] set command [list $obj configure $target] set Snit_configureCache($option) $command return $command } # Implements the standard "configure" method # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # args A list of options and their values, possibly empty. proc ::snit::RT.method.configure {type selfns win self args} { # If two or more arguments, set values as usual. if {[llength $args] >= 2} { ::snit::RT.method.configurelist $type $selfns $win $self $args return } # If zero arguments, acquire data for each known option # and return the list if {[llength $args] == 0} { set result {} foreach opt [RT.method.info.options $type $selfns $win $self] { # Refactor this, so that we don't need to call via $self. lappend result [RT.GetOptionDbSpec \ $type $selfns $win $self $opt] } return $result } # They want it for just one. set opt [lindex $args 0] return [RT.GetOptionDbSpec $type $selfns $win $self $opt] } # Retrieves the option database spec for a single option. # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # option The name of an option # # TBD: This is a bad name. What it's returning is the # result of the configure query. proc ::snit::RT.GetOptionDbSpec {type selfns win self opt} { variable ${type}::Snit_optionInfo upvar ${selfns}::Snit_components Snit_components upvar ${selfns}::options options if {[info exists options($opt)]} { # This is a locally-defined option. Just build the # list and return it. set res $Snit_optionInfo(resource-$opt) set cls $Snit_optionInfo(class-$opt) set def $Snit_optionInfo(default-$opt) return [list $opt $res $cls $def \ [RT.method.cget $type $selfns $win $self $opt]] } elseif {[info exists Snit_optionInfo(target-$opt)]} { # This is an explicitly delegated option. The only # thing we don't have is the default. set res $Snit_optionInfo(resource-$opt) set cls $Snit_optionInfo(class-$opt) # Get the default set logicalName [lindex $Snit_optionInfo(target-$opt) 0] set comp $Snit_components($logicalName) set target [lindex $Snit_optionInfo(target-$opt) 1] if {[catch {$comp configure $target} result]} { set defValue {} } else { set defValue [lindex $result 3] } return [list $opt $res $cls $defValue [$self cget $opt]] } elseif {"" != $Snit_optionInfo(starcomp) && [lsearch -exact $Snit_optionInfo(except) $opt] == -1} { set logicalName $Snit_optionInfo(starcomp) set target $opt set comp $Snit_components($logicalName) if {[catch {set value [$comp cget $target]} result]} { error "unknown option \"$opt\"" } if {![catch {$comp configure $target} result]} { # Replace the delegated option name with the local name. return [::snit::Expand $result $target $opt] } # configure didn't work; return simple form. return [list $opt "" "" "" $value] } else { error "unknown option \"$opt\"" } } #----------------------------------------------------------------------- # Type Introspection # Implements the standard "info" typemethod. # # type The snit type # command The info subcommand # args All other arguments. proc ::snit::RT.typemethod.info {type command args} { global errorInfo global errorCode switch -exact $command { args - body - default - typevars - typemethods - instances { # TBD: it should be possible to delete this error # handling. set errflag [catch { uplevel 1 [linsert $args 0 \ ::snit::RT.typemethod.info.$command $type] } result] if {$errflag} { return -code error -errorinfo $errorInfo \ -errorcode $errorCode $result } else { return $result } } default { error "\"$type info $command\" is not defined" } } } # Returns a list of the type's typevariables whose names match a # pattern, excluding Snit internal variables. # # type A Snit type # pattern Optional. The glob pattern to match. Defaults # to *. proc ::snit::RT.typemethod.info.typevars {type {pattern *}} { set result {} foreach name [info vars "${type}::$pattern"] { set tail [namespace tail $name] if {![string match "Snit_*" $tail]} { lappend result $name } } return $result } # Returns a list of the type's methods whose names match a # pattern. If "delegate typemethod *" is used, the list may # not be complete. # # type A Snit type # pattern Optional. The glob pattern to match. Defaults # to *. proc ::snit::RT.typemethod.info.typemethods {type {pattern *}} { variable ${type}::Snit_typemethodInfo variable ${type}::Snit_typemethodCache # FIRST, get the explicit names, skipping prefixes. set result {} foreach name [array names Snit_typemethodInfo $pattern] { if {[lindex $Snit_typemethodInfo($name) 0] != 1} { lappend result $name } } # NEXT, add any from the cache that aren't explicit. if {[info exists Snit_typemethodInfo(*)]} { # First, remove "*" from the list. set ndx [lsearch -exact $result "*"] if {$ndx != -1} { set result [lreplace $result $ndx $ndx] } foreach name [array names Snit_typemethodCache $pattern] { if {[lsearch -exact $result $name] == -1} { lappend result $name } } } return $result } # $type info args # # Returns a method's list of arguments. does not work for delegated # methods, nor for the internal dispatch methods of multi-word # methods. proc ::snit::RT.typemethod.info.args {type method} { upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo # Snit_methodInfo: method -> list (flag cmd component) # flag : 1 -> internal dispatcher for multi-word method. # 0 -> regular method # # cmd : template mapping from method to command prefix, may # contain placeholders for various pieces of information. # # component : is empty for normal methods. #parray Snit_typemethodInfo if {![info exists Snit_typemethodInfo($method)]} { return -code error "Unknown typemethod \"$method\"" } foreach {flag cmd component} $Snit_typemethodInfo($method) break if {$flag} { return -code error "Unknown typemethod \"$method\"" } if {$component != ""} { return -code error "Delegated typemethod \"$method\"" } set map [list %m $method %j [join $method _] %t $type] set theproc [lindex [string map $map $cmd] 0] return [lrange [::info args $theproc] 1 end] } # $type info body # # Returns a method's body. does not work for delegated # methods, nor for the internal dispatch methods of multi-word # methods. proc ::snit::RT.typemethod.info.body {type method} { upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo # Snit_methodInfo: method -> list (flag cmd component) # flag : 1 -> internal dispatcher for multi-word method. # 0 -> regular method # # cmd : template mapping from method to command prefix, may # contain placeholders for various pieces of information. # # component : is empty for normal methods. #parray Snit_typemethodInfo if {![info exists Snit_typemethodInfo($method)]} { return -code error "Unknown typemethod \"$method\"" } foreach {flag cmd component} $Snit_typemethodInfo($method) break if {$flag} { return -code error "Unknown typemethod \"$method\"" } if {$component != ""} { return -code error "Delegated typemethod \"$method\"" } set map [list %m $method %j [join $method _] %t $type] set theproc [lindex [string map $map $cmd] 0] return [RT.body [::info body $theproc]] } # $type info default # # Returns a method's list of arguments. does not work for delegated # methods, nor for the internal dispatch methods of multi-word # methods. proc ::snit::RT.typemethod.info.default {type method aname dvar} { upvar 1 $dvar def upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo # Snit_methodInfo: method -> list (flag cmd component) # flag : 1 -> internal dispatcher for multi-word method. # 0 -> regular method # # cmd : template mapping from method to command prefix, may # contain placeholders for various pieces of information. # # component : is empty for normal methods. #parray Snit_methodInfo if {![info exists Snit_typemethodInfo($method)]} { return -code error "Unknown typemethod \"$method\"" } foreach {flag cmd component} $Snit_typemethodInfo($method) break if {$flag} { return -code error "Unknown typemethod \"$method\"" } if {$component != ""} { return -code error "Delegated typemethod \"$method\"" } set map [list %m $method %j [join $method _] %t $type] set theproc [lindex [string map $map $cmd] 0] return [::info default $theproc $aname def] } # Returns a list of the type's instances whose names match # a pattern. # # type A Snit type # pattern Optional. The glob pattern to match # Defaults to * # # REQUIRE: type is fully qualified. proc ::snit::RT.typemethod.info.instances {type {pattern *}} { set result {} foreach selfns [namespace children $type] { upvar ${selfns}::Snit_instance instance if {[string match $pattern $instance]} { lappend result $instance } } return $result } #----------------------------------------------------------------------- # Instance Introspection # Implements the standard "info" method. # # type The snit type # selfns The instance's instance namespace # win The instance's original name # self The instance's current name # command The info subcommand # args All other arguments. proc ::snit::RT.method.info {type selfns win self command args} { switch -exact $command { args - body - default - type - vars - options - methods - typevars - typemethods { set errflag [catch { uplevel 1 [linsert $args 0 ::snit::RT.method.info.$command \ $type $selfns $win $self] } result] if {$errflag} { global errorInfo return -code error -errorinfo $errorInfo $result } else { return $result } } default { # error "\"$self info $command\" is not defined" return -code error "\"$self info $command\" is not defined" } } } # $self info type # # Returns the instance's type proc ::snit::RT.method.info.type {type selfns win self} { return $type } # $self info typevars # # Returns the instance's type's typevariables proc ::snit::RT.method.info.typevars {type selfns win self {pattern *}} { return [RT.typemethod.info.typevars $type $pattern] } # $self info typemethods # # Returns the instance's type's typemethods proc ::snit::RT.method.info.typemethods {type selfns win self {pattern *}} { return [RT.typemethod.info.typemethods $type $pattern] } # Returns a list of the instance's methods whose names match a # pattern. If "delegate method *" is used, the list may # not be complete. # # type A Snit type # selfns The instance namespace # win The original instance name # self The current instance name # pattern Optional. The glob pattern to match. Defaults # to *. proc ::snit::RT.method.info.methods {type selfns win self {pattern *}} { variable ${type}::Snit_methodInfo variable ${selfns}::Snit_methodCache # FIRST, get the explicit names, skipping prefixes. set result {} foreach name [array names Snit_methodInfo $pattern] { if {[lindex $Snit_methodInfo($name) 0] != 1} { lappend result $name } } # NEXT, add any from the cache that aren't explicit. if {[info exists Snit_methodInfo(*)]} { # First, remove "*" from the list. set ndx [lsearch -exact $result "*"] if {$ndx != -1} { set result [lreplace $result $ndx $ndx] } foreach name [array names Snit_methodCache $pattern] { if {[lsearch -exact $result $name] == -1} { lappend result $name } } } return $result } # $self info args # # Returns a method's list of arguments. does not work for delegated # methods, nor for the internal dispatch methods of multi-word # methods. proc ::snit::RT.method.info.args {type selfns win self method} { upvar ${type}::Snit_methodInfo Snit_methodInfo # Snit_methodInfo: method -> list (flag cmd component) # flag : 1 -> internal dispatcher for multi-word method. # 0 -> regular method # # cmd : template mapping from method to command prefix, may # contain placeholders for various pieces of information. # # component : is empty for normal methods. #parray Snit_methodInfo if {![info exists Snit_methodInfo($method)]} { return -code error "Unknown method \"$method\"" } foreach {flag cmd component} $Snit_methodInfo($method) break if {$flag} { return -code error "Unknown method \"$method\"" } if {$component != ""} { return -code error "Delegated method \"$method\"" } set map [list %m $method %j [join $method _] %t $type %n $selfns %w $win %s $self] set theproc [lindex [string map $map $cmd] 0] return [lrange [::info args $theproc] 4 end] } # $self info body # # Returns a method's body. does not work for delegated # methods, nor for the internal dispatch methods of multi-word # methods. proc ::snit::RT.method.info.body {type selfns win self method} { upvar ${type}::Snit_methodInfo Snit_methodInfo # Snit_methodInfo: method -> list (flag cmd component) # flag : 1 -> internal dispatcher for multi-word method. # 0 -> regular method # # cmd : template mapping from method to command prefix, may # contain placeholders for various pieces of information. # # component : is empty for normal methods. #parray Snit_methodInfo if {![info exists Snit_methodInfo($method)]} { return -code error "Unknown method \"$method\"" } foreach {flag cmd component} $Snit_methodInfo($method) break if {$flag} { return -code error "Unknown method \"$method\"" } if {$component != ""} { return -code error "Delegated method \"$method\"" } set map [list %m $method %j [join $method _] %t $type %n $selfns %w $win %s $self] set theproc [lindex [string map $map $cmd] 0] return [RT.body [::info body $theproc]] } # $self info default # # Returns a method's list of arguments. does not work for delegated # methods, nor for the internal dispatch methods of multi-word # methods. proc ::snit::RT.method.info.default {type selfns win self method aname dvar} { upvar 1 $dvar def upvar ${type}::Snit_methodInfo Snit_methodInfo # Snit_methodInfo: method -> list (flag cmd component) # flag : 1 -> internal dispatcher for multi-word method. # 0 -> regular method # # cmd : template mapping from method to command prefix, may # contain placeholders for various pieces of information. # # component : is empty for normal methods. if {![info exists Snit_methodInfo($method)]} { return -code error "Unknown method \"$method\"" } foreach {flag cmd component} $Snit_methodInfo($method) break if {$flag} { return -code error "Unknown method \"$method\"" } if {$component != ""} { return -code error "Delegated method \"$method\"" } set map [list %m $method %j [join $method _] %t $type %n $selfns %w $win %s $self] set theproc [lindex [string map $map $cmd] 0] return [::info default $theproc $aname def] } # $self info vars # # Returns the instance's instance variables proc ::snit::RT.method.info.vars {type selfns win self {pattern *}} { set result {} foreach name [info vars "${selfns}::$pattern"] { set tail [namespace tail $name] if {![string match "Snit_*" $tail]} { lappend result $name } } return $result } # $self info options # # Returns a list of the names of the instance's options proc ::snit::RT.method.info.options {type selfns win self {pattern *}} { variable ${type}::Snit_optionInfo # First, get the local and explicitly delegated options set result [concat $Snit_optionInfo(local) $Snit_optionInfo(delegated)] # If "configure" works as for Tk widgets, add the resulting # options to the list. Skip excepted options if {"" != $Snit_optionInfo(starcomp)} { upvar ${selfns}::Snit_components Snit_components set logicalName $Snit_optionInfo(starcomp) set comp $Snit_components($logicalName) if {![catch {$comp configure} records]} { foreach record $records { set opt [lindex $record 0] if {[lsearch -exact $result $opt] == -1 && [lsearch -exact $Snit_optionInfo(except) $opt] == -1} { lappend result $opt } } } } # Next, apply the pattern set names {} foreach name $result { if {[string match $pattern $name]} { lappend names $name } } return $names } proc ::snit::RT.body {body} { regsub -all ".*# END snit method prolog\n" $body {} body return $body } amsn-0.98.9/utils/pixmapprogbar/0000755000175000017500000000000011757711634016420 5ustar billiobbilliobamsn-0.98.9/utils/pixmapprogbar/trough.gif0000644000175000017500000000061710252127467020415 0ustar billiobbilliobGIF89aN!Created with The GIMP! ,N0IWx7յy5An+xn kq"&{{˪NeiƏШnZ!:Z`8 Zn -r89uj~dxlvxr{m{wsv~~nȼпŵ¸ý(=iKhp@Â5H!-:x<.)z,XbB#5Tiq%Ɂ3XRI7Mύ>3ϛE*]ʴӛ ;amsn-0.98.9/utils/pixmapprogbar/pixmapprogbar.tcl0000644000175000017500000000470510252127467021777 0ustar billiobbilliobpackage require snit package require scalable-bg snit::widget pixmapprogbar { variable progress variable barwidth option -font -configuremethod SetFont option -foreground -configuremethod SetFg -default black -cgetmethod GetFg option -fg -configuremethod SetFg -cgetmethod GetFg option -overforeground -configuremethod SetOverFg -default white -cgetmethod GetOverFg option -overfg -configuremethod SetOverFg -cgetmethod GetOverFg component trough delegate option * to trough constructor { args } { install trough using canvas $win.c -bg white -highlightthickness 0 -relief flat $self configurelist $args set troughimg [image create photo -file trough.gif] scalable-bg trough -source $troughimg -width [$trough cget -width] -height [$trough cget -height] -n 1 -w 1 -s 1 -e 1 set barimg [image create photo -file bar.gif] scalable-bg bar -source $barimg -width 0 -height [$trough cget -height] -n 3 -w 3 -s 6 -e 6 set progress 0 set barwidth 0 $trough create image 0 0 -anchor nw -image [trough name] -tag trough $trough create image 0 0 -anchor nw -image [bar name] -tag bar $trough create text 0 0 -anchor c -text "0%" -tag indicator $self configurelist $args pack $trough -expand true -fill x bind $trough "$self Resize %w %h" } method Resize { w h } { $trough coords indicator [expr [winfo width $trough] / 2] [expr [winfo height $trough] / 2] set barwidth [expr round($progress * [winfo width $trough])] set barheight [winfo height $trough] bar configure -width $barwidth -height $barheight } method setprogress { value } { set progress $value set barwidth [expr round($value * [winfo width $trough])] bar configure -width $barwidth if { $barwidth > [lindex [$trough coords indicator] 0] } { $trough itemconfigure indicator -fill $options(-overforeground) } else { $trough itemconfigure indicator -fill $options(-foreground) } $trough itemconfigure indicator -text "[expr round($value * 100)]%" } method SetFont { option value } { set options(-font) $value $trough itemconfigure indicator -font $value } method SetFg { option value } { set options(-foreground) $value set options(-fg) $value $trough itemconfigure indicator -fill $value } method GetFg { option } { return $options(-foreground) } method SetOverFg { option value } { set options(-overforeground) $value set options(-overfg) $value } method GetOverFg { option } { return $options(-overforeground) } }amsn-0.98.9/utils/pixmapprogbar/bar.gif0000644000175000017500000000037110252127467017646 0ustar billiobbilliobGIF89aN ! ,NЌ@8ͻRdihlLm,t$T!PH$K:yKIEvumnnp(znх8 >^|~vpte|g}tuŽ;amsn-0.98.9/utils/pixmapprogbar/test.tcl0000644000175000017500000000132210313040522020053 0ustar billiobbilliob#!/usr/bin/wish lappend auto_path ../ source pixmapprogbar.tcl package require pixmapbutton frame .top pixmapprogbar .top.pb -height 20 -overfg blue -font [font create -family helvetica -size 12 -weight bold] frame .bottom button .bottom.1 -text "step 1" -command ".top.pb setprogress 0.2" button .bottom.2 -text "step 2" -command ".top.pb setprogress 0.4" button .bottom.3 -text "step 3" -command ".top.pb setprogress 0.6" button .bottom.4 -text "step 4" -command ".top.pb setprogress 0.8" button .bottom.5 -text "step 5" -command ".top.pb setprogress 1.0" pack .top.pb -expand true -fill x pack .bottom.1 .bottom.2 .bottom.3 .bottom.4 .bottom.5 pack .top .bottom -side top -pady 10 puts [.top.pb cget -foreground] amsn-0.98.9/utils/farsight/0000755000175000017500000000000011757711723015353 5ustar billiobbilliobamsn-0.98.9/utils/farsight/pkgIndex.tcl0000644000175000017500000000032711234373740017623 0ustar billiobbilliob# Tcl package index file if {[package vcompare [info tclversion] 8.4] < 0} return package ifneeded Farsight 0.1 "[list load [file join $dir tcl_farsight[info shared]] Farsight]; package provide Farsight 0.1" amsn-0.98.9/utils/farsight/src/0000755000175000017500000000000011757711633016142 5ustar billiobbilliobamsn-0.98.9/utils/farsight/src/tcl_farsight.c0000644000175000017500000040004411755433160020753 0ustar billiobbilliob/* File : tcl_farsight.c Description : Contains all functions for accessing farsight 2 Author : Youness El Alaoui (KaKaRoTo - kakaroto@users.sourceforge.net) */ // Include the header file #include "tcl_farsight.h" #include #include #include #include #include #ifdef HAVE_FARSTREAM #define LIBNAME "Farstream" #define PREFIX "farstream" #include #include #include #else #ifdef HAVE_FARSIGHT #define LIBNAME "Farsight" #define PREFIX "farsight" #include #include #include #else # error "HAVE_FARSTREAM or HAVE_FARSIGHT must be defined\n"; #endif /* HAVE_FARSIGHT */ #endif /* HAVE_FARSTREAM */ #ifdef G_OS_WIN32 #include #include #include #define snprintf _snprintf #define inet_ntop inet_ntop_win32 #else #include #include #include #endif #define OLD_AUDIO_CALL "A6" #define OLD_AUDIO_VIDEO_CALL "AV6" #define NEW_AUDIO_CALL "A19" #define NEW_AUDIO_VIDEO_CALL "AV19" typedef enum { RTP_AUDIO = 1, RTP_VIDEO = 2, RTP_ICE6 = 4, RTP_ICE19 = 8, RTP_AUDIO_ICE6 = (RTP_AUDIO | RTP_ICE6), RTP_AUDIO_ICE19 = (RTP_AUDIO | RTP_ICE19), RTP_AUDIO_VIDEO_ICE6 = (RTP_AUDIO | RTP_VIDEO | RTP_ICE6), RTP_AUDIO_VIDEO_ICE19 = (RTP_AUDIO | RTP_VIDEO | RTP_ICE19), } FsCallType; static GList * get_plugins_filtered (gboolean source, gboolean audio); static FsCallType call_type; /* Options, does not need to be freed */ static Tcl_Obj *level_callback = NULL; static Tcl_Interp *level_callback_interp = NULL; static Tcl_Obj *debug_callback = NULL; static Tcl_Interp *debug_callback_interp = NULL; static char *audio_source = NULL; static char *audio_source_device = NULL; static char *audio_source_pipeline = NULL; static char *audio_sink = NULL; static char *audio_sink_device = NULL; static char *audio_sink_pipeline = NULL; static char *video_source = NULL; static char *video_source_device = NULL; static gulong video_preview_xid = 0; static char *video_source_pipeline = NULL; static char *video_sink = NULL; static gulong video_sink_xid = 0; static char *video_sink_pipeline = NULL; static GstElement *pipeline = NULL; static GstElement *test_pipeline = NULL; static GstElement *source_bin = NULL; static GstElement *volumeIn = NULL; static GstElement *volumeOut = NULL; static GstElement *levelIn = NULL; static GstElement *levelOut = NULL; static GstElement *preview = NULL; static FsParticipant *participant = NULL; static FsSession *audio_session = NULL; static FsStream *audio_stream = NULL; static FsSession *video_session = NULL; static FsStream *video_stream = NULL; static gboolean audio_candidates_prepared = FALSE; static gboolean audio_codecs_ready = FALSE; static Tcl_Obj *audio_local_candidates = NULL; static gboolean video_candidates_prepared = FALSE; static gboolean video_codecs_ready = FALSE; static Tcl_Obj *video_local_candidates = NULL; static Tcl_Obj *callback = NULL; static Tcl_Interp *callback_interp = NULL; static Tcl_ThreadId main_tid = 0; static int audio_components_selected = 0; static int video_components_selected = 0; static FsElementAddedNotifier *fsnotifier = NULL; #ifdef __APPLE__ static GList *cocoa_windows = NULL; #endif #ifdef _WIN32 static const char *inet_ntop_win32(int af, const void *src, char *dst, socklen_t cnt) { if (af == AF_INET) { struct sockaddr_in in; memset(&in, 0, sizeof(in)); in.sin_family = AF_INET; memcpy(&in.sin_addr, src, sizeof(struct in_addr)); getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST); return dst; } return NULL; } #endif static char *host2ip(char *hostname) { struct addrinfo * result; static char ip[30]; const char * ret; int error; error = getaddrinfo(hostname, NULL, NULL, &result); if (error != 0) { return NULL; } if (result) { ret = inet_ntop (AF_INET, &((struct sockaddr_in *) result->ai_addr)->sin_addr, ip, INET_ADDRSTRLEN); freeaddrinfo (result); if (ret == NULL) { return NULL; } } return ip; } static gboolean g_object_has_property (GObject *object, const gchar *property) { GObjectClass *klass; klass = G_OBJECT_GET_CLASS (object); return NULL != g_object_class_find_property (klass, property); } static void Close () { #ifdef __APPLE__ GList *i = NULL; #endif if (participant) { g_object_unref (participant); participant = NULL; } if (audio_stream) { g_object_unref (audio_stream); audio_stream = NULL; } if (audio_session) { g_object_unref (audio_session); audio_session = NULL; } if (video_stream) { g_object_unref (video_stream); video_stream = NULL; } if (video_session) { g_object_unref (video_session); video_session = NULL; } if (pipeline) { gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (pipeline); pipeline = NULL; } if (test_pipeline) { gst_element_set_state (test_pipeline, GST_STATE_NULL); gst_object_unref (test_pipeline); test_pipeline = NULL; } if (volumeIn) { gst_object_unref (volumeIn); volumeIn = NULL; } if (volumeOut) { gst_object_unref (volumeOut); volumeOut = NULL; } if (levelIn) { gst_object_unref (levelIn); levelIn = NULL; } if (levelOut) { gst_object_unref (levelOut); levelOut = NULL; } if (preview) { gst_object_unref (preview); preview = NULL; } if (source_bin) { gst_element_set_state (source_bin, GST_STATE_NULL); gst_object_unref (source_bin); source_bin = NULL; } audio_candidates_prepared = FALSE; audio_codecs_ready = FALSE; video_candidates_prepared = FALSE; video_codecs_ready = FALSE; audio_components_selected = 0; video_components_selected = 0; if (audio_local_candidates) { Tcl_DecrRefCount(audio_local_candidates); audio_local_candidates = NULL; } if (video_local_candidates) { Tcl_DecrRefCount(video_local_candidates); video_local_candidates = NULL; } if (callback) { Tcl_DecrRefCount (callback); callback = NULL; callback_interp = NULL; } if (fsnotifier != NULL) { g_object_unref (fsnotifier); } fsnotifier = NULL; #ifdef __APPLE__ for (i = g_list_first(cocoa_windows); i; ) { NSWindow *win = (NSWindow *) i->data; i = g_list_next(i); cocoa_windows = g_list_remove(cocoa_windows, win); [win close]; } #endif } static void _notify_debug (gchar *format, ...) { Tcl_Obj *msg = NULL; Tcl_Obj *eval = Tcl_NewStringObj ("eval", -1); Tcl_Obj *args = Tcl_NewListObj (0, NULL); Tcl_Obj *command[] = {eval, debug_callback, args}; Tcl_Interp *interp = debug_callback_interp; gchar *message; va_list ap; va_start (ap, format); message = g_strdup_vprintf (format, ap); va_end (ap); msg = Tcl_NewStringObj (message, -1); Tcl_ListObjAppendElement(NULL, args, msg); if (debug_callback && debug_callback_interp) { /* Take the callback here in case it gets Closed by the eval */ Tcl_Obj *cbk = debug_callback; Tcl_IncrRefCount (eval); Tcl_IncrRefCount (args); Tcl_IncrRefCount (cbk); if (Tcl_EvalObjv(interp, 3, command, TCL_EVAL_GLOBAL) == TCL_ERROR) { g_debug ("Error executing debug handler : %s --- %s", Tcl_GetStringResult(interp), msg); } Tcl_DecrRefCount (cbk); Tcl_DecrRefCount (args); Tcl_DecrRefCount (eval); } g_free (message); } static void _notify_callback (char *status_msg, Tcl_Obj *obj1, Tcl_Obj *obj2) { Tcl_Obj *status = Tcl_NewStringObj (status_msg, -1); Tcl_Obj *eval = Tcl_NewStringObj ("eval", -1); Tcl_Obj *empty = Tcl_NewListObj (0, NULL); Tcl_Obj *args = Tcl_NewListObj (0, NULL); Tcl_Obj *command[] = {eval, callback, args}; Tcl_Interp *interp = callback_interp; Tcl_ListObjAppendElement(NULL, args, status); if (obj1) Tcl_ListObjAppendElement(NULL, args, obj1); else Tcl_ListObjAppendElement(NULL, args, empty); if (obj2) Tcl_ListObjAppendElement(NULL, args, obj2); else Tcl_ListObjAppendElement(NULL, args, empty); if (callback && callback_interp) { /* Take the callback here in case it gets Closed by the eval */ Tcl_Obj *cbk = callback; Tcl_IncrRefCount (eval); Tcl_IncrRefCount (args); Tcl_IncrRefCount (cbk); if (Tcl_EvalObjv(interp, 3, command, TCL_EVAL_GLOBAL) == TCL_ERROR) { _notify_debug ("Error executing %s handler : %s", status_msg, Tcl_GetStringResult(interp)); } Tcl_DecrRefCount (cbk); Tcl_DecrRefCount (args); Tcl_DecrRefCount (eval); } } static void _notify_level (char *direction, gfloat level) { Tcl_Obj *dir = Tcl_NewStringObj (direction, -1); Tcl_Obj *eval = Tcl_NewStringObj ("eval", -1); Tcl_Obj *args = Tcl_NewListObj (0, NULL); Tcl_Obj *command[] = {eval, level_callback, args}; Tcl_Interp *interp = level_callback_interp; if (level < -1000) level = -1000; Tcl_ListObjAppendElement(NULL, args, dir); Tcl_ListObjAppendElement(NULL, args, Tcl_NewDoubleObj (level)); if (level_callback && level_callback_interp) { /* Take the callback here in case it gets Closed by the eval */ Tcl_Obj *cbk = level_callback; Tcl_IncrRefCount (eval); Tcl_IncrRefCount (args); Tcl_IncrRefCount (cbk); if (Tcl_EvalObjv(interp, 3, command, TCL_EVAL_GLOBAL) == TCL_ERROR) { _notify_debug ("Error executing level handler (%s, %f) : %s", direction, level, Tcl_GetStringResult(interp)); } Tcl_DecrRefCount (cbk); Tcl_DecrRefCount (args); Tcl_DecrRefCount (eval); } } static void _notify_error (char *error) { Tcl_Obj *obj = Tcl_NewStringObj (error, -1); _notify_debug ("An error occured : %s", error); _notify_callback ("ERROR", obj, obj); Close (); } typedef struct { Tcl_Event header; char *error; } FarsightErrorEvent; static int Farsight_ErrorEventProc (Tcl_Event *evPtr, int flags) { FarsightErrorEvent *ev = (FarsightErrorEvent *) evPtr; char *error = ev->error; _notify_error (error); return 1; } static void _notify_error_post (char *error) { FarsightErrorEvent *evPtr; evPtr = (FarsightErrorEvent *)ckalloc(sizeof(FarsightErrorEvent)); evPtr->header.proc = Farsight_ErrorEventProc; evPtr->header.nextPtr = NULL; evPtr->error = error; Tcl_ThreadQueueEvent(main_tid, (Tcl_Event *)evPtr, TCL_QUEUE_TAIL); Tcl_ThreadAlert(main_tid); } static void _notify_active (char *msg, const char *local, const char *remote) { Tcl_Obj *local_candidate = Tcl_NewStringObj (local, -1); Tcl_Obj *remote_candidate = Tcl_NewStringObj (remote, -1); _notify_callback (msg, local_candidate, remote_candidate); } static void _notify_prepared (gchar *msg, FsSession *session, Tcl_Obj *local_candidates) { Tcl_Obj *local_codecs = Tcl_NewListObj (0, NULL); GList *codecs = NULL; GList *item = NULL; g_object_get (session, "codecs", &codecs, NULL); for (item = g_list_first (codecs); item; item = g_list_next (item)) { FsCodec *codec = item->data; Tcl_Obj *tcl_codec = NULL; Tcl_Obj *elements[3]; elements[0] = Tcl_NewStringObj (codec->encoding_name, -1); elements[1] = Tcl_NewIntObj (codec->id); elements[2] = Tcl_NewIntObj (codec->clock_rate); tcl_codec = Tcl_NewListObj (3, elements); Tcl_ListObjAppendElement(NULL, local_codecs, tcl_codec); } fs_codec_list_destroy (codecs); _notify_callback (msg, local_codecs, local_candidates == NULL ? Tcl_NewListObj (0, NULL) : Tcl_DuplicateObj(local_candidates)); } static void _notify_audio_prepared () { if (audio_codecs_ready && audio_candidates_prepared) { _notify_prepared ("PREPARED_AUDIO", audio_session, audio_local_candidates); } } static void _notify_video_prepared () { if (video_codecs_ready && video_candidates_prepared) { _notify_prepared ("PREPARED_VIDEO", video_session, video_local_candidates); } } static const char * _fs_candidate_type_to_string (FsCandidateType type) { switch (type) { case FS_CANDIDATE_TYPE_HOST: return "host"; break; case FS_CANDIDATE_TYPE_SRFLX: return "srflx"; break; case FS_CANDIDATE_TYPE_PRFLX: return "prflx"; break; case FS_CANDIDATE_TYPE_RELAY: return "relay"; break; default: return ""; break; } } static void _new_local_candidate (FsStream *stream, FsCandidate *candidate) { Tcl_Obj *tcl_candidate = NULL; Tcl_Obj *elements[11]; Tcl_Obj **local_candidates = NULL; if (stream == audio_stream) local_candidates = &audio_local_candidates; else local_candidates = &video_local_candidates; if (*local_candidates == NULL) { *local_candidates = Tcl_NewListObj (0, NULL); Tcl_IncrRefCount(*local_candidates); } elements[0] = Tcl_NewStringObj (candidate->foundation == NULL ? "" : candidate->foundation, -1); elements[1] = Tcl_NewIntObj (candidate->component_id); elements[2] = Tcl_NewStringObj (candidate->ip, -1); elements[3] = Tcl_NewIntObj (candidate->port); elements[4] = Tcl_NewStringObj (candidate->base_ip, -1); elements[5] = Tcl_NewIntObj (candidate->base_port); elements[6] = Tcl_NewStringObj (candidate->proto == FS_NETWORK_PROTOCOL_UDP ? "UDP" : "TCP", -1); if (call_type & RTP_ICE6) elements[7] = Tcl_NewDoubleObj ((gfloat) candidate->priority / 1000); else elements[7] = Tcl_NewIntObj (candidate->priority); elements[8] = Tcl_NewStringObj ( _fs_candidate_type_to_string (candidate->type), -1); elements[9] = Tcl_NewStringObj (candidate->username == NULL ? "" : candidate->username, -1); elements[10] = Tcl_NewStringObj (candidate->password == NULL ? "" : candidate->password, -1); tcl_candidate = Tcl_NewListObj (11, elements); Tcl_ListObjAppendElement(NULL, *local_candidates, tcl_candidate); } static void _local_candidates_prepared (FsStream *stream) { if (stream == audio_stream) { audio_candidates_prepared = TRUE; _notify_debug ("AUDIO CANDIDATES ARE PREPARED"); _notify_audio_prepared (); } else { video_candidates_prepared = TRUE; _notify_debug ("VIDEO CANDIDATES ARE PREPARED"); _notify_video_prepared (); } } static void _sink_element_added (GstBin *bin, GstElement *sink, gpointer user_data) { g_object_set (sink, "async", FALSE, NULL); g_object_set (sink, "sync", FALSE, NULL); } static gchar * get_device_property_name (gchar *plugin_name) { if (!strcmp (plugin_name, "dshowaudiosrc") || !strcmp (plugin_name, "dshowvideosrc")) return "device-name"; else return "device"; } static GstElement * _test_source (gchar *name) { GstPropertyProbe *probe = NULL; GstElement *element = NULL; GstElement *tee = NULL; GstElement *queue = NULL; GstElement *valve = NULL; GstElement *fakesink = NULL; GstElement *bin = NULL; GstPad *bin_pad = NULL; GstStateChangeReturn state_ret; GValueArray *arr; _notify_debug("Testing source %s", name); if (!strcmp (name, "dtmfsrc") || !strcmp (name, "audiotestsrc") || !strcmp (name, "autoaudiosrc") || !strcmp (name, "autovideosrc") || !strcmp (name, "videotestsrc") || !strcmp (name, "ximagesrc") || !strcmp (name, "dx9screencapsrc") || !strcmp (name, "gdiscreencapsrc")) return NULL; element = gst_element_factory_make (name, NULL); if (element == NULL) return NULL; if (g_object_has_property (element, "buffer-time")) g_object_set(element, "buffer-time", G_GINT64_CONSTANT(20000), NULL); if (g_object_has_property (element, "is-live")) g_object_set(element, "is-live", TRUE, NULL); /* Build a bin and put the element in it with a tee ! fakesink */ bin = gst_bin_new ("source_bin"); if (bin == NULL) { _notify_debug ("Could not create source bin"); gst_object_unref (element); return NULL; } if (gst_bin_add (GST_BIN (bin), element) == FALSE) { _notify_debug ("Could not add source to source bin"); gst_object_unref (element); gst_object_unref (bin); return NULL; } tee = gst_element_factory_make ("tee", NULL); if (tee == NULL || gst_bin_add (GST_BIN (bin), tee) == FALSE) { _notify_debug ("Could not add tee to source bin"); if (tee) gst_object_unref (tee); gst_object_unref (bin); return NULL; } if (gst_element_link(element, tee) == FALSE) { _notify_debug ("Could not link source to tee"); gst_object_unref (bin); return NULL; } queue = gst_element_factory_make ("queue", NULL); if (queue == NULL || gst_bin_add (GST_BIN (bin), queue) == FALSE) { _notify_debug ("Could not add queue to source bin"); gst_object_unref (queue); gst_object_unref (bin); return NULL; } if (gst_element_link(tee, queue) == FALSE) { _notify_debug ("Could not link tee to queue"); gst_object_unref (bin); return NULL; } fakesink = gst_element_factory_make ("fakesink", NULL); if (fakesink == NULL) { _notify_debug ("Could not create fakesink in source bin"); gst_object_unref (bin); return NULL; } g_object_set (fakesink, "async", FALSE, NULL); g_object_set (fakesink, "sync", FALSE, NULL); if (gst_bin_add (GST_BIN (bin), fakesink) == FALSE) { _notify_debug ("Could not add fakesink to source bin"); gst_object_unref (fakesink); gst_object_unref (bin); return NULL; } if (gst_element_link(queue, fakesink) == FALSE) { _notify_debug ("Could not link fakesink to source"); gst_object_unref (bin); return NULL; } queue = gst_element_factory_make ("queue", NULL); if (queue == NULL || gst_bin_add (GST_BIN (bin), queue) == FALSE) { _notify_debug ("Could not add second queue to source bin"); gst_object_unref (queue); gst_object_unref (bin); return NULL; } if (gst_element_link(tee, queue) == FALSE) { _notify_debug ("Could not link tee to second queue"); gst_object_unref (bin); return NULL; } valve = gst_element_factory_make ("valve", "hack_valve"); if (valve == NULL || gst_bin_add (GST_BIN (bin), valve) == FALSE) { _notify_debug ("Could not add valve to source bin"); gst_object_unref (valve); gst_object_unref (bin); return NULL; } if (gst_element_link(queue, valve) == FALSE) { _notify_debug ("Could not link queue to valve"); gst_object_unref (bin); return NULL; } g_object_set (valve, "drop", TRUE, NULL); bin_pad = gst_element_get_static_pad (valve, "src"); gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("src", bin_pad)); gst_object_unref (bin_pad); GST_OBJECT_FLAG_UNSET (bin, GST_ELEMENT_IS_SINK); /* Test the source */ state_ret = gst_element_set_state (bin, GST_STATE_PLAYING); if (state_ret == GST_STATE_CHANGE_ASYNC) { _notify_debug ("Waiting for %s to go to state PLAYING", name); state_ret = gst_element_get_state (bin, NULL, NULL, GST_CLOCK_TIME_NONE); } if (state_ret != GST_STATE_CHANGE_FAILURE) { gst_element_set_locked_state (bin, TRUE); source_bin = bin; gst_object_ref (bin); return bin; } if (GST_IS_PROPERTY_PROBE (element)) { probe = GST_PROPERTY_PROBE (element); if (probe) { arr = gst_property_probe_probe_and_get_values_name (probe, get_device_property_name(name)); if (arr && arr->n_values > 0) { guint i; for (i = 0; i < arr->n_values; ++i) { const gchar *device; GValue *val; val = g_value_array_get_nth (arr, i); if (val == NULL || !G_VALUE_HOLDS_STRING (val)) continue; device = g_value_get_string (val); if (device == NULL) continue; g_object_set(element, get_device_property_name(name), device, NULL); state_ret = gst_element_set_state (bin, GST_STATE_PLAYING); if (state_ret == GST_STATE_CHANGE_ASYNC) { _notify_debug ("Waiting for %s to go to state PLAYING", name); state_ret = gst_element_get_state (bin, NULL, NULL, GST_CLOCK_TIME_NONE); } if (state_ret != GST_STATE_CHANGE_FAILURE) { g_value_array_free (arr); gst_element_set_locked_state (bin, TRUE); source_bin = bin; gst_object_ref (bin); return bin; } } g_value_array_free (arr); } } } gst_element_set_state (bin, GST_STATE_NULL); gst_object_unref (bin); return NULL; } static GstElement * _create_audio_source () { GstElement *src = NULL; GList *sources, *walk; gchar *priority_sources[] = {"dshowaudiosrc", "directsoundsrc", "osxaudiosrc", "gconfaudiosrc", "pulsesrc", "alsasrc", "oss4src", "osssrc", NULL}; gchar **test_source = NULL; _notify_debug ("Creating audio_source : %s --- %s -- %s", audio_source_pipeline ? audio_source_pipeline : "(null)", audio_source ? audio_source : "(null)", audio_source_device ? audio_source_device : "(null)"); if (audio_source_pipeline) { GstPad *pad = NULL; GstBin *bin; gchar *desc; GError *error = NULL; GstStateChangeReturn state_ret; /* parse the pipeline to a bin */ desc = g_strdup_printf ("bin.( %s ! queue )", audio_source_pipeline); bin = (GstBin *) gst_parse_launch (desc, &error); g_free (desc); if (bin) { /* find pads and ghost them if necessary */ if ((pad = gst_bin_find_unlinked_pad (bin, GST_PAD_SRC))) { gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("src", pad)); gst_object_unref (pad); } src = GST_ELEMENT (bin); } if (error) { _notify_debug ("Error while creating audio_source pipeline (%d): %s", error->code, error->message? error->message : "(null)"); } state_ret = gst_element_set_state (src, GST_STATE_READY); if (state_ret == GST_STATE_CHANGE_ASYNC) { _notify_debug ("Waiting for audio_source_pipeline to go to state READY"); state_ret = gst_element_get_state (src, NULL, NULL, GST_CLOCK_TIME_NONE); } if (state_ret == GST_STATE_CHANGE_FAILURE) { gst_object_unref (src); return NULL; } GST_OBJECT_FLAG_UNSET (src, GST_ELEMENT_IS_SINK); return src; } else if (audio_source) { if (strcmp (audio_source, "-") == 0) { /* User disabled audio*/ return NULL; } else { GstStateChangeReturn state_ret; src = gst_element_factory_make (audio_source, NULL); if (src && audio_source_device) g_object_set(src, get_device_property_name(audio_source), audio_source_device, NULL); state_ret = gst_element_set_state (src, GST_STATE_READY); if (state_ret == GST_STATE_CHANGE_ASYNC) { _notify_debug ("Waiting for %s to go to state READY", audio_source); state_ret = gst_element_get_state (src, NULL, NULL, GST_CLOCK_TIME_NONE); } if (state_ret == GST_STATE_CHANGE_FAILURE) { gst_object_unref (src); return NULL; } GST_OBJECT_FLAG_UNSET (src, GST_ELEMENT_IS_SINK); return src; } } for (test_source = priority_sources; *test_source; test_source++) { GstElement *element = _test_source (*test_source); if (element == NULL) continue; _notify_debug ("Using audio_source %s", *test_source); src = element; break; } if (src) { GST_OBJECT_FLAG_UNSET (src, GST_ELEMENT_IS_SINK); return src; } sources = get_plugins_filtered (TRUE, TRUE); for (walk = sources; walk; walk = g_list_next (walk)) { GstElement *element; GstElementFactory *factory = GST_ELEMENT_FACTORY(walk->data); element = _test_source (GST_PLUGIN_FEATURE_NAME(factory)); if (element == NULL) continue; _notify_debug ("Using audio_source %s", GST_PLUGIN_FEATURE_NAME(factory)); src = element; break; } for (walk = sources; walk; walk = g_list_next (walk)) { if (walk->data) gst_object_unref (GST_ELEMENT_FACTORY (walk->data)); } g_list_free (sources); if (src) GST_OBJECT_FLAG_UNSET (src, GST_ELEMENT_IS_SINK); return src; } static GstElement * _create_audio_sink () { GstElement *snk = NULL; if (audio_sink_pipeline) { GstPad *pad = NULL; GstBin *bin; gchar *desc; GError *error = NULL; /* parse the pipeline to a bin */ desc = g_strdup_printf ("bin.( %s ! queue )", audio_sink_pipeline); bin = (GstBin *) gst_parse_launch (desc, &error); g_free (desc); if (bin) { /* find pads and ghost them if necessary */ if ((pad = gst_bin_find_unlinked_pad (bin, GST_PAD_SINK))) { gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("sink", pad)); gst_object_unref (pad); } snk = GST_ELEMENT (bin); } if (error) { _notify_debug ("Error while creating audio_sink pipeline (%d): %s", error->code, error->message ? error->message : "(null)"); } } else if (audio_sink && strcmp (audio_sink, "autoaudiosink") != 0) { snk = gst_element_factory_make (audio_sink, NULL); if (snk && audio_sink_device) g_object_set(snk, "device", audio_sink_device, NULL); if (snk) { if (g_object_has_property (snk, "sync")) { g_object_set(snk, "sync", FALSE, NULL); g_object_set(snk, "async", FALSE, NULL); } } } if (snk == NULL) { snk = gst_element_factory_make ("autoaudiosink", NULL); g_signal_connect (snk, "element-added", G_CALLBACK (_sink_element_added), NULL); } return snk; } static void _audio_src_pad_added (FsStream *self, GstPad *pad, FsCodec *codec, gpointer user_data) { GstElement *pipeline = user_data; GstElement *snk = NULL; GstElement *convert = gst_element_factory_make ("audioconvert", NULL); GstElement *resample = gst_element_factory_make ("audioresample", NULL); GstElement *convert2 = gst_element_factory_make ("audioconvert", NULL); GstPad *sink_pad = NULL; GstPadLinkReturn ret; snk = _create_audio_sink (); if (snk == NULL) { _notify_error_post ("Could not create audio_sink"); if (convert) gst_object_unref (convert); if (resample) gst_object_unref (resample); if (convert2) gst_object_unref (convert2); return; } if (gst_bin_add (GST_BIN (pipeline), snk) == FALSE) { _notify_error_post ("Could not add audio_sink to pipeline"); if (snk) gst_object_unref (snk); if (convert) gst_object_unref (convert); if (resample) gst_object_unref (resample); if (convert2) gst_object_unref (convert2); return; } if (gst_bin_add (GST_BIN (pipeline), convert) == FALSE) { _notify_error_post ("Could not add converter to pipeline"); if (convert) gst_object_unref (convert); if (resample) gst_object_unref (resample); if (convert2) gst_object_unref (convert2); return; } if (gst_bin_add (GST_BIN (pipeline), resample) == FALSE) { _notify_error_post ("Could not add resampler to pipeline"); if (resample) gst_object_unref (resample); if (convert2) gst_object_unref (convert2); return; } if (gst_bin_add (GST_BIN (pipeline), convert2) == FALSE) { _notify_error_post ("Could not add second converter to pipeline"); if (convert2) gst_object_unref (convert2); return; } volumeOut = gst_element_factory_make ("volume", NULL); if (volumeOut) { gst_object_ref (volumeOut); if (gst_bin_add (GST_BIN (pipeline), volumeOut) == FALSE) { _notify_debug ("Could not add output volume to pipeline"); gst_object_unref (volumeOut); volumeOut = NULL; goto no_volume; } if (gst_element_link(volumeOut, convert) == FALSE) { _notify_debug ("Could not link volume out to converter"); gst_bin_remove (GST_BIN (pipeline), volumeOut); gst_object_unref (volumeOut); volumeOut = NULL; goto no_volume; } sink_pad = gst_element_get_static_pad (volumeOut, "sink"); } else { no_volume: sink_pad = gst_element_get_static_pad (convert, "sink"); } ret = gst_pad_link (pad, sink_pad); gst_object_unref (sink_pad); if (ret != GST_PAD_LINK_OK) { _notify_error_post ("Could not link volume/sink to fsrtpconference sink pad"); return; } if (gst_element_link(convert, resample) == FALSE) { _notify_error_post ("Could not link converter to resampler"); return; } if (gst_element_link(resample, convert2) == FALSE) { _notify_error_post ("Could not link resampler to second converter"); return; } levelOut = gst_element_factory_make ("level", NULL); if (levelOut) { gst_object_ref (levelOut); if (gst_bin_add (GST_BIN (pipeline), levelOut) == FALSE) { _notify_debug ("Could not add output level to pipeline"); gst_object_unref (levelOut); levelOut = NULL; goto no_level; } g_object_set (G_OBJECT (levelOut), "message", TRUE, NULL); if (gst_element_link(convert2, levelOut) == FALSE) { _notify_debug ("Could not link level out to converter"); gst_bin_remove (GST_BIN (pipeline), levelOut); gst_object_unref (levelOut); levelOut = NULL; goto no_level; } if (gst_element_link(levelOut, snk) == FALSE) { _notify_debug ("Could not link audio_sink to level out"); gst_element_unlink(convert2, levelOut); gst_bin_remove (GST_BIN (pipeline), levelOut); gst_object_unref (levelOut); levelOut = NULL; goto no_level; } } else { no_level: if (gst_element_link(convert2, snk) == FALSE) { _notify_error_post ("Could not link audio_sink to converter"); return; } } if (gst_element_set_state (volumeOut, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { _notify_error_post ("Unable to set volume OUT to PLAYING"); return; } if (gst_element_set_state (convert, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { _notify_error_post ("Unable to set converter to PLAYING"); return; } if (gst_element_set_state (resample, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { _notify_error_post ("Unable to set resampler to PLAYING"); return; } if (gst_element_set_state (convert2, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { _notify_error_post ("Unable to set second converter to PLAYING"); return; } if (gst_element_set_state (snk, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { _notify_error_post ("Unable to set audio_sink to PLAYING"); return; } if (levelOut) { if (gst_element_set_state (levelOut, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { _notify_error_post ("Unable to set audio_sink to PLAYING"); return; } } } static GstElement * _create_video_source () { GstElement *src = NULL; GList *sources, *walk; gchar *priority_sources[] = {"dshowvideosrc", "ksvideosrc", "gconfvideosrc", "gconfv4l2src", "v4l2src", "v4lsrc", NULL}; gchar **test_source = NULL; GstElement *tee = NULL; GstElement *colorspace = NULL; GstElement *capsfilter = NULL; GstElement *videoscale = NULL; GstElement *queue = NULL; GstCaps *caps = NULL; GstElement *video_bin = NULL; GstPad *bin_pad = NULL; _notify_debug ("Creating video_source : %s --- %s -- %s", video_source_pipeline ? video_source_pipeline : "(null)", video_source ? video_source : "(null)", video_source_device ? video_source_device : "(null)"); if (video_source_pipeline) { GstPad *pad = NULL; GstBin *bin; gchar *desc; GError *error = NULL; GstStateChangeReturn state_ret; /* parse the pipeline to a bin */ desc = g_strdup_printf ("bin.( %s ! queue )", video_source_pipeline); bin = (GstBin *) gst_parse_launch (desc, &error); g_free (desc); if (bin) { /* find pads and ghost them if necessary */ if ((pad = gst_bin_find_unlinked_pad (bin, GST_PAD_SRC))) { gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("src", pad)); gst_object_unref (pad); } src = GST_ELEMENT (bin); } if (error) { _notify_debug ("Error while creating video_source pipeline (%d): %s", error->code, error->message? error->message : "(null)"); } state_ret = gst_element_set_state (src, GST_STATE_READY); if (state_ret == GST_STATE_CHANGE_ASYNC) { _notify_debug ("Waiting for video_source_pipeline to go to state READY"); state_ret = gst_element_get_state (src, NULL, NULL, GST_CLOCK_TIME_NONE); } if (state_ret == GST_STATE_CHANGE_FAILURE) { gst_object_unref (src); return NULL; } goto add_preview; } else if (video_source) { if (strcmp (video_source, "-") == 0) { /* User disabled video */ return NULL; } else { GstStateChangeReturn state_ret; src = gst_element_factory_make (video_source, NULL); if (src && video_source_device) g_object_set(src, get_device_property_name(video_source), video_source_device, NULL); state_ret = gst_element_set_state (src, GST_STATE_READY); if (state_ret == GST_STATE_CHANGE_ASYNC) { _notify_debug ("Waiting for %s to go to state READY", video_source); state_ret = gst_element_get_state (src, NULL, NULL, GST_CLOCK_TIME_NONE); } if (state_ret == GST_STATE_CHANGE_FAILURE) { gst_object_unref (src); return NULL; } goto add_preview; } } for (test_source = priority_sources; *test_source; test_source++) { GstElement *element = _test_source (*test_source); if (element == NULL) continue; _notify_debug ("Using video_source %s", *test_source); src = element; break; } if (src) goto add_preview; sources = get_plugins_filtered (TRUE, FALSE); for (walk = sources; walk; walk = g_list_next (walk)) { GstElement *element; GstElementFactory *factory = GST_ELEMENT_FACTORY(walk->data); element = _test_source (GST_PLUGIN_FEATURE_NAME(factory)); if (element == NULL) continue; _notify_debug ("Using video_source %s", GST_PLUGIN_FEATURE_NAME(factory)); src = element; break; } for (walk = sources; walk; walk = g_list_next (walk)) { if (walk->data) gst_object_unref (GST_ELEMENT_FACTORY (walk->data)); } g_list_free (sources); if (src == NULL) return NULL; add_preview: video_bin = gst_bin_new ("video_bin"); if (video_bin == NULL) { _notify_debug ("Could not create video bin"); gst_element_set_state (src, GST_STATE_NULL); gst_object_unref (src); return NULL; } if (gst_bin_add (GST_BIN (video_bin), src) == FALSE) { _notify_debug ("Could not add video source to video bin"); gst_element_set_state (src, GST_STATE_NULL); gst_object_unref (src); gst_object_unref (video_bin); return NULL; } colorspace = gst_element_factory_make ("ffmpegcolorspace", NULL); if (colorspace == NULL || gst_bin_add (GST_BIN (video_bin), colorspace) == FALSE) { _notify_debug ("Could not add colorspace to video bin"); gst_element_set_locked_state (src, FALSE); gst_object_unref (colorspace); gst_element_set_state (video_bin, GST_STATE_NULL); gst_object_unref (video_bin); return NULL; } if (gst_element_link(src, colorspace) == FALSE) { _notify_debug ("Could not link video source to colorspace"); gst_element_set_locked_state (src, FALSE); gst_element_set_state (video_bin, GST_STATE_NULL); gst_object_unref (video_bin); return NULL; } videoscale = gst_element_factory_make ("videoscale", NULL); if (videoscale == NULL || gst_bin_add (GST_BIN (video_bin), videoscale) == FALSE) { _notify_debug ("Could not add videoscale to video bin"); gst_object_unref (videoscale); gst_element_set_locked_state (src, FALSE); gst_element_set_state (video_bin, GST_STATE_NULL); gst_object_unref (video_bin); return NULL; } if (gst_element_link(colorspace, videoscale) == FALSE) { _notify_debug ("Could not link colorspace to videoscale"); gst_element_set_locked_state (src, FALSE); gst_element_set_state (video_bin, GST_STATE_NULL); gst_object_unref (video_bin); return NULL; } capsfilter = gst_element_factory_make ("capsfilter", "capsfilter"); if (capsfilter == NULL || gst_bin_add (GST_BIN (video_bin), capsfilter) == FALSE) { _notify_debug ("Could not add capsfilter to video bin"); gst_object_unref (capsfilter); gst_element_set_locked_state (src, FALSE); gst_element_set_state (video_bin, GST_STATE_NULL); gst_object_unref (video_bin); return NULL; } if (gst_element_link(videoscale, capsfilter) == FALSE) { _notify_debug ("Could not link videoscale to capsfilter"); gst_element_set_locked_state (src, FALSE); gst_element_set_state (video_bin, GST_STATE_NULL); gst_object_unref (video_bin); return NULL; } caps = gst_caps_new_simple ("video/x-raw-yuv", "width", G_TYPE_INT, 176, "height", G_TYPE_INT, 144, NULL); g_object_set (capsfilter, "caps", caps, NULL); tee = gst_element_factory_make ("tee", NULL); if (tee == NULL || gst_bin_add (GST_BIN (video_bin), tee) == FALSE) { _notify_debug ("Could not add tee to video bin"); if (tee) gst_object_unref (tee); gst_element_set_locked_state (src, FALSE); gst_element_set_state (video_bin, GST_STATE_NULL); gst_object_unref (video_bin); return NULL; } if (gst_element_link(capsfilter, tee) == FALSE) { _notify_debug ("Could not link capsfilter to tee"); gst_element_set_locked_state (src, FALSE); gst_element_set_state (video_bin, GST_STATE_NULL); gst_object_unref (video_bin); return NULL; } queue = gst_element_factory_make ("queue", NULL); if (queue == NULL || gst_bin_add (GST_BIN (video_bin), queue) == FALSE) { _notify_debug ("Could not add preview queue to video bin"); gst_object_unref (queue); gst_element_set_locked_state (src, FALSE); gst_element_set_state (video_bin, GST_STATE_NULL); gst_object_unref (video_bin); return NULL; } if (gst_element_link(tee, queue) == FALSE) { _notify_debug ("Could not link tee to preview queue"); gst_element_set_locked_state (src, FALSE); gst_element_set_state (video_bin, GST_STATE_NULL); gst_object_unref (video_bin); return NULL; } colorspace = gst_element_factory_make ("ffmpegcolorspace", NULL); if (colorspace == NULL || gst_bin_add (GST_BIN (video_bin), colorspace) == FALSE) { _notify_debug ("Could not add colorspace to video bin"); gst_object_unref (colorspace); gst_element_set_locked_state (src, FALSE); gst_element_set_state (video_bin, GST_STATE_NULL); gst_object_unref (video_bin); return NULL; } if (gst_element_link(queue, colorspace) == FALSE) { _notify_debug ("Could not link preview queue to colorspace"); gst_element_set_locked_state (src, FALSE); gst_element_set_state (video_bin, GST_STATE_NULL); gst_object_unref (video_bin); return NULL; } #ifdef __APPLE__ preview = gst_element_factory_make ("osxvideosink", NULL); if (preview) { g_object_set (preview, "async", FALSE, NULL); g_object_set (preview, "sync", FALSE, NULL); } #else preview = gst_element_factory_make ("autovideosink", NULL); if (preview) { g_signal_connect (preview, "element-added", G_CALLBACK (_sink_element_added), NULL); } #endif if (preview == NULL) { _notify_debug ("Could not create preview window"); gst_element_set_locked_state (src, FALSE); gst_element_set_state (video_bin, GST_STATE_NULL); gst_object_unref (video_bin); return NULL; } if (gst_bin_add (GST_BIN (video_bin), preview) == FALSE) { _notify_debug ("Could not add preview to video bin"); if (preview) gst_object_unref (preview); preview = NULL; gst_element_set_locked_state (src, FALSE); gst_element_set_state (video_bin, GST_STATE_NULL); gst_object_unref (video_bin); return NULL; } gst_object_ref (preview); if (gst_element_link(colorspace, preview) == FALSE) { _notify_debug ("Could not link preview to video source"); if (preview) gst_object_unref (preview); preview = NULL; gst_element_set_locked_state (src, FALSE); gst_element_set_state (video_bin, GST_STATE_NULL); gst_object_unref (video_bin); return NULL; } queue = gst_element_factory_make ("queue", NULL); if (queue == NULL || gst_bin_add (GST_BIN (video_bin), queue) == FALSE) { _notify_debug ("Could not add video queue to video bin"); gst_object_unref (queue); gst_element_set_locked_state (src, FALSE); gst_element_set_state (video_bin, GST_STATE_NULL); gst_object_unref (video_bin); return NULL; } if (gst_element_link(tee, queue) == FALSE) { _notify_debug ("Could not link tee to video queue"); gst_element_set_locked_state (src, FALSE); gst_element_set_state (video_bin, GST_STATE_NULL); gst_object_unref (video_bin); return NULL; } bin_pad = gst_element_get_static_pad (queue, "src"); gst_element_add_pad (GST_ELEMENT (video_bin), gst_ghost_pad_new ("src", bin_pad)); gst_object_unref (bin_pad); GST_OBJECT_FLAG_UNSET (video_bin, GST_ELEMENT_IS_SINK); return video_bin; } static GstElement * _create_video_sink () { GstElement *snk = NULL; if (video_sink_pipeline) { GstPad *pad = NULL; GstBin *bin; gchar *desc; GError *error = NULL; /* parse the pipeline to a bin */ desc = g_strdup_printf ("bin.( %s ! queue )", video_sink_pipeline); bin = (GstBin *) gst_parse_launch (desc, &error); g_free (desc); if (bin) { /* find pads and ghost them if necessary */ if ((pad = gst_bin_find_unlinked_pad (bin, GST_PAD_SINK))) { gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("sink", pad)); gst_object_unref (pad); } snk = GST_ELEMENT (bin); } if (error) { _notify_debug ("Error while creating video_sink pipeline (%d): %s", error->code, error->message ? error->message : "(null)"); } } else if (video_sink && strcmp (video_sink, "autovideosink") != 0) { snk = gst_element_factory_make (video_sink, NULL); if (snk) { if (g_object_has_property (snk, "sync")) { g_object_set (snk, "async", FALSE, NULL); g_object_set (snk, "sync", FALSE, NULL); } } } if (snk == NULL) { #ifdef __APPLE__ snk = gst_element_factory_make ("osxvideosink", NULL); if (snk) { g_object_set (snk, "async", FALSE, NULL); g_object_set (snk, "sync", FALSE, NULL); } #else snk = gst_element_factory_make ("autovideosink", NULL); if (snk) { g_signal_connect (snk, "element-added", G_CALLBACK (_sink_element_added), NULL); } #endif } return snk; } static void _video_src_pad_added (FsStream *self, GstPad *pad, FsCodec *codec, gpointer user_data) { GstElement *pipeline = user_data; GstElement *snk = NULL; GstElement *colorspace = gst_element_factory_make ("ffmpegcolorspace", NULL); GstPad *sink_pad = NULL; GstPadLinkReturn ret; snk = _create_video_sink (); if (snk == NULL) { _notify_error_post ("Could not create video_sink"); if (colorspace) gst_object_unref (colorspace); return; } if (gst_bin_add (GST_BIN (pipeline), snk) == FALSE) { _notify_error_post ("Could not add video_sink to pipeline"); if (snk) gst_object_unref (snk); if (colorspace) gst_object_unref (colorspace); return; } if (gst_bin_add (GST_BIN (pipeline), colorspace) == FALSE) { _notify_error_post ("Could not add colorspace to pipeline"); if (colorspace) gst_object_unref (colorspace); return; } sink_pad = gst_element_get_static_pad (colorspace, "sink"); ret = gst_pad_link (pad, sink_pad); gst_object_unref (sink_pad); if (ret != GST_PAD_LINK_OK) { _notify_error_post ("Could not link colorspace to fsrtpconference sink pad"); return; } if (gst_element_link(colorspace, snk) == FALSE) { _notify_error_post ("Could not link converter to resampler"); return; } if (gst_element_set_state (colorspace, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { _notify_error_post ("Unable to set converter to PLAYING"); return; } if (gst_element_set_state (snk, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { _notify_error_post ("Unable to set audio_sink to PLAYING"); return; } } static void _conference_element_added (FsElementAddedNotifier *notifier, GstBin *bin, GstElement *element, gpointer user_data) { GstElementFactory *factory; const gchar *name; factory = gst_element_get_factory (element); name = gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)); if (strcmp (name, "ffenc_h263") == 0) { /* Ensure that the encoder works with rtp */ g_object_set (element, "rtp-payload-size", 1, NULL); } else if (strcmp (name, "rtph263pay") == 0) { /* Only mode A in h263 payloading is supported by WLM */ g_object_set (element, "modea-only", TRUE, "mtu", 1024, NULL); } else if (strcmp (name, "gstrtpbin") == 0) { /* Lower the jitterbuffer latency to make it more suitable for video * conferencing */ g_object_set (element, "latency", 100, NULL); } } static void _codecs_ready (FsSession *session) { if (session == audio_session) { audio_codecs_ready = TRUE; _notify_debug ("AUDIO CODECS ARE READY"); _notify_audio_prepared (); } else { video_codecs_ready = TRUE; _notify_debug ("VIDEO CODECS ARE READY"); _notify_video_prepared (); } } typedef struct { Tcl_Event header; GstMessage *message; } FarsightBusEvent; static int Farsight_BusEventProc (Tcl_Event *evPtr, int flags) { FarsightBusEvent *ev = (FarsightBusEvent *) evPtr; GstMessage *message = ev->message; /* If we destroy the pipeline in an async operation, we must ignore the messages */ if (pipeline == NULL && test_pipeline == NULL) goto done; switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ELEMENT: { const GstStructure *s = gst_message_get_structure (message); if (gst_structure_has_name (s, PREFIX "-error")) { const GValue *errorvalue, *debugvalue, *error_no; error_no = gst_structure_get_value (message->structure, "error-no"); errorvalue = gst_structure_get_value (message->structure, "error-msg"); debugvalue = gst_structure_get_value (message->structure, "debug-msg"); #ifdef HAVE_FARSTREAM if (g_value_get_enum (error_no)) { #else if (g_value_get_enum (error_no) != FS_ERROR_UNKNOWN_CNAME) { #endif /* HAVE_FARSTREAM */ _notify_debug ("Error on BUS (%d) %s .. %s", g_value_get_enum (error_no), g_value_get_string (errorvalue), g_value_get_string (debugvalue)); _notify_error (LIBNAME " error"); } } else if (gst_structure_has_name (s, PREFIX "-new-local-candidate")) { FsStream *stream; FsCandidate *candidate; const GValue *value; value = gst_structure_get_value (s, "stream"); stream = g_value_get_object (value); value = gst_structure_get_value (s, "candidate"); candidate = g_value_get_boxed (value); _new_local_candidate (stream, candidate); } else if (gst_structure_has_name (s, PREFIX "-local-candidates-prepared")) { FsStream *stream; const GValue *value; value = gst_structure_get_value (s, "stream"); stream = g_value_get_object (value); _local_candidates_prepared (stream); } else if (gst_structure_has_name (s, PREFIX "-codecs-changed")) { gboolean ready; if (!audio_codecs_ready) { g_object_get (audio_session, "codecs-ready", &ready, NULL); if (ready) { _codecs_ready (audio_session); } } if (video_session != NULL && !video_codecs_ready) { g_object_get (video_session, "codecs-ready", &ready, NULL); if (ready) { _codecs_ready (video_session); } } } else if (gst_structure_has_name (s, PREFIX "-new-active-candidate-pair")) { FsCandidate *local; FsCandidate *remote; FsStream *stream; const GValue *value; value = gst_structure_get_value (s, "local-candidate"); local = g_value_get_boxed (value); value = gst_structure_get_value (s, "remote-candidate"); remote = g_value_get_boxed (value); value = gst_structure_get_value (s, "stream"); stream = g_value_get_object (value); _notify_debug ("New active candidate pair (%s) : ", stream == audio_stream ? "audio" : "video"); _notify_debug ("Local candidate: %s %d %s %d %s %d %s %d %s %s %s\n", local->foundation == NULL ? "-" : local->foundation, local->component_id, local->ip, local->port, local->base_ip == NULL ? "-" : local->base_ip, local->base_port, local->proto == FS_NETWORK_PROTOCOL_UDP ? "UDP" : "TCP", local->priority, _fs_candidate_type_to_string (local->type), local->username == NULL ? "-" : local->username, local->password == NULL ? "-" : local->password); _notify_debug ("Remote candidate: %s %d %s %d %s %d %s %d %s %s %s\n", remote->foundation == NULL ? "-" : remote->foundation, remote->component_id, remote->ip, remote->port, remote->base_ip == NULL ? "-" : remote->base_ip, remote->base_port, remote->proto == FS_NETWORK_PROTOCOL_UDP ? "UDP" : "TCP", remote->priority, _fs_candidate_type_to_string (remote->type), remote->username == NULL ? "-" : remote->username, remote->password == NULL ? "-" : remote->password); if (stream == audio_stream) { if (++audio_components_selected == 2) { _notify_active ("AUDIO_ACTIVE", local->foundation, remote->foundation); } } else { if (++video_components_selected == 2) { _notify_active ("VIDEO_ACTIVE", local->foundation, remote->foundation); } } } else if (gst_structure_has_name (s, "level")) { gint channels; gdouble rms_dB; gdouble rms; const GValue *list; const GValue *value; gint i; /* we can get the number of channels as the length of any of the value * lists */ list = gst_structure_get_value (s, "rms"); channels = gst_value_list_get_size (list); rms = 0; for (i = 0; i < channels; ++i) { list = gst_structure_get_value (s, "rms"); value = gst_value_list_get_value (list, i); rms_dB = g_value_get_double (value); rms += rms_dB; } if (GST_MESSAGE_SRC (message) == GST_OBJECT(levelIn)) { _notify_level ("IN", (gfloat) (rms / channels)); } else if (GST_MESSAGE_SRC (message) == GST_OBJECT(levelOut)) { _notify_level ("OUT", (gfloat) (rms / channels)); } } #ifdef __APPLE__ else if (gst_structure_has_name (s, "have-ns-view")) { NSWindow * win = nil; NSView *nsview = nil; NSRect rect; unsigned int mask = NSResizableWindowMask | NSTexturedBackgroundWindowMask | NSMiniaturizableWindowMask; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; nsview = (NSView *)g_value_get_pointer(gst_structure_get_value (s, "nsview")); if (nsview) { rect.origin.x = 100.0; rect.origin.y = 100.0; rect.size.width = 352.0 ; rect.size.height = 288.0; NSApplicationLoad(); win =[[NSWindow alloc] initWithContentRect: rect styleMask: mask backing: NSBackingStoreBuffered defer: NO screen: nil]; [win setContentView:nsview]; [win makeKeyAndOrderFront:nil]; cocoa_windows = g_list_append(cocoa_windows, win); } [pool release]; } #endif } break; case GST_MESSAGE_ERROR: { GError *error = NULL; gchar *debug = NULL; gst_message_parse_error (message, &error, &debug); _notify_debug ("Got an error on the BUS (%d): %s (%s)", error->code, error->message, debug); g_error_free (error); g_free (debug); _notify_error ("Gstreamer error"); } break; default: break; } done: gst_message_unref (message); return 1; } struct xid_data { GstElement *src; gulong window_id; gboolean found; }; static void set_window_xid (gpointer data, gpointer user_data) { GstXOverlay *xov = GST_X_OVERLAY (data); struct xid_data *xiddata = (struct xid_data *) user_data; if (GST_ELEMENT_CAST(xov) == xiddata->src) { gst_x_overlay_set_xwindow_id (xov, xiddata->window_id); xiddata->found = TRUE; } } static GstBusSyncReply _bus_callback (GstBus *bus, GstMessage *message, gpointer user_data) { FarsightBusEvent *evPtr; GstBusSyncReply ret = GST_BUS_PASS; switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ELEMENT: { const GstStructure *s = gst_message_get_structure (message); if (gst_structure_has_name (s, PREFIX "-error")) { goto drop; } else if (gst_structure_has_name (s, PREFIX "-new-local-candidate")) { goto drop; } else if (gst_structure_has_name (s, PREFIX "-local-candidates-prepared")) { goto drop; } else if (gst_structure_has_name (s, PREFIX "-codecs-changed")) { goto drop; } else if (gst_structure_has_name (s, PREFIX "-new-active-candidate-pair")) { goto drop; } else if (gst_structure_has_name (s, "level")) { goto drop; } else if (gst_structure_has_name (s, "prepare-xwindow-id")) { struct xid_data xiddata; GstIterator *it = NULL; xiddata.src = GST_ELEMENT (GST_MESSAGE_SRC (message)); xiddata.window_id = video_preview_xid; xiddata.found = FALSE; if (preview) { it = gst_bin_iterate_all_by_interface (GST_BIN (preview), GST_TYPE_X_OVERLAY); while (gst_iterator_foreach (it, set_window_xid, &xiddata) == GST_ITERATOR_RESYNC) gst_iterator_resync (it); gst_iterator_free (it); } if (xiddata.found == FALSE) { gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (xiddata.src), video_sink_xid); } ret = GST_BUS_DROP; } #ifdef __APPLE__ else if (gst_structure_has_name (s, "have-ns-view")) { goto drop; } #endif } break; case GST_MESSAGE_ERROR: goto drop; break; default: break; } return ret; drop: ret = GST_BUS_DROP; evPtr = (FarsightBusEvent *)ckalloc(sizeof(FarsightBusEvent)); evPtr->header.proc = Farsight_BusEventProc; evPtr->header.nextPtr = NULL; evPtr->message = message; Tcl_ThreadQueueEvent(main_tid, (Tcl_Event *)evPtr, TCL_QUEUE_TAIL); Tcl_ThreadAlert(main_tid); return ret; } static GstElement *_find_source (GstElement *src) { GstElement *source = NULL; if (GST_IS_BIN (src)) { GstIterator *it = gst_bin_iterate_sources (GST_BIN(src)); gboolean done = FALSE; GstElement *item = NULL; while (!done) { switch (gst_iterator_next (it, &item)) { case GST_ITERATOR_OK: source = item; gst_object_unref (item); done = TRUE; break; case GST_ITERATOR_RESYNC: gst_iterator_resync (it); break; case GST_ITERATOR_ERROR: done = TRUE; break; case GST_ITERATOR_DONE: done = TRUE; break; } } gst_iterator_free (it); if (source == NULL) return src; } else { return src; } return _find_source (source); } static GstElement *_find_sink (GstElement *snk) { GstElement *sink = NULL; if (GST_IS_BIN (snk)) { GstIterator *it = gst_bin_iterate_sinks (GST_BIN(snk)); gboolean done = FALSE; GstElement *item = NULL; while (!done) { switch (gst_iterator_next (it, &item)) { case GST_ITERATOR_OK: sink = item; gst_object_unref (item); done = TRUE; break; case GST_ITERATOR_RESYNC: gst_iterator_resync (it); break; case GST_ITERATOR_ERROR: done = TRUE; break; case GST_ITERATOR_DONE: done = TRUE; break; } } gst_iterator_free (it); if (sink == NULL) return snk; } else { return snk; } return _find_sink (sink); } int Farsight_TestAudio _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { GstBus *bus = NULL; GstElement *src = NULL; GstPad *sinkpad = NULL, *srcpad = NULL; GstPad *tempsink; GstElement *snk = NULL; GstElement *src_convert = NULL; GstElement *src_resample = NULL; GstElement *src_convert2 = NULL; GstElement *sink_convert = NULL; GstElement *sink_resample = NULL; GstElement *sink_convert2 = NULL; GstElement *capsfilter = NULL; GstPadLinkReturn ret; gint state = 0; Tcl_Obj *source = NULL; Tcl_Obj *sink = NULL; Tcl_Obj *result = NULL; GstElementFactory *factory = NULL; // We verify the arguments if( objc != 1) { Tcl_WrongNumArgs (interp, 1, objv, ""); return TCL_ERROR; } main_tid = Tcl_GetCurrentThread(); if (pipeline != NULL) { Tcl_AppendResult (interp, "Already started" , (char *) NULL); return TCL_ERROR; } if (test_pipeline != NULL) { Tcl_AppendResult (interp, "Already testing" , (char *) NULL); return TCL_ERROR; } test_pipeline = gst_pipeline_new ("pipeline"); if (test_pipeline == NULL) { Tcl_AppendResult (interp, "Couldn't create gstreamer pipeline" , (char *) NULL); goto error; } bus = gst_element_get_bus (test_pipeline); gst_bus_set_sync_handler (bus, _bus_callback, NULL); gst_object_unref (bus); if (gst_element_set_state (test_pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { Tcl_AppendResult (interp, "Unable to set pipeline to PLAYING", (char *) NULL); goto error; } src = _create_audio_source (); if (src == NULL) { _notify_debug ("Couldn't create audio source, using audiotestsrc"); src = gst_element_factory_make ("audiotestsrc", NULL); } if (gst_bin_add (GST_BIN (test_pipeline), src) == FALSE) { _notify_debug ("Couldn't add audio_source to pipeline"); gst_object_unref (src); src = NULL; goto error; } volumeIn = gst_element_factory_make ("volume", NULL); if (volumeIn) { gst_object_ref (volumeIn); if (gst_bin_add (GST_BIN (test_pipeline), volumeIn) == FALSE) { _notify_debug ("Could not add input volume to pipeline"); gst_object_unref (volumeIn); volumeIn = NULL; goto no_volume_in; } srcpad = gst_element_get_static_pad (volumeIn, "src"); if (gst_element_link(src, volumeIn) == FALSE) { _notify_debug ("Could not link audio_source to volume"); gst_bin_remove (GST_BIN (test_pipeline), volumeIn); gst_object_unref (volumeIn); volumeIn = NULL; goto no_volume_in; } } else { _notify_debug ("Couldn't create volume In elemnt"); no_volume_in: srcpad = gst_element_get_static_pad (src, "src"); } levelIn = gst_element_factory_make ("level", NULL); if (levelIn) { GstPad *levelsink; gst_object_ref (levelIn); if (gst_bin_add (GST_BIN (test_pipeline), levelIn) == FALSE) { _notify_debug ("Could not add input level to pipeline"); gst_object_unref (levelIn); levelIn = NULL; goto no_level_in; } g_object_set (G_OBJECT (levelIn), "message", TRUE, NULL); levelsink = gst_element_get_static_pad (levelIn, "sink"); if (gst_pad_link (srcpad, levelsink) != GST_PAD_LINK_OK) { gst_object_unref (levelsink); _notify_debug ("Couldn't link the volume/src to level"); gst_bin_remove (GST_BIN (test_pipeline), levelIn); gst_object_unref (levelIn); levelIn = NULL; goto no_level_in; } gst_object_unref (srcpad); srcpad = gst_element_get_static_pad (levelIn, "src"); } else { no_level_in: _notify_debug ("Couldn't create level In elemnt"); } src_convert = gst_element_factory_make ("audioconvert", NULL); if (gst_bin_add (GST_BIN (test_pipeline), src_convert) == FALSE) { Tcl_AppendResult (interp, "Could not add src converter to pipeline", (char *) NULL); gst_object_unref (src_convert); goto error; } src_resample = gst_element_factory_make ("audioresample", NULL); if (gst_bin_add (GST_BIN (test_pipeline), src_resample) == FALSE) { Tcl_AppendResult (interp, "Could not add src resampler to pipeline", (char *) NULL); gst_object_unref (src_resample); goto error; } src_convert2 = gst_element_factory_make ("audioconvert", NULL); if (gst_bin_add (GST_BIN (test_pipeline), src_convert2) == FALSE) { Tcl_AppendResult (interp, "Could not add second src converter to pipeline", (char *) NULL); gst_object_unref (src_convert2); goto error; } tempsink = gst_element_get_static_pad (src_convert, "sink"); if (gst_pad_link (srcpad, tempsink) != GST_PAD_LINK_OK) { gst_object_unref (tempsink); _notify_debug ("Couldn't link the src to converter"); gst_bin_remove (GST_BIN (test_pipeline), src_convert); gst_object_unref (src_convert); goto error; } gst_object_unref (srcpad); if (gst_element_link(src_convert, src_resample) == FALSE) { Tcl_AppendResult (interp, "Could not link converter to resampler", (char *) NULL); goto error; } if (gst_element_link(src_resample, src_convert2) == FALSE) { Tcl_AppendResult (interp, "Could not link resampler to second converter", (char *) NULL); goto error; } srcpad = gst_element_get_static_pad (src_convert2, "src"); capsfilter = gst_element_factory_make ("capsfilter", "capsfilter"); if (capsfilter) { GstPad *caps_sink; GstCaps *caps; if (gst_bin_add (GST_BIN (test_pipeline), capsfilter) == FALSE) { _notify_debug ("Could not add capsfilter to pipeline"); gst_object_unref (capsfilter); goto no_capsfilter; } caps_sink = gst_element_get_static_pad (capsfilter, "sink"); if (gst_pad_link (srcpad, caps_sink) != GST_PAD_LINK_OK) { gst_object_unref (caps_sink); _notify_debug ("Couldn't link the volume/level/src to capsfilter"); gst_bin_remove (GST_BIN (test_pipeline), capsfilter); goto no_capsfilter; } caps = gst_caps_new_simple ("audio/x-raw-int", "rate", G_TYPE_INT, 16000, NULL); g_object_set (capsfilter, "caps", caps, NULL); gst_object_unref (srcpad); srcpad = gst_element_get_static_pad (capsfilter, "src"); } else { _notify_debug ("couldn't create capsfilter"); } no_capsfilter: snk = _create_audio_sink (); if (snk == NULL) { Tcl_AppendResult (interp, "Could not create audio_sink", (char *) NULL); goto error; } if (gst_bin_add (GST_BIN (test_pipeline), snk) == FALSE) { Tcl_AppendResult (interp, "Could not add sink to pipeline", (char *) NULL); gst_object_unref (snk); goto error; } sink_convert = gst_element_factory_make ("audioconvert", NULL); if (gst_bin_add (GST_BIN (test_pipeline), sink_convert) == FALSE) { Tcl_AppendResult (interp, "Could not add converter to pipeline", (char *) NULL); gst_object_unref (sink_convert); goto error; } sink_resample = gst_element_factory_make ("audioresample", NULL); if (gst_bin_add (GST_BIN (test_pipeline), sink_resample) == FALSE) { Tcl_AppendResult (interp, "Could not add resampler to pipeline", (char *) NULL); gst_object_unref (sink_resample); goto error; } sink_convert2 = gst_element_factory_make ("audioconvert", NULL); if (gst_bin_add (GST_BIN (test_pipeline), sink_convert2) == FALSE) { Tcl_AppendResult (interp, "Could not add second converter to pipeline", (char *) NULL); gst_object_unref (sink_convert2); goto error; } volumeOut = gst_element_factory_make ("volume", NULL); if (volumeOut) { gst_object_ref (volumeOut); if (gst_bin_add (GST_BIN (test_pipeline), volumeOut) == FALSE) { _notify_debug ("Could not add output volume to pipeline"); gst_object_unref (volumeOut); volumeOut = NULL; goto no_volume_out; } if (gst_element_link(volumeOut, sink_convert) == FALSE) { _notify_debug ("Could not link volume out to converter"); gst_bin_remove (GST_BIN (test_pipeline), volumeOut); gst_object_unref (volumeOut); volumeOut = NULL; goto no_volume_out; } sinkpad = gst_element_get_static_pad (volumeOut, "sink"); } else { _notify_debug ("Couldn't create volume OUT elemnt"); no_volume_out: sinkpad = gst_element_get_static_pad (sink_convert, "sink"); } ret = gst_pad_link (srcpad, sinkpad); gst_object_unref (sinkpad); gst_object_unref (srcpad); if (ret != GST_PAD_LINK_OK) { Tcl_AppendResult (interp, "Could not link src to sink", (char *) NULL); goto error; } if (gst_element_link(sink_convert, sink_resample) == FALSE) { Tcl_AppendResult (interp, "Could not link converter to resampler", (char *) NULL); goto error; } if (gst_element_link(sink_resample, sink_convert2) == FALSE) { Tcl_AppendResult (interp, "Could not link resampler to second converter", (char *) NULL); goto error; } levelOut = gst_element_factory_make ("level", NULL); if (levelOut) { gst_object_ref (levelOut); if (gst_bin_add (GST_BIN (test_pipeline), levelOut) == FALSE) { _notify_debug ("Could not add output level to pipeline"); gst_object_unref (levelOut); levelOut = NULL; goto no_level_out; } g_object_set (G_OBJECT (levelOut), "message", TRUE, NULL); if (gst_element_link(sink_convert2, levelOut) == FALSE) { _notify_debug ("Could not link level out to converter"); gst_bin_remove (GST_BIN (test_pipeline), levelOut); gst_object_unref (levelOut); levelOut = NULL; goto no_level_out; } if (gst_element_link(levelOut, snk) == FALSE) { _notify_debug ("Could not link audio_sink to level out"); gst_element_unlink(sink_convert2, levelOut); gst_bin_remove (GST_BIN (test_pipeline), levelOut); gst_object_unref (levelOut); levelOut = NULL; goto no_level_out; } } else { _notify_debug ("Could not create level out element"); no_level_out: if (gst_element_link(sink_convert2, snk) == FALSE) { Tcl_AppendResult (interp, "Could not link audio_sink to converter", (char *) NULL); goto error; } } if (gst_element_set_state (test_pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { Tcl_AppendResult (interp, "Unable to set pipeline to PLAYING", (char *) NULL); goto error; } if (source_bin) { gst_child_proxy_set (GST_OBJECT(source_bin), "hack_valve::drop", FALSE, NULL); gst_element_set_locked_state (source_bin, FALSE); gst_object_unref (source_bin); source_bin = NULL; } result = Tcl_NewListObj (0, NULL); factory = gst_element_get_factory (_find_source (src)); source = Tcl_NewStringObj (GST_PLUGIN_FEATURE_NAME(factory), -1); factory = gst_element_get_factory (_find_sink (snk)); sink = Tcl_NewStringObj (GST_PLUGIN_FEATURE_NAME(factory), -1); Tcl_ListObjAppendElement(interp, result, source); Tcl_ListObjAppendElement(interp, result, sink); Tcl_SetObjResult (interp, result); return TCL_OK; error: Close (); return TCL_ERROR; } int Farsight_TestVideo _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { GstBus *bus = NULL; GstElement *src = NULL; GstElement *colorspace = NULL; GstElement *snk = NULL; Tcl_Obj *source = NULL; Tcl_Obj *sink = NULL; Tcl_Obj *result = NULL; GstElementFactory *factory = NULL; // We verify the arguments if( objc != 1) { Tcl_WrongNumArgs (interp, 1, objv, ""); return TCL_ERROR; } main_tid = Tcl_GetCurrentThread(); if (pipeline != NULL) { Tcl_AppendResult (interp, "Already started" , (char *) NULL); return TCL_ERROR; } if (test_pipeline != NULL) { Tcl_AppendResult (interp, "Already testing" , (char *) NULL); return TCL_ERROR; } test_pipeline = gst_pipeline_new ("pipeline"); if (test_pipeline == NULL) { Tcl_AppendResult (interp, "Couldn't create gstreamer pipeline" , (char *) NULL); goto error; } bus = gst_element_get_bus (test_pipeline); gst_bus_set_sync_handler (bus, _bus_callback, NULL); gst_object_unref (bus); if (gst_element_set_state (test_pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { Tcl_AppendResult (interp, "Unable to set pipeline to PLAYING", (char *) NULL); goto error; } src = _create_video_source (); if (src == NULL) { _notify_debug ("Couldn't create video source, using videotestsrc"); src = gst_element_factory_make ("videotestsrc", NULL); } if (gst_bin_add (GST_BIN (test_pipeline), src) == FALSE) { _notify_debug ("Couldn't add video_source to test pipeline"); gst_element_set_state (test_pipeline, GST_STATE_NULL); gst_object_unref (src); src = NULL; goto error; } colorspace = gst_element_factory_make ("ffmpegcolorspace", NULL); if (colorspace == NULL || gst_bin_add (GST_BIN (test_pipeline), colorspace) == FALSE) { _notify_debug ("Could not add colorspace to test pipeline"); gst_object_unref (colorspace); goto error; } if (gst_element_link(src, colorspace) == FALSE) { _notify_debug ("Could not link source to colorspace"); goto error; } /* Uncomment once we want to have a TestView that also tests the video sink */ if (preview) snk = gst_element_factory_make ("fakesink", NULL); else snk = _create_video_sink (); if (snk == NULL) { Tcl_AppendResult (interp, "Could not create video sink", (char *) NULL); goto error; } if (gst_bin_add (GST_BIN (test_pipeline), snk) == FALSE) { Tcl_AppendResult (interp, "Could not add video sink to pipeline", (char *) NULL); if (snk) gst_object_unref (snk); goto error; } if (gst_element_link(colorspace, snk) == FALSE) { _notify_debug ("Could not link colorspace to sink"); goto error; } if (preview == NULL) { preview = snk; gst_object_ref (preview); } if (gst_element_set_state (test_pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { Tcl_AppendResult (interp, "Unable to set pipeline to PLAYING", (char *) NULL); goto error; } if (source_bin) { gst_child_proxy_set (GST_OBJECT(source_bin), "hack_valve::drop", FALSE, NULL); gst_element_set_locked_state (source_bin, FALSE); gst_object_unref (source_bin); source_bin = NULL; } result = Tcl_NewListObj (0, NULL); factory = gst_element_get_factory (_find_source (src)); source = Tcl_NewStringObj (GST_PLUGIN_FEATURE_NAME(factory), -1); factory = gst_element_get_factory (_find_sink (snk)); sink = Tcl_NewStringObj (GST_PLUGIN_FEATURE_NAME(factory), -1); Tcl_ListObjAppendElement(interp, result, source); Tcl_ListObjAppendElement(interp, result, sink); Tcl_SetObjResult (interp, result); return TCL_OK; error: Close (); return TCL_ERROR; } static int _tcl_codecs_to_fscodecs (Tcl_Interp *interp, Tcl_Obj **tcl_remote_codecs, int total_codecs, GList **remote_codecs, FsMediaType media_type) { FsCodec *codec = NULL; int i; for (i = 0; i < total_codecs; i++) { int total_elements; Tcl_Obj **elements = NULL; codec = fs_codec_new (0, NULL, media_type, 0); if (Tcl_ListObjGetElements(interp, tcl_remote_codecs[i], &total_elements, &elements) != TCL_OK) { Tcl_AppendResult (interp, "\nInvalid codec", (char *) NULL); goto error_codec; } if (total_elements != 3) { Tcl_AppendResult (interp, "\nInvalid codec : ", Tcl_GetString (tcl_remote_codecs[i]), (char *) NULL); goto error_codec; } codec->encoding_name = g_strdup (Tcl_GetStringFromObj (elements[0], NULL)); if (Tcl_GetIntFromObj (interp, elements[1], &codec->id) != TCL_OK) { Tcl_AppendResult (interp, "\nInvalid codec : ", Tcl_GetString (tcl_remote_codecs[i]), (char *) NULL); goto error_codec; } if (Tcl_GetIntFromObj (interp, elements[2], &codec->clock_rate) != TCL_OK) { Tcl_AppendResult (interp, "\nInvalid codec : ", Tcl_GetString (tcl_remote_codecs[i]), (char *) NULL); goto error_codec; } _notify_debug ("New remote %s codec : %d %s %d", media_type == FS_MEDIA_TYPE_AUDIO ? "audio" : "video", codec->id, codec->encoding_name, codec->clock_rate); *remote_codecs = g_list_append (*remote_codecs, codec); } return TCL_OK; error_codec: fs_codec_destroy (codec); fs_codec_list_destroy (*remote_codecs); *remote_codecs = NULL; return TCL_ERROR; } static int _tcl_candidates_to_fscandidates (Tcl_Interp *interp, Tcl_Obj **tcl_remote_candidates, int total_candidates, GList **remote_candidates) { FsCandidate *candidate = NULL; int i; for (i = 0; i < total_candidates; i++) { int total_elements; Tcl_Obj **elements = NULL; double temp_d; int temp_i; char *temp_s; candidate = fs_candidate_new (NULL, 1, 0, FS_NETWORK_PROTOCOL_UDP, NULL, 0); if (Tcl_ListObjGetElements(interp, tcl_remote_candidates[i], &total_elements, &elements) != TCL_OK) { Tcl_AppendResult (interp, "\nInvalid candidate", (char *) NULL); goto error_candidate; } if (total_elements != 11) { Tcl_AppendResult (interp, "Invalid candidate : ", Tcl_GetString (tcl_remote_candidates[i]), (char *) NULL); goto error_candidate; } /* Foundation */ candidate->foundation = g_strdup (Tcl_GetString (elements[0])); /* Component id*/ if (Tcl_GetIntFromObj (interp, elements[1], &candidate->component_id) != TCL_OK) { Tcl_AppendResult (interp, "\nInvalid candidate : ", Tcl_GetString (tcl_remote_candidates[i]), (char *) NULL); goto error_candidate; } /* IP */ candidate->ip = g_strdup (Tcl_GetString (elements[2])); /* port */ if (Tcl_GetIntFromObj (interp, elements[3], &temp_i) != TCL_OK) { Tcl_AppendResult (interp, "\nInvalid candidate : ", Tcl_GetString (tcl_remote_candidates[i]), (char *) NULL); goto error_candidate; } candidate->port = temp_i; /* base IP */ if (Tcl_GetString (elements[4]) != NULL && Tcl_GetString (elements[4])[0] != 0) { candidate->base_ip = g_strdup (Tcl_GetString (elements[4])); /* base port */ if (Tcl_GetIntFromObj (interp, elements[5], &temp_i) != TCL_OK) { Tcl_AppendResult (interp, "\nInvalid candidate : ", Tcl_GetString (tcl_remote_candidates[i]), (char *) NULL); goto error_candidate; } candidate->base_port = temp_i; } /* Protocol */ candidate->proto = strcmp (Tcl_GetString (elements[6]), "UDP") == 0 ? FS_NETWORK_PROTOCOL_UDP : FS_NETWORK_PROTOCOL_TCP; /* Priority */ if (call_type & RTP_ICE6) { if (Tcl_GetDoubleFromObj (interp, elements[7], &temp_d) != TCL_OK) { Tcl_AppendResult (interp, "\nInvalid candidate : ", Tcl_GetString (tcl_remote_candidates[i]), (char *) NULL); goto error_candidate; } candidate->priority = (guint32) (temp_d * 1000); } else { if (Tcl_GetIntFromObj (interp, elements[7], &temp_i) != TCL_OK) { Tcl_AppendResult (interp, "\nInvalid candidate : ", Tcl_GetString (tcl_remote_candidates[i]), (char *) NULL); goto error_candidate; } candidate->priority = temp_i; } /* Type */ temp_s = Tcl_GetString (elements[8]); if (strcmp (temp_s, "host") == 0) { candidate->type = FS_CANDIDATE_TYPE_HOST; } else if (strcmp (temp_s, "srflx") == 0) { candidate->type = FS_CANDIDATE_TYPE_SRFLX; } else if (strcmp (temp_s, "prflx") == 0) { candidate->type = FS_CANDIDATE_TYPE_PRFLX; } else if (strcmp (temp_s, "relay") == 0) { candidate->type = FS_CANDIDATE_TYPE_RELAY; } /* Username/Password */ candidate->username = g_strdup (Tcl_GetString (elements[9])); candidate->password = g_strdup (Tcl_GetString (elements[10])); _notify_debug ("New Remote candidate: %s %d %s %d %s %d %s %d %s %s %s\n", candidate->foundation == NULL ? "-" : candidate->foundation, candidate->component_id, candidate->ip, candidate->port, candidate->base_ip == NULL ? "-" : candidate->base_ip, candidate->base_port, candidate->proto == FS_NETWORK_PROTOCOL_UDP ? "UDP" : "TCP", candidate->priority, _fs_candidate_type_to_string (candidate->type), candidate->username == NULL ? "-" : candidate->username, candidate->password == NULL ? "-" : candidate->password); *remote_candidates = g_list_append (*remote_candidates, candidate); } return TCL_OK; error_candidate: fs_candidate_destroy (candidate); fs_candidate_list_destroy (*remote_candidates); *remote_candidates = NULL; return TCL_ERROR; } static int _tcl_relay_info_to_gvalue_array (Tcl_Interp *interp, Tcl_Obj **tcl_relay_info, int total_relay_info, GValueArray **audio_relay_info, GValueArray **video_relay_info) { int i; for (i = 0; i < total_relay_info; i++) { char *turn_ip = NULL; char *turn_hostname = NULL; int turn_port = 1863; int stream = 0; int component = 0; char *username = NULL; char *password = NULL; char *type = NULL; int total_elements; Tcl_Obj **elements = NULL; GstStructure *turn_setup = NULL; GValue gvalue = { 0 }; g_value_init (&gvalue, GST_TYPE_STRUCTURE); if (Tcl_ListObjGetElements(interp, tcl_relay_info[i], &total_elements, &elements) != TCL_OK) { Tcl_AppendResult (interp, "\nInvalid relay info element", (char *) NULL); return TCL_ERROR; } if (total_elements != 7) { Tcl_AppendResult (interp, "\nInvalid relay info element : ", Tcl_GetString (tcl_relay_info[i]), (char *) NULL); return TCL_ERROR; } turn_hostname = Tcl_GetStringFromObj (elements[0], NULL); turn_ip = host2ip (turn_hostname); if (turn_ip == NULL) { Tcl_AppendResult (interp, "TURN server invalid : Could not resolve hostname", (char *) NULL); return TCL_ERROR; } if (Tcl_GetIntFromObj (interp, elements[1], &turn_port) == TCL_ERROR) { Tcl_AppendResult (interp, "TURN port invalid : Expected integer" , (char *) NULL); return TCL_ERROR; } if (turn_port == 0) { turn_port = 1863; } username = Tcl_GetStringFromObj (elements[2], NULL); password = Tcl_GetStringFromObj (elements[3], NULL); if (Tcl_GetIntFromObj (interp, elements[4], &stream) == TCL_ERROR) { Tcl_AppendResult (interp, "TURN stream invalid : Expected integer" , (char *) NULL); return TCL_ERROR; } if (Tcl_GetIntFromObj (interp, elements[5], &component) == TCL_ERROR) { Tcl_AppendResult (interp, "TURN component invalid : Expected integer" , (char *) NULL); return TCL_ERROR; } type = Tcl_GetStringFromObj (elements[6], NULL); turn_setup = gst_structure_new ("relay-info", "ip", G_TYPE_STRING, turn_ip, "port", G_TYPE_UINT, turn_port, "component", G_TYPE_UINT, component, "username", G_TYPE_STRING, username, "password", G_TYPE_STRING, password, "relay-type", G_TYPE_STRING, type, NULL); if (turn_setup == NULL) { Tcl_AppendResult (interp, "Unable to create relay info" , (char *) NULL); return TCL_ERROR; } gst_value_set_structure (&gvalue, turn_setup); if (stream == 1) { if (*audio_relay_info == NULL) { *audio_relay_info = g_value_array_new (0); } *audio_relay_info = g_value_array_append (*audio_relay_info, &gvalue); } else if (stream == 2) { if (*video_relay_info == NULL) { *video_relay_info = g_value_array_new (0); } *video_relay_info = g_value_array_append (*video_relay_info, &gvalue); } else { gst_structure_free (turn_setup); Tcl_AppendResult (interp, "Invalid stream id" , (char *) NULL); return TCL_ERROR; } gst_structure_free (turn_setup); } return TCL_OK; } int Farsight_Prepare _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { GError *error = NULL; GstBus *bus = NULL; GstElement *src = NULL; GstPad *sinkpad = NULL, *srcpad = NULL; GstPad *tempsink; GstElement *conference = NULL; GstElement *src_convert = NULL; GstElement *src_resample = NULL; GstElement *src_convert2 = NULL; GstElement *src_colorspace = NULL; GParameter transmitter_params[6]; int controlling; char *stun_ip = NULL; char *stun_hostname = NULL; int stun_port = 3478; Tcl_Obj **tcl_relay_info = NULL; int total_relay_info; GValueArray *audio_relay_info = NULL; GValueArray *video_relay_info = NULL; int total_params; char *mode = NULL; // We verify the arguments if( objc < 4 || objc > 7) { Tcl_WrongNumArgs (interp, 1, objv, " callback controlling mode ?relay_info?" " ?stun_ip stun_port?\n" "Where mode can be either : " OLD_AUDIO_CALL ", " OLD_AUDIO_VIDEO_CALL ", " NEW_AUDIO_CALL " or " NEW_AUDIO_VIDEO_CALL "\n" "Where relay_info is a list with each element being a list containing : " "{turn_hostname turn_port turn_username turn_password stream component type}"); return TCL_ERROR; } if (Tcl_GetBooleanFromObj (interp, objv[2], &controlling) != TCL_OK) { return TCL_ERROR; } mode = Tcl_GetStringFromObj (objv[3], NULL); if (strcmp (mode, OLD_AUDIO_CALL) == 0) { call_type = RTP_AUDIO_ICE6; } else if (strcmp (mode, OLD_AUDIO_VIDEO_CALL) == 0) { call_type = RTP_AUDIO_VIDEO_ICE6; } else if (strcmp (mode, NEW_AUDIO_CALL) == 0) { call_type = RTP_AUDIO_ICE19; } else if (strcmp (mode, NEW_AUDIO_VIDEO_CALL) == 0) { call_type = RTP_AUDIO_VIDEO_ICE19; } else { Tcl_AppendResult (interp, "Invalid call mode, must be either : ", OLD_AUDIO_CALL, ", ", NEW_AUDIO_CALL, " or ", NEW_AUDIO_VIDEO_CALL, (char *) NULL); return TCL_ERROR; } if (pipeline != NULL) { Tcl_AppendResult (interp, "Already prepared/in preparation" , (char *) NULL); return TCL_ERROR; } if (test_pipeline != NULL) { Close (); } callback = objv[1]; Tcl_IncrRefCount (callback); callback_interp = interp; main_tid = Tcl_GetCurrentThread(); if (objc > 4) { if (Tcl_ListObjGetElements(interp, objv[4], &total_relay_info, &tcl_relay_info) != TCL_OK) { Tcl_AppendResult (interp, "\nInvalid relay info", (char *) NULL); return TCL_ERROR; } if (_tcl_relay_info_to_gvalue_array (interp, tcl_relay_info, total_relay_info, &audio_relay_info, &video_relay_info) != TCL_OK) { goto error; } } if (objc > 5) { stun_hostname = Tcl_GetStringFromObj (objv[5], NULL); stun_ip = host2ip (stun_hostname); if (stun_ip == NULL) { Tcl_AppendResult (interp, "Stun server invalid : Could not resolve hostname", (char *) NULL); return TCL_ERROR; } } if (objc > 6) { if (Tcl_GetIntFromObj (interp, objv[6], &stun_port) == TCL_ERROR) { Tcl_AppendResult (interp, "Stun port invalid : Expected integer" , (char *) NULL); return TCL_ERROR; } } audio_candidates_prepared = FALSE; audio_codecs_ready = FALSE; video_candidates_prepared = FALSE; video_codecs_ready = FALSE; pipeline = gst_pipeline_new ("pipeline"); if (pipeline == NULL) { Tcl_AppendResult (interp, "Couldn't create gstreamer pipeline" , (char *) NULL); goto error; } bus = gst_element_get_bus (pipeline); gst_bus_set_sync_handler (bus, _bus_callback, NULL); gst_object_unref (bus); if (gst_element_set_state (pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { Tcl_AppendResult (interp, "Unable to set pipeline to PLAYING", (char *) NULL); goto error; } conference = gst_element_factory_make ("fsrtpconference", NULL); if (conference == NULL) { Tcl_AppendResult (interp, "Couldn't create fsrtpconference" , (char *) NULL); goto error; } if (gst_bin_add (GST_BIN (pipeline), conference) == FALSE) { Tcl_AppendResult (interp, "Couldn't add fsrtpconference to the pipeline", (char *) NULL); goto error; } g_object_set (conference, "sdes-cname", "", NULL); fsnotifier = fs_element_added_notifier_new (); fs_element_added_notifier_add (fsnotifier, GST_BIN (conference)); g_signal_connect (fsnotifier, "element-added", G_CALLBACK (_conference_element_added), NULL); participant = fs_conference_new_participant (FS_CONFERENCE (conference), #ifdef HAVE_FARSIGHT "", #endif /* HAVE_FARSIGHT */ &error); if (error) { char temp[1000]; snprintf (temp, 1000, "Error while creating new participant (%d): %s", error->code, error->message); Tcl_AppendResult (interp, temp, (char *) NULL); goto error; } if (participant == NULL) { Tcl_AppendResult (interp, "Couldn't create new participant" , (char *) NULL); goto error; } audio_session = fs_conference_new_session (FS_CONFERENCE (conference), FS_MEDIA_TYPE_AUDIO, &error); if (error) { char temp[1000]; snprintf (temp, 1000, "Error while creating new audio_session (%d): %s", error->code, error->message); Tcl_AppendResult (interp, temp, (char *) NULL); goto error; } if (audio_session == NULL) { Tcl_AppendResult (interp, "Couldn't create new audio_session" , (char *) NULL); goto error; } /* Set codec preferences.. if this fails, then it's no big deal.. */ { GList *codec_preferences = NULL; FsCodec *x_msrta_16000 = fs_codec_new (114, "x-msrta", FS_MEDIA_TYPE_AUDIO, 16000); FsCodec *siren = fs_codec_new (111, "SIREN", FS_MEDIA_TYPE_AUDIO, 16000); FsCodec *g7221 = fs_codec_new (112, "G7221", FS_MEDIA_TYPE_AUDIO, 16000); FsCodec *x_msrta_8000 = fs_codec_new (115, "x-msrta", FS_MEDIA_TYPE_AUDIO, 8000); FsCodec *aal2 = fs_codec_new (116, "AAL2-G726-32", FS_MEDIA_TYPE_AUDIO, 8000); FsCodec *g723 = fs_codec_new (4, "G723", FS_MEDIA_TYPE_AUDIO, 8000); FsCodec *pcma = fs_codec_new (8, "PCMA", FS_MEDIA_TYPE_AUDIO, 8000); FsCodec *pcmu = fs_codec_new (0, "PCMU", FS_MEDIA_TYPE_AUDIO, 8000); FsCodec *red = fs_codec_new (97, "RED", FS_MEDIA_TYPE_AUDIO, 8000); FsCodec *telephone_event = fs_codec_new (101, "telephone-event", FS_MEDIA_TYPE_AUDIO, 8000); codec_preferences = g_list_append (codec_preferences, x_msrta_16000); codec_preferences = g_list_append (codec_preferences, siren); codec_preferences = g_list_append (codec_preferences, g7221); codec_preferences = g_list_append (codec_preferences, x_msrta_8000); codec_preferences = g_list_append (codec_preferences, aal2); codec_preferences = g_list_append (codec_preferences, g723); codec_preferences = g_list_append (codec_preferences, pcma); codec_preferences = g_list_append (codec_preferences, pcmu); codec_preferences = g_list_append (codec_preferences, red); codec_preferences = g_list_append (codec_preferences, telephone_event); fs_session_set_codec_preferences (audio_session, codec_preferences, NULL); fs_codec_list_destroy (codec_preferences); } if (!audio_codecs_ready) { gboolean ready; g_object_get (audio_session, "codecs-ready", &ready, NULL); if (ready) { _codecs_ready (audio_session); } } g_object_set (audio_session, "no-rtcp-timeout", 0, NULL); g_object_get (audio_session, "sink-pad", &sinkpad, NULL); if (sinkpad == NULL) { Tcl_AppendResult (interp, "Couldn't get sink pad" , (char *) NULL); goto error; } src = _create_audio_source (); if (src == NULL) { _notify_debug ("Couldn't create audio source"); goto no_audio_source; } if (gst_bin_add (GST_BIN (pipeline), src) == FALSE) { _notify_debug ("Couldn't add audio_source to pipeline"); if (src) gst_object_unref (src); goto no_audio_source; } volumeIn = gst_element_factory_make ("volume", NULL); if (volumeIn) { gst_object_ref (volumeIn); if (gst_bin_add (GST_BIN (pipeline), volumeIn) == FALSE) { _notify_debug ("Could not add input volume to pipeline"); gst_object_unref (volumeIn); volumeIn = NULL; goto no_volume; } srcpad = gst_element_get_static_pad (volumeIn, "src"); if (gst_element_link(src, volumeIn) == FALSE) { _notify_debug ("Could not link audio_source to volume"); gst_bin_remove (GST_BIN (pipeline), volumeIn); gst_object_unref (volumeIn); volumeIn = NULL; goto no_volume; } } else { no_volume: srcpad = gst_element_get_static_pad (src, "src"); } levelIn = gst_element_factory_make ("level", NULL); if (levelIn) { GstPad *levelsink; gst_object_ref (levelIn); if (gst_bin_add (GST_BIN (pipeline), levelIn) == FALSE) { _notify_debug ("Could not add input level to pipeline"); gst_object_unref (levelIn); levelIn = NULL; goto no_level; } g_object_set (G_OBJECT (levelIn), "message", TRUE, NULL); levelsink = gst_element_get_static_pad (levelIn, "sink"); if (gst_pad_link (srcpad, levelsink) != GST_PAD_LINK_OK) { gst_object_unref (levelsink); gst_object_unref (srcpad); _notify_debug ("Couldn't link the volume/src to level"); gst_bin_remove (GST_BIN (pipeline), levelIn); gst_object_unref (levelIn); levelIn = NULL; goto no_level; } gst_object_unref (srcpad); srcpad = gst_element_get_static_pad (levelIn, "src"); } no_level: src_convert = gst_element_factory_make ("audioconvert", NULL); if (gst_bin_add (GST_BIN (pipeline), src_convert) == FALSE) { Tcl_AppendResult (interp, "Could not add src converter to pipeline", (char *) NULL); gst_object_unref (src_convert); goto error; } src_resample = gst_element_factory_make ("audioresample", NULL); if (gst_bin_add (GST_BIN (pipeline), src_resample) == FALSE) { Tcl_AppendResult (interp, "Could not add src resampler to pipeline", (char *) NULL); gst_object_unref (src_resample); goto error; } src_convert2 = gst_element_factory_make ("audioconvert", NULL); if (gst_bin_add (GST_BIN (pipeline), src_convert2) == FALSE) { Tcl_AppendResult (interp, "Could not add second src converter to pipeline", (char *) NULL); gst_object_unref (src_convert2); goto error; } tempsink = gst_element_get_static_pad (src_convert, "sink"); if (gst_pad_link (srcpad, tempsink) != GST_PAD_LINK_OK) { gst_object_unref (tempsink); gst_object_unref (srcpad); _notify_debug ("Couldn't link the src to converter"); goto error; } gst_object_unref (srcpad); gst_object_unref (tempsink); if (gst_element_link(src_convert, src_resample) == FALSE) { Tcl_AppendResult (interp, "Could not link converter to resampler", (char *) NULL); goto error; } if (gst_element_link(src_resample, src_convert2) == FALSE) { Tcl_AppendResult (interp, "Could not link resampler to second converter", (char *) NULL); goto error; } srcpad = gst_element_get_static_pad (src_convert2, "src"); if (gst_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK) { gst_object_unref (sinkpad); gst_object_unref (srcpad); _notify_debug ("Couldn't link the volume/level/src to fsrtpconference"); goto no_audio_source; } gst_object_unref (sinkpad); gst_object_unref (srcpad); no_audio_source: memset (transmitter_params, 0, sizeof (GParameter) * 6); total_params = 0; transmitter_params[total_params].name = "compatibility-mode"; g_value_init (&transmitter_params[total_params].value, G_TYPE_UINT); if (call_type & RTP_ICE6) { g_value_set_uint (&transmitter_params[total_params].value, 2); } else { g_value_set_uint (&transmitter_params[total_params].value, 3); } total_params++; transmitter_params[total_params].name = "controlling-mode"; g_value_init (&transmitter_params[total_params].value, G_TYPE_BOOLEAN); g_value_set_boolean (&transmitter_params[total_params].value, controlling); total_params++; if (stun_ip) { _notify_debug ("stun ip : %s : %d", stun_ip, stun_port); transmitter_params[total_params].name = "stun-ip"; g_value_init (&transmitter_params[total_params].value, G_TYPE_STRING); g_value_set_string (&transmitter_params[total_params].value, stun_ip); total_params++; transmitter_params[total_params].name = "stun-port"; g_value_init (&transmitter_params[total_params].value, G_TYPE_UINT); g_value_set_uint (&transmitter_params[total_params].value, stun_port); total_params++; } if (audio_relay_info) { _notify_debug ("FS: relay info = %p - %d", audio_relay_info, audio_relay_info->n_values); transmitter_params[total_params].name = "relay-info"; g_value_init (&transmitter_params[total_params].value, G_TYPE_VALUE_ARRAY); g_value_set_boxed (&transmitter_params[total_params].value, audio_relay_info); total_params++; } #ifdef HAVE_FARSTREAM audio_stream = fs_session_new_stream (audio_session, participant, FS_DIRECTION_BOTH, &error); if(!fs_stream_set_transmitter(audio_stream, "nice", transmitter_params, total_params, &error)) { char temp[1000]; snprintf (temp, 1000, "Could not set transmitter \"nice\" (%d): %s.", error->code, error->message); goto error; } #else audio_stream = fs_session_new_stream (audio_session, participant, FS_DIRECTION_BOTH, "nice", total_params, transmitter_params, &error); #endif /* HAVE_FARSTREAM */ if (error) { char temp[1000]; snprintf (temp, 1000, "Error while creating new audio_stream (%d): %s", error->code, error->message); Tcl_AppendResult (interp, temp, (char *) NULL); goto error; } if (audio_stream == NULL) { Tcl_AppendResult (interp, "Couldn't create new audio_stream" , (char *) NULL); goto error; } g_signal_connect (audio_stream, "src-pad-added", G_CALLBACK (_audio_src_pad_added), pipeline); /* Setup video pipeline */ if (call_type & RTP_VIDEO) { video_session = fs_conference_new_session (FS_CONFERENCE (conference), FS_MEDIA_TYPE_VIDEO, &error); if (error) { char temp[1000]; snprintf (temp, 1000, "Error while creating new video_session (%d): %s", error->code, error->message); Tcl_AppendResult (interp, temp, (char *) NULL); goto error; } if (video_session == NULL) { Tcl_AppendResult (interp, "Couldn't create new video_session" , (char *) NULL); goto error; } /* Set codec preferences.. if this fails, then it's no big deal.. */ { GList *codec_preferences = NULL; FsCodec *x_rtvc1 = fs_codec_new (121, "x-rtvc1", FS_MEDIA_TYPE_VIDEO, 90000); FsCodec *h263 = fs_codec_new (34, "H263", FS_MEDIA_TYPE_VIDEO, 90000); codec_preferences = g_list_append (codec_preferences, x_rtvc1); codec_preferences = g_list_append (codec_preferences, h263); fs_session_set_codec_preferences (video_session, codec_preferences, NULL); fs_codec_list_destroy (codec_preferences); } if (!video_codecs_ready) { gboolean ready; g_object_get (video_session, "codecs-ready", &ready, NULL); if (ready) { _codecs_ready (video_session); } } g_object_set (video_session, "no-rtcp-timeout", 0, NULL); g_object_get (video_session, "sink-pad", &sinkpad, NULL); if (sinkpad == NULL) { Tcl_AppendResult (interp, "Couldn't get sink pad" , (char *) NULL); goto error; } src = _create_video_source (); if (src == NULL) { _notify_debug ("Couldn't create video_source"); goto no_video_source; } if (gst_bin_add (GST_BIN (pipeline), src) == FALSE) { _notify_debug ("Couldn't add video source to pipeline"); if (src) gst_object_unref (src); if (!video_codecs_ready) { _codecs_ready (video_session); } goto no_video_source; } src_colorspace = gst_element_factory_make ("ffmpegcolorspace", NULL); if (gst_bin_add (GST_BIN (pipeline), src_colorspace) == FALSE) { Tcl_AppendResult (interp, "Could not add src colorspace to pipeline", (char *) NULL); gst_object_unref (src_colorspace); goto error; } if (gst_element_link(src, src_colorspace) == FALSE) { Tcl_AppendResult (interp, "Could not link src to colorspace", (char *) NULL); goto error; } srcpad = gst_element_get_static_pad (src_colorspace, "src"); if (gst_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK) { gst_object_unref (sinkpad); gst_object_unref (srcpad); _notify_debug ("Couldn't link the colorspace to fsrtpconference"); if (!video_codecs_ready) { _codecs_ready (video_session); } goto no_video_source; } gst_object_unref (sinkpad); gst_object_unref (srcpad); no_video_source: memset (transmitter_params, 0, sizeof (GParameter) * 6); total_params = 0; transmitter_params[total_params].name = "compatibility-mode"; g_value_init (&transmitter_params[total_params].value, G_TYPE_UINT); if (call_type & RTP_ICE6) { g_value_set_uint (&transmitter_params[total_params].value, 2); } else { g_value_set_uint (&transmitter_params[total_params].value, 3); } total_params++; transmitter_params[total_params].name = "controlling-mode"; g_value_init (&transmitter_params[total_params].value, G_TYPE_BOOLEAN); g_value_set_boolean (&transmitter_params[total_params].value, controlling); total_params++; if (stun_ip) { _notify_debug ("stun ip : %s : %d", stun_ip, stun_port); transmitter_params[total_params].name = "stun-ip"; g_value_init (&transmitter_params[total_params].value, G_TYPE_STRING); g_value_set_string (&transmitter_params[total_params].value, stun_ip); total_params++; transmitter_params[total_params].name = "stun-port"; g_value_init (&transmitter_params[total_params].value, G_TYPE_UINT); g_value_set_uint (&transmitter_params[total_params].value, stun_port); total_params++; } if (video_relay_info) { _notify_debug ("FS: relay info = %p - %d", video_relay_info, video_relay_info->n_values); transmitter_params[total_params].name = "relay-info"; g_value_init (&transmitter_params[total_params].value, G_TYPE_VALUE_ARRAY); g_value_set_boxed (&transmitter_params[total_params].value, video_relay_info); total_params++; } #ifdef HAVE_FARSTREAM video_stream = fs_session_new_stream (video_session, participant, FS_DIRECTION_BOTH, &error); if(!fs_stream_set_transmitter(video_stream, "nice", transmitter_params, total_params, &error)) { char temp[1000]; snprintf (temp, 1000, "Could not set transmitter \"nice\" (%d): %s.", error->code, error->message); goto error; } #else video_stream = fs_session_new_stream (video_session, participant, FS_DIRECTION_BOTH, "nice", total_params, transmitter_params, &error); #endif /* HAVE_FARSTREAM */ if (error) { char temp[1000]; snprintf (temp, 1000, "Error while creating new video_stream (%d): %s", error->code, error->message); Tcl_AppendResult (interp, temp, (char *) NULL); goto error; } if (video_stream == NULL) { Tcl_AppendResult (interp, "Couldn't create new video_stream" , (char *) NULL); goto error; } g_signal_connect (video_stream, "src-pad-added", G_CALLBACK (_video_src_pad_added), pipeline); } if (gst_element_set_state (pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { Tcl_AppendResult (interp, "Unable to set pipeline to PLAYING", (char *) NULL); goto error; } if (source_bin) { gst_child_proxy_set (GST_OBJECT(source_bin), "hack_valve::drop", FALSE, NULL); gst_element_set_locked_state (source_bin, FALSE); gst_object_unref (source_bin); source_bin = NULL; } if (!video_codecs_ready) { _codecs_ready (video_session); } if (audio_relay_info) g_value_array_free (audio_relay_info); if (video_relay_info) g_value_array_free (video_relay_info); return TCL_OK; error: _notify_debug ("Error: %s", Tcl_GetStringResult(interp)); Close (); if (audio_relay_info) g_value_array_free (audio_relay_info); if (video_relay_info) g_value_array_free (video_relay_info); return TCL_ERROR; } int Farsight_Start _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { GError *error = NULL; GList *audio_remote_codecs = NULL; GList *video_remote_codecs = NULL; int total_codecs; Tcl_Obj **tcl_remote_codecs = NULL; GList *audio_remote_candidates = NULL; GList *video_remote_candidates = NULL; int total_candidates; Tcl_Obj **tcl_remote_candidates = NULL; // We verify the arguments if( objc != 3 && objc != 5) { Tcl_WrongNumArgs (interp, 1, objv, " remote_audio_codecs remote_audio_candidates" " ?remote_video_codecs remote_video_candidates?\n" "Where remote_codecs is a list with each element being a list containing : " "{encoding_name payload_type clock_rate}\n" "And where remote_candidates is a list with each element being a list containing : " "{foundation component_id ip port base_ip base_port protocol " "priority type username password}"); return TCL_ERROR; } if (pipeline == NULL) { Tcl_AppendResult (interp, LIBNAME " needs to be prepared first", (char *) NULL); return TCL_ERROR; } /* Get audio codecs */ if (Tcl_ListObjGetElements(interp, objv[1], &total_codecs, &tcl_remote_codecs) != TCL_OK) { Tcl_AppendResult (interp, "\nInvalid codec list", (char *) NULL); return TCL_ERROR; } if (_tcl_codecs_to_fscodecs (interp, tcl_remote_codecs, total_codecs, &audio_remote_codecs, FS_MEDIA_TYPE_AUDIO) != TCL_OK) { goto error; } /* Get video codecs */ if (objc == 5) { if (Tcl_ListObjGetElements(interp, objv[3], &total_codecs, &tcl_remote_codecs) != TCL_OK) { Tcl_AppendResult (interp, "\nInvalid codec list", (char *) NULL); return TCL_ERROR; } if (_tcl_codecs_to_fscodecs (interp, tcl_remote_codecs, total_codecs, &video_remote_codecs, FS_MEDIA_TYPE_VIDEO) != TCL_OK) { goto error; } } /* Get audio candidates */ if (Tcl_ListObjGetElements(interp, objv[2], &total_candidates, &tcl_remote_candidates) != TCL_OK) { Tcl_AppendResult (interp, "\nInvalid candidates list", (char *) NULL); return TCL_ERROR; } if (_tcl_candidates_to_fscandidates (interp, tcl_remote_candidates, total_candidates, &audio_remote_candidates) != TCL_OK) { goto error; } /* Get video candidates */ if (objc == 5) { if (Tcl_ListObjGetElements(interp, objv[4], &total_candidates, &tcl_remote_candidates) != TCL_OK) { Tcl_AppendResult (interp, "\nInvalid candidates list", (char *) NULL); return TCL_ERROR; } if (_tcl_candidates_to_fscandidates (interp, tcl_remote_candidates, total_candidates, &video_remote_candidates) != TCL_OK) { goto error; } } /* Set audio candidates */ if (audio_remote_candidates) { if (!fs_stream_set_remote_candidates (audio_stream, audio_remote_candidates, &error)) { Tcl_AppendResult (interp, "Could not set the audio remote candidates", (char *) NULL); goto error; } fs_candidate_list_destroy (audio_remote_candidates); audio_remote_candidates = NULL; } /* Set video candidates */ if (video_remote_candidates && video_stream) { if (!fs_stream_set_remote_candidates (video_stream, video_remote_candidates, &error)) { Tcl_AppendResult (interp, "Could not set the video remote candidates", (char *) NULL); goto error; } fs_candidate_list_destroy (video_remote_candidates); video_remote_candidates = NULL; } /* Set audio codecs */ if (audio_remote_codecs) { if (!fs_stream_set_remote_codecs (audio_stream, audio_remote_codecs, &error)) { Tcl_AppendResult (interp, "Could not set the audio remote codecs", (char *) NULL); goto error; } fs_codec_list_destroy (audio_remote_codecs); audio_remote_codecs = NULL; } /* Set video codecs */ if (video_remote_codecs && video_stream) { if (!fs_stream_set_remote_codecs (video_stream, video_remote_codecs, &error)) { Tcl_AppendResult (interp, "Could not set the video remote codecs", (char *) NULL); goto error; } fs_codec_list_destroy (video_remote_codecs); video_remote_codecs = NULL; } return TCL_OK; error: fs_codec_list_destroy (audio_remote_codecs); fs_codec_list_destroy (video_remote_codecs); fs_candidate_list_destroy (audio_remote_candidates); fs_candidate_list_destroy (video_remote_candidates); return TCL_ERROR; } int Farsight_Stop _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { // We verify the arguments if( objc != 1) { Tcl_WrongNumArgs (interp, 1, objv, ""); return TCL_ERROR; } Close (); return TCL_OK; } int Farsight_InUse _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { // We verify the arguments if( objc != 1) { Tcl_WrongNumArgs (interp, 1, objv, ""); return TCL_ERROR; } Tcl_SetObjResult (interp, Tcl_NewBooleanObj (pipeline != NULL)); return TCL_OK; } int Farsight_DumpPipeline _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { // We verify the arguments if( objc != 2) { Tcl_WrongNumArgs (interp, 1, objv, "filename"); return TCL_ERROR; } if (pipeline) GST_DEBUG_BIN_TO_DOT_FILE (pipeline, GST_DEBUG_GRAPH_SHOW_ALL, Tcl_GetString (objv[1])); if (test_pipeline) GST_DEBUG_BIN_TO_DOT_FILE (test_pipeline, GST_DEBUG_GRAPH_SHOW_ALL, Tcl_GetString (objv[1])); return TCL_OK; } static int _SetMute (GstElement *element, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { gboolean mute; // We verify the arguments if( objc != 2) { Tcl_WrongNumArgs (interp, 1, objv, "mute"); return TCL_ERROR; } if (Tcl_GetBooleanFromObj(interp, objv[1], &mute) == TCL_ERROR) { return TCL_ERROR; } if (element) { g_object_set (element, "mute", mute, NULL); } else { Tcl_AppendResult (interp, LIBNAME " isn't running", (char *) NULL); return TCL_ERROR; } return TCL_OK; } int Farsight_SetMuteIn _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { return _SetMute (volumeIn, interp, objc, objv); } int Farsight_SetMuteOut _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { return _SetMute (volumeOut, interp, objc, objv); } static int _GetMute (GstElement *element, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { gboolean mute; // We verify the arguments if( objc != 1) { Tcl_WrongNumArgs (interp, 1, objv, ""); return TCL_ERROR; } if (element) { g_object_get (element, "mute", &mute, NULL); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(mute)); } else { Tcl_AppendResult (interp, LIBNAME " isn't running", (char *) NULL); return TCL_ERROR; } return TCL_OK; } int Farsight_GetMuteIn _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { return _GetMute (volumeIn, interp, objc, objv); } int Farsight_GetMuteOut _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { return _GetMute (volumeOut, interp, objc, objv); } static int _SetVolume (GstElement *element, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { gdouble volume; // We verify the arguments if( objc != 2) { Tcl_WrongNumArgs (interp, 1, objv, "volume"); return TCL_ERROR; } if (Tcl_GetDoubleFromObj(interp, objv[1], &volume) == TCL_ERROR) { return TCL_ERROR; } volume = pow (10, volume / 20); if (element) { g_object_set (element, "volume", volume, NULL); } else { Tcl_AppendResult (interp, LIBNAME " isn't running", (char *) NULL); return TCL_ERROR; } return TCL_OK; } int Farsight_SetVolumeIn _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { return _SetVolume (volumeIn, interp, objc, objv); } int Farsight_SetVolumeOut _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { return _SetVolume (volumeOut, interp, objc, objv); } static int _GetVolume (GstElement *element, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { gdouble volume; // We verify the arguments if( objc != 1) { Tcl_WrongNumArgs (interp, 1, objv, ""); return TCL_ERROR; } if (element) { g_object_get (element, "volume", &volume, NULL); Tcl_SetObjResult(interp, Tcl_NewDoubleObj(volume)); } else { Tcl_AppendResult (interp, LIBNAME " isn't running", (char *) NULL); return TCL_ERROR; } return TCL_OK; } int Farsight_GetVolumeIn _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { return _GetVolume (volumeIn, interp, objc, objv); } int Farsight_GetVolumeOut _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { return _GetVolume (volumeOut, interp, objc, objv); } static gboolean klass_contains (const gchar *klass, const gchar *needle) { gchar *found = strstr (klass, needle); if(!found) return FALSE; if (found != klass && *(found-1) != '/') return FALSE; if (found[strlen (needle)] != 0 && found[strlen (needle)] != '/') return FALSE; return TRUE; } static gboolean is_audio_source (GstElementFactory *factory) { const gchar *klass = gst_element_factory_get_klass (factory); /* we might have some sources that provide a non raw stream */ return (klass_contains (klass, "Audio") && klass_contains (klass, "Source")); } static gboolean is_audio_sink (GstElementFactory *factory) { const gchar *klass = gst_element_factory_get_klass (factory); /* we might have some sinks that provide decoding */ return (klass_contains (klass, "Audio") && klass_contains (klass, "Sink")); } static gboolean is_video_source (GstElementFactory *factory) { const gchar *klass = gst_element_factory_get_klass (factory); /* we might have some sources that provide a non raw stream */ return (klass_contains (klass, "Video") && klass_contains (klass, "Source")); } static gboolean is_video_sink (GstElementFactory *factory) { const gchar *klass = gst_element_factory_get_klass (factory); /* we might have some sinks that provide decoding */ return (klass_contains (klass, "Video") && klass_contains (klass, "Sink")); } /* function used to sort element features */ /* Copy-pasted from decodebin */ static gint compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2) { gint diff; const gchar *rname1, *rname2; diff = gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1); if (diff != 0) return diff; rname1 = gst_plugin_feature_get_name (f1); rname2 = gst_plugin_feature_get_name (f2); diff = strcmp (rname2, rname1); return diff; } static GList * get_plugins_filtered (gboolean source, gboolean audio) { GList *walk, *registry, *result = NULL; GstElementFactory *factory; gchar *klass = NULL; registry = gst_registry_get_feature_list (gst_registry_get_default (), GST_TYPE_ELEMENT_FACTORY); registry = g_list_sort (registry, (GCompareFunc) compare_ranks); for (walk = registry; walk; walk = g_list_next (walk)) { factory = GST_ELEMENT_FACTORY (walk->data); if (audio) { if ((source && is_audio_source (factory)) || (!source && is_audio_sink (factory))) { result = g_list_append (result, factory); gst_object_ref (factory); } } else { if ((source && is_video_source (factory)) || (!source && is_video_sink (factory))) { result = g_list_append (result, factory); gst_object_ref (factory); } } } gst_plugin_feature_list_free (registry); return result; } int Farsight_Probe _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { Tcl_Obj *source = NULL; Tcl_Obj *temp = NULL; Tcl_Obj *type = NULL; Tcl_Obj *devices = NULL; Tcl_Obj *result = NULL; GList *audio_sources, *audio_sinks, *video_sources, *video_sinks, *walk, *list; gint si; result = Tcl_NewListObj (0, NULL); // We verify the arguments if( objc != 1) { Tcl_WrongNumArgs (interp, 1, objv, ""); return TCL_ERROR; } audio_sources = get_plugins_filtered (TRUE, TRUE); audio_sinks = get_plugins_filtered (FALSE, TRUE); video_sources = get_plugins_filtered (TRUE, FALSE); video_sinks = get_plugins_filtered (FALSE, FALSE); for (si = 0; si < 4; si++) { switch (si) { case 0: list = audio_sources; type = Tcl_NewStringObj ("audiosource", -1); break; case 1: list = audio_sinks; type = Tcl_NewStringObj ("audiosink", -1); break; case 2: list = video_sources; type = Tcl_NewStringObj ("videosource", -1); break; case 3: list = video_sinks; type = Tcl_NewStringObj ("videosink", -1); break; default: break; } for (walk = list; walk; walk = g_list_next (walk)) { GstPropertyProbe *probe; GValueArray *arr; GstElement *element; GstElementFactory *factory = GST_ELEMENT_FACTORY(walk->data); element = gst_element_factory_create (factory, NULL); if (element == NULL) continue; source = Tcl_NewListObj (0, NULL); devices = Tcl_NewListObj (0, NULL); Tcl_ListObjAppendElement(NULL, source, type); temp = Tcl_NewStringObj (GST_PLUGIN_FEATURE_NAME(factory), -1); Tcl_ListObjAppendElement(NULL, source, temp); temp = Tcl_NewStringObj (gst_element_factory_get_longname (factory), -1); Tcl_ListObjAppendElement(NULL, source, temp); temp = Tcl_NewStringObj (gst_element_factory_get_description (factory), -1); Tcl_ListObjAppendElement(NULL, source, temp); if (GST_IS_PROPERTY_PROBE (element)) { probe = GST_PROPERTY_PROBE (element); if (probe) { arr = gst_property_probe_probe_and_get_values_name (probe, get_device_property_name(GST_PLUGIN_FEATURE_NAME(factory))); if (arr) { guint i; for (i = 0; i < arr->n_values; ++i) { const gchar *device; GValue *val; val = g_value_array_get_nth (arr, i); if (val == NULL || !G_VALUE_HOLDS_STRING (val)) continue; device = g_value_get_string (val); if (device == NULL) continue; temp = Tcl_NewStringObj (device, -1); Tcl_ListObjAppendElement(NULL, devices, temp); } g_value_array_free (arr); Tcl_ListObjAppendElement(NULL, source, devices); } else { /* no devices found */ _notify_debug ("No devices found for element %s", GST_PLUGIN_FEATURE_NAME(factory)); } } else { _notify_debug ("Unable to cast element %s to GST_PROPERTY_PROBE", GST_PLUGIN_FEATURE_NAME(factory)); } } else { _notify_debug ("Element %s doesn't implement GST_PROPERTY_PROBE", GST_PLUGIN_FEATURE_NAME(factory)); } Tcl_ListObjAppendElement(NULL, result, source); gst_object_unref (element); } for (walk = list; walk; walk = g_list_next (walk)) { if (walk->data) gst_object_unref (GST_ELEMENT_FACTORY (walk->data)); } g_list_free (list); } Tcl_SetObjResult (interp, result); return TCL_OK; } int Farsight_Config _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { static const char *farsightOptions[] = { "-level", "-debug", "-audio-source", "-audio-source-device", "-audio-source-pipeline", "-audio-sink", "-audio-sink-device", "-audio-sink-pipeline", "-video-source", "-video-source-device", "-video-preview-xid", "-video-source-pipeline", "-video-sink", "-video-sink-xid", "-video-sink-pipeline", NULL }; enum farsightOptions { FS_LEVEL, FS_DEBUG, FS_AUDIO_SOURCE, FS_AUDIO_SRC_DEVICE, FS_AUDIO_SRC_PIPELINE, FS_AUDIO_SINK, FS_AUDIO_SINK_DEVICE, FS_AUDIO_SINK_PIPELINE, FS_VIDEO_SOURCE, FS_VIDEO_SRC_DEVICE, FS_VIDEO_PREVIEW_XID, FS_VIDEO_SRC_PIPELINE, FS_VIDEO_SINK, FS_VIDEO_SINK_XID, FS_VIDEO_SINK_PIPELINE }; int optionIndex, a; for (a = 1; a < objc; a++) { if (Tcl_GetIndexFromObj(interp, objv[a], farsightOptions, "option", TCL_EXACT, &optionIndex) != TCL_OK) { return TCL_ERROR; } switch ((enum farsightOptions) optionIndex) { case FS_LEVEL: a++; if (a >= objc) { Tcl_AppendResult(interp, "no argument given for -level option", NULL); return TCL_ERROR; } if (level_callback) { Tcl_DecrRefCount (level_callback); level_callback = NULL; level_callback_interp = NULL; } if (Tcl_GetString (objv[a]) != NULL && Tcl_GetString (objv[a])[0] != 0) { level_callback = objv[a]; Tcl_IncrRefCount (level_callback); level_callback_interp = interp; } break; case FS_DEBUG: a++; if (a >= objc) { Tcl_AppendResult(interp, "no argument given for -debug option", NULL); return TCL_ERROR; } if (debug_callback) { Tcl_DecrRefCount (debug_callback); debug_callback = NULL; debug_callback_interp = NULL; } if (Tcl_GetString (objv[a]) != NULL && Tcl_GetString (objv[a])[0] != 0) { debug_callback = objv[a]; Tcl_IncrRefCount (debug_callback); debug_callback_interp = interp; } break; case FS_AUDIO_SOURCE: a++; if (a >= objc) { Tcl_AppendResult(interp, "no argument given for -audio-source option", NULL); return TCL_ERROR; } if (audio_source) { g_free (audio_source); audio_source = NULL; } if (Tcl_GetString (objv[a]) != NULL && Tcl_GetString (objv[a])[0] != 0) { audio_source = g_strdup (Tcl_GetString(objv[a])); } break; case FS_AUDIO_SRC_DEVICE: { a++; if (a >= objc) { Tcl_AppendResult(interp, "no argument given for -audio-source-device option", NULL); return TCL_ERROR; } if (audio_source_device) { g_free (audio_source_device); audio_source_device = NULL; } if (Tcl_GetString (objv[a]) != NULL && Tcl_GetString (objv[a])[0] != 0) { audio_source_device = g_strdup (Tcl_GetString(objv[a])); } break; } case FS_AUDIO_SRC_PIPELINE: a++; if (a >= objc) { Tcl_AppendResult(interp, "no argument given for -audio-source-pipeline option", NULL); return TCL_ERROR; } if (audio_source_pipeline) { g_free (audio_source_pipeline); audio_source_pipeline = NULL; } if (Tcl_GetString (objv[a]) != NULL && Tcl_GetString (objv[a])[0] != 0) { audio_source_pipeline = g_strdup (Tcl_GetString(objv[a])); } break; case FS_AUDIO_SINK: a++; if (a >= objc) { Tcl_AppendResult(interp, "no argument given for -audio-sink option", NULL); return TCL_ERROR; } if (audio_sink) { g_free (audio_sink); audio_sink = NULL; } if (Tcl_GetString (objv[a]) != NULL && Tcl_GetString (objv[a])[0] != 0) { audio_sink = g_strdup (Tcl_GetString(objv[a])); } break; case FS_AUDIO_SINK_DEVICE: { a++; if (a >= objc) { Tcl_AppendResult(interp, "no argument given for -audio-sink-device option", NULL); return TCL_ERROR; } if (audio_sink_device) { g_free (audio_sink_device); audio_sink_device = NULL; } if (Tcl_GetString (objv[a]) != NULL && Tcl_GetString (objv[a])[0] != 0) { audio_sink_device = g_strdup (Tcl_GetString(objv[a])); } break; } case FS_AUDIO_SINK_PIPELINE: a++; if (a >= objc) { Tcl_AppendResult(interp, "no argument given for -audio-sink-pipeline option", NULL); return TCL_ERROR; } if (audio_sink_pipeline) { g_free (audio_sink_pipeline); audio_sink_pipeline = NULL; } if (Tcl_GetString (objv[a]) != NULL && Tcl_GetString (objv[a])[0] != 0) { audio_sink_pipeline = g_strdup (Tcl_GetString(objv[a])); } break; case FS_VIDEO_SOURCE: a++; if (a >= objc) { Tcl_AppendResult(interp, "no argument given for -video-source option", NULL); return TCL_ERROR; } if (video_source) { g_free (video_source); video_source = NULL; } if (Tcl_GetString (objv[a]) != NULL && Tcl_GetString (objv[a])[0] != 0) { video_source = g_strdup (Tcl_GetString(objv[a])); } break; case FS_VIDEO_SRC_DEVICE: { a++; if (a >= objc) { Tcl_AppendResult(interp, "no argument given for -video-source-device option", NULL); return TCL_ERROR; } if (video_source_device) { g_free (video_source_device); video_source_device = NULL; } if (Tcl_GetString (objv[a]) != NULL && Tcl_GetString (objv[a])[0] != 0) { video_source_device = g_strdup (Tcl_GetString(objv[a])); } break; } case FS_VIDEO_PREVIEW_XID: { a++; if (a >= objc) { Tcl_AppendResult(interp, "no argument given for -video-preview-xid option", NULL); return TCL_ERROR; } if (Tcl_GetLongFromObj (interp, objv[a], &video_preview_xid) != TCL_OK) { return TCL_ERROR; } break; } case FS_VIDEO_SRC_PIPELINE: a++; if (a >= objc) { Tcl_AppendResult(interp, "no argument given for -video-source-pipeline option", NULL); return TCL_ERROR; } if (video_source_pipeline) { g_free (video_source_pipeline); video_source_pipeline = NULL; } if (Tcl_GetString (objv[a]) != NULL && Tcl_GetString (objv[a])[0] != 0) { video_source_pipeline = g_strdup (Tcl_GetString(objv[a])); } break; case FS_VIDEO_SINK: a++; if (a >= objc) { Tcl_AppendResult(interp, "no argument given for -video-sink option", NULL); return TCL_ERROR; } if (video_sink) { g_free (video_sink); video_sink = NULL; } if (Tcl_GetString (objv[a]) != NULL && Tcl_GetString (objv[a])[0] != 0) { video_sink = g_strdup (Tcl_GetString(objv[a])); } break; case FS_VIDEO_SINK_XID: { a++; if (a >= objc) { Tcl_AppendResult(interp, "no argument given for -video-sink-xid option", NULL); return TCL_ERROR; } if (Tcl_GetLongFromObj (interp, objv[a], &video_sink_xid) != TCL_OK) { return TCL_ERROR; } break; } case FS_VIDEO_SINK_PIPELINE: a++; if (a >= objc) { Tcl_AppendResult(interp, "no argument given for -video-sink-pipeline option", NULL); return TCL_ERROR; } if (video_sink_pipeline) { g_free (video_sink_pipeline); video_sink_pipeline = NULL; } if (Tcl_GetString (objv[a]) != NULL && Tcl_GetString (objv[a])[0] != 0) { video_sink_pipeline = g_strdup (Tcl_GetString(objv[a])); } break; default: Tcl_AppendResult(interp, "bad option to ::Farsight::Config", NULL); return TCL_ERROR; break; } } return TCL_OK; } /* Function : Farsight_Init Description : The Init function that will be called when the extension is loaded to your tcl shell */ int Farsight_Init (Tcl_Interp *interp) { #ifdef G_OS_WIN32 WSADATA w; #endif //Check Tcl version is 8.4 or higher if (Tcl_InitStubs(interp, "8.4", 0) == NULL) { return TCL_ERROR; } #if defined(__APPLE__) || defined(__BSD__) || defined(__FreeBSD__) || defined(__NetBSD__) gst_registry_fork_set_enabled((gboolean)FALSE); #endif gst_init (NULL, NULL); #ifdef G_OS_WIN32 WSAStartup(0x0202, &w); #endif // Create the wrapping commands in the Farsight namespace Tcl_CreateObjCommand(interp, "::Farsight::Prepare", Farsight_Prepare, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Farsight::Start", Farsight_Start, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Farsight::Stop", Farsight_Stop, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Farsight::InUse", Farsight_InUse, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Farsight::Probe", Farsight_Probe, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Farsight::SetVolumeIn", Farsight_SetVolumeIn, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Farsight::GetVolumeIn", Farsight_GetVolumeIn, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Farsight::SetVolumeOut", Farsight_SetVolumeOut, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Farsight::GetVolumeOut", Farsight_GetVolumeOut, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Farsight::SetMuteIn", Farsight_SetMuteIn, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Farsight::GetMuteIn", Farsight_GetMuteIn, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Farsight::SetMuteOut", Farsight_SetMuteOut, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Farsight::GetMuteOut", Farsight_GetMuteOut, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Farsight::Config", Farsight_Config, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Farsight::TestAudio", Farsight_TestAudio, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Farsight::TestVideo", Farsight_TestVideo, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Farsight::DumpPipeline", Farsight_DumpPipeline, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); // end of Initialisation return TCL_OK; } int Farsight_SafeInit (Tcl_Interp *interp) { return Farsight_Init(interp); } int Tcl_farsight_Init (Tcl_Interp *interp) { return Farsight_Init(interp); } int Tcl_farsight_SafeInit (Tcl_Interp *interp) { return Farsight_Init(interp); } int Farsight_Unload (Tcl_Interp *interp) { Close(); return TCL_OK; } int Farsight_SafeUnload (Tcl_Interp *interp) { return Farsight_Unload(interp); } int Tcl_farsight_SafeUnload (Tcl_Interp *interp) { return Farsight_SafeUnload(interp); } int Tcl_farsight_Unload (Tcl_Interp *interp) { return Farsight_Unload(interp); } amsn-0.98.9/utils/farsight/src/Rules.mk0000644000175000017500000000061511755433160017561 0ustar billiobbilliobOBJS-tcl_farsight := $(tcl_farsight_dir)/src/tcl_farsight.o TARGETS-tcl_farsight := $(tcl_farsight_dir)/src/tcl_farsight.$(SHLIB_EXTENSION) $(OBJS-tcl_farsight): CFLAGS += ${FARSIGHT2_CFLAGS} $(TARGETS-tcl_farsight): LDFLAGS += ${FARSIGHT2_LIBS} all:: $(TARGETS-tcl_farsight) clean:: clean-tcl_farsight clean-tcl_farsight:: rm -f $(TARGETS-tcl_farsight) $(OBJS-tcl_farsight) amsn-0.98.9/utils/farsight/src/tcl_farsight.h0000644000175000017500000000411311236675310020754 0ustar billiobbilliob/* File : tcl_farsight.h Description : Header file for the tcl_farsight extension for tcl. Author : Youness El Alaoui ( KaKaRoTo - kakaroto@user.sourceforge.net) */ #ifndef _TCL_FARSIGHT #define _TCL_FARSIGHT // Include files, must include windows.h before tk.h and tcl.h before tk.h or else compiling errors #include #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include #endif #include // Defined as described in tcl.tk compiling extension help #ifndef STATIC_BUILD #if defined(_MSC_VER) # define EXPORT(a,b) __declspec(dllexport) a b # define DllEntryPoint DllMain #else # if defined(__BORLANDC__) # define EXPORT(a,b) a _export b # else # define EXPORT(a,b) a b # endif #endif #endif #define DLL_BUILD #define BUILD_TCL_FARSIGHT #ifdef BUILD_TCL_FARSIGHT # undef TCL_STORAGE_CLASS # define TCL_STORAGE_CLASS DLLEXPORT #endif #ifdef __cplusplus extern "C" #endif // External functions EXTERN int Tcl_farsight_Init _ANSI_ARGS_((Tcl_Interp *interp)); EXTERN int Tcl_farsight_SafeInit _ANSI_ARGS_((Tcl_Interp *interp)); EXTERN int Farsight_Init _ANSI_ARGS_((Tcl_Interp *interp)); EXTERN int Farsight_SafeInit _ANSI_ARGS_((Tcl_Interp *interp)); EXTERN int Farsight_Prepare _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Farsight_Start _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Farsight_InUse _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Farsight_Stop _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Farsight_Probe _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); #ifdef __APPLE__ #include @interface FarsightAppDelegate : NSObject - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender; @end #endif # undef TCL_STORAGE_CLASS # define TCL_STORAGE_CLASS DLLIMPORT #endif /* _TCL_FARSIGHT */ amsn-0.98.9/utils/farsight/Rules.mk0000644000175000017500000000076411755433160016777 0ustar billiobbilliobOBJS-farsight := $(tcl_farsight_dir)/src/tcl_farsight.$(SHLIB_EXTENSION) TARGETS-farsight := $(tcl_farsight_dir)/tcl_farsight.$(SHLIB_EXTENSION) ifeq (${HAVE_FARSTREAM},yes) $(OBJS-farsight): CFLAGS+=-DHAVE_FARSTREAM else ifeq (${HAVE_FARSIGHT},yes) $(OBJS-farsight): CFLAGS+=-DHAVE_FARSIGHT endif endif $(TARGETS-farsight): $(OBJS-farsight) cp $< $@ all:: $(TARGETS-farsight) clean:: clean-farsight clean-farsight:: rm -f $(TARGETS-farsight) $(OBJS-farsight) amsn-0.98.9/utils/drawboard/0000755000175000017500000000000011757711633015511 5ustar billiobbilliobamsn-0.98.9/utils/drawboard/pkgIndex.tcl0000644000175000017500000000012310356234135017751 0ustar billiobbilliobpackage ifneeded drawboard 0.2 \ [list source [file join $dir drawboard.tcl]] amsn-0.98.9/utils/drawboard/grid.png0000644000175000017500000000031210433151545017126 0ustar billiobbilliobPNG  IHDR;0bKGDC pHYs  tIME  71LQtEXtCommentCreated with The GIMPd%n.IDATH CĈ;KbX,bTm+2_IENDB`amsn-0.98.9/utils/drawboard/drawboard.tcl0000644000175000017500000003162611472317214020161 0ustar billiobbilliob##Drawboard widget by Karel Demeyer # # NAME # # drawboard - Create and manipulate drawboard widgets # # SYNOPSIS # # drawboard pathName ?options? # # STANDARD OPTIONS # # ... # # WIDGET-SPECIFIC OPTIONS # # -grid, grid, Grid # -drawmode, drawmode, Drawmode # -color, color, Color # -pencil, pencil, Pencil # -width, width, Width # -height, height, Height # # WIDGET COMMAND # # pathName cget option # pathName configure ?option? ?value option value ...? #TODO: # -gridimg option # provide 1 default pencil and 1 default gridimg # Improved Saving # Loading # fixed dimensions (-width / -height doesn't work yet properly) # remove amsn plus button # review cutting .. it has bugs package require snit package provide drawboard 0.2 snit::widgetadaptor drawboard { option -grid -default 1 -configuremethod SetConfig option -drawmode -default free option -color -default black -configuremethod SetConfig option -pencil -default pencil1 -configuremethod SetConfig option -width -default 100 option -height -default 100 #option -gridimg variable buttondown variable oldx variable oldy variable endx variable endy variable gridsourceimg variable strokes_list variable curStroke variable curDrawingAttributes variable drawAttrs_list constructor { args } { installhull using canvas -bg white -relief flat -highlightthickness 0 -width $options(-width) -height $options(-height) status_log "creating drawboard widget $self" $self configurelist $args #if {$options(-gridimg) == ""} { # set gridsourceimg [$self LoadImage drawboardgrid grid.png] #} else { # set gridsourceimg $options(-gridimg) #} set gridsourceimg [::skin::loadPixmap grid] #give the grid a color ::picture::Colorize $gridsourceimg blue #create the image where we will copy the grid on (tiled) image create photo grid$self #put the grid-image (initially empty) on the canvas $hull create image 0 0 -anchor nw -image grid$self -tag grid #create the initial drawboard img set drawboard [image create photo] ;# -width $width -height $height] #put the drawboard-img on the canvas $hull create image 0 0 -anchor nw -image $drawboard -tag drawboard #make it possible to disable coloring of pencils, for "stamps" (like using smileys as pencil) $self SetConfig coloring 1 $self UpdatePencil set endx 0 set endy 0 set strokes_list [list] set curDrawingAttributes [list 7 $options(-color)] set drawAttrs_list [list] #bindings bind $self "$self ButtonDown" bind $self "$self MouseMove" bind $self "$self ButtonRelease" bind $self "$self Configure" $self configurelist $args } method LoadImage {imagename filename} { return [image create photo $imagename -file $filename.gif] } ############################################### # When mousebutton pressed # ############################################### method ButtonDown {} { set drawboard [$hull itemcget drawboard -image] #change the buttondown-flag set buttondown 1 #set initial coordinates of the mouse on the drawboard set oldx [expr {[winfo pointerx $self] - [winfo rootx $self]}] set oldy [expr {[winfo pointery $self] - [winfo rooty $self]}] set curStroke [list $oldx $oldy] $self DrawDot $oldx $oldy $self SetEnds $oldx $oldy } ############################################### # When mousebutton is released # ############################################### method ButtonRelease {} { if { $options(-drawmode) == "line"} { set drawboard [$hull itemcget drawboard -image] set newx [expr {[winfo pointerx $self] - [winfo rootx $self]}] set newy [expr {[winfo pointery $self] - [winfo rooty $self]}] $self DrawLine $oldx $oldy $newx $newy $self SetEnds $newx $newy lappend curStroke $newx $newy } lappend strokes_list $curStroke lappend drawAttrs_list $curDrawingAttributes #change the buttondown-flag set buttondown 0 unset oldx oldy } ############################################### # When the mouse is moved # ############################################### method MouseMove {} { if { $options(-drawmode) == "free" } { #If we're dragging, draw if {$buttondown} { #Get the names of the items set drawboard [$hull itemcget drawboard -image] #find the coordinates of the mouse on the selfas (drawboard) set posx [expr {[winfo pointerx $self] - [winfo rootx $self]}] set posy [expr {[winfo pointery $self] - [winfo rooty $self]}] #if the coords made a jump, draw a line between 'm, otherwise just draw a dot if {[expr abs($oldx - $posx)] > 2 || [expr abs($oldy - $posy)] > 2} { $self DrawLine $oldx $oldy $posx $posy } else { $self DrawDot $posx $posy } #remember where we were set oldx $posx set oldy $posy lappend curStroke $oldx $oldy $self SetEnds $posx $posy } } } ############################################### # Draws a dot with the pencil on given coords # ############################################### method DrawDot { x y } { set drawboard [$hull itemcget drawboard -image] set x [expr {$x - [image width pencil_$self]/2}] set y [expr {$y - [image height pencil_$self]/2}] #only draw if on the drawboard if {$x > 0 && $y > 0 && $x < [$drawboard cget width] && $y < [$drawboard cget height]} { $drawboard copy pencil_$self -to $x $y } } ############################################### # Draws a line between 2 given coord-pairs # # with the pencil # ############################################### method DrawLine { x1 y1 x2 y2 } { set drawboard [$hull itemcget drawboard -image] set xsize [$drawboard cget width] set ysize [$drawboard cget heigth] #if we end off the board, end on the edge if {$x2 < 0} { set x2 0} if {$y2 < 0} { set y2 0} if { $x2 > $xsize } { set x2 $xsize } if { $y2 > $ysize } { set y2 $ysize } #calculate the x and y distance set xdist [expr {($x1 - $x2)*1.0}] set ydist [expr {($y1 - $y2)*1.0}] #also get there absolute values set absxdist [expr {abs($xdist)}] set absydist [expr {abs($ydist)}] #calculate the x and y diffs if {$absxdist > $absydist} { set absdist $absxdist } else { set absdist $absydist } if {$absdist == 0} { set xdiff 0 set ydiff 0 } else { set xdiff [expr {$xdist / $absdist}] set ydiff [expr {$ydist / $absdist}] } set steps $absdist #draw the line for {set idx 0} { $idx < $steps } {incr idx } { set x1 [expr {$x1 - $xdiff}] set y1 [expr {$y1 - $ydiff}] $self DrawDot [expr int($x1)] [expr int($y1)] } } method Configure {} { #get the new dimensions set width [winfo width $self] set height [winfo height $self] if { $height < $endy } { set endy $height } if { $width < $endx } { set endx $width } set drawboard [$hull itemcget drawboard -image] $drawboard configure -width $width -height $height $self UpdateGrid } method UpdateGrid { } { if { $options(-grid) == 1 } { set width [winfo width $self] set height [winfo height $self] grid$self copy $gridsourceimg -to 0 0 $width $height -shrink } else { catch {grid$self blank} } } method SetEnds {x y} { set farx [expr $x + [image width pencil_$self]] set fary [expr $y + [image height pencil_$self]] if { $farx > $endx } { set endx $farx } if { $fary > $endy } { set endy $fary } } method ClearDrawboard {} { [$hull itemcget drawboard -image] blank set endx 0 set endy 0 set strokes_list [list] set curStroke_x [list] set curStroke_y [list] set curDrawingAttributes [list 7 $options(-color)] set drawAttrs_list [list] } #TODO: method LoadDrawing { filename } { #$self ClearDrawboard #draw loaded image set drawboard [$hull itemcget drawboard -image] set loadedimg [image create photo -file $filename] $drawboard copy $loadedimg $self SetEnds [image width $loadedimg] [image height $loadedimg] $self Configure } method SaveDrawing {filename {gifFortified 0}} { set drawboard [$hull itemcget drawboard -image] #to make sure the ends are not to far and all is right set boardh [image height $drawboard] set boardw [image width $drawboard] if {$boardh < $endy} { set endy $boardh } if {$boardw < $endx} { set endx $boardw } #only save to the most far used coordinates image create photo temp temp copy $drawboard -from 0 0 $endx $endy image create photo $drawboard $drawboard copy temp #put the drawboard on a white background image create photo copytosend ;# -width [image width $drawboard] -height [image height $drawboard] #fix the "cannot save empty file" bug if { $endx == 0 || $endy == 0 } { copytosend put {#ffffff} -to 1 1 [image width $drawboard] [image height $drawboard] } else { copytosend put {#ffffff} -to 0 0 [image width $drawboard] [image height $drawboard] } copytosend copy $drawboard set endx 0 set endy 0 ::picture::Save copytosend $filename cxgif # Fortify the GIF with the strokes_list if {$gifFortified} { if {![catch {package require tclISF 0.3}]} { if {[catch {[tclISF save $filename $strokes_list $drawAttrs_list]} err]} { status_log "\[SaveDrawing\] saving to file $filename. Got Error: $err" red status_log "$strokes_list" red status_log "$drawAttrs_list" red } } else { if {![catch {package require -exact tclISF 0.2}]} { if {[catch {[tclISF_save $filename $strokes_list $drawAttrs_list]} err]} { status_log "\[SaveDrawing\] saving to file $filename. Got Error: $err" red status_log "$strokes_list" red status_log "$drawAttrs_list" red } } } } image delete copytosend image delete temp } method ToggleGrid {} { if { $options(-grid) == 1} { $self SetConfig -grid 0 } else { $self SetConfig -grid 1 } } method SetConfig {option value} { set options($option) $value #actions after change of options #the space was added so the option isn't passed to the switch command switch " $option" { " -grid" { $self UpdateGrid } " -pencil" { $self UpdatePencil } " -color" { $self UpdatePencil } } } method UpdatePencil { } { set pencilname $options(-pencil) #if the pencil img already exists, delete it first before we (re)make it catch { image delete pencil_$self } set pencilimg [::skin::loadPixmap $pencilname] #get the dimensions for the pencil-image set width [image width $pencilimg] set height [image height $pencilimg] #create the pencil image image create photo pencil_$self -width $width -height $height #copy the source-img on the new (still empty) pencil image pencil_$self copy $pencilimg #color the pencil ::picture::Colorize pencil_$self $options(-color) #fill the drawing attributes if {[string first "pencil_" $pencilname] == 0} { set width [string range $pencilname 7 end] } set curDrawingAttributes [list $width $options(-color)] } } amsn-0.98.9/utils/contentmanager/0000755000175000017500000000000011757711633016551 5ustar billiobbilliobamsn-0.98.9/utils/contentmanager/pkgIndex.tcl0000644000175000017500000000013510364215620021011 0ustar billiobbilliobpackage ifneeded contentmanager 0.1 \ [list source [file join $dir contentmanager.tcl]] amsn-0.98.9/utils/contentmanager/contentmanager.tcl0000644000175000017500000005450210406336725022263 0ustar billiobbilliobpackage provide contentmanager 0.1 package require snit package require scalable-bg package require contentmanager # o-------------------------------------------------------------------------------+ # Name: contentmanager | # Description: Manager type | # Function: Provide an easy-to-use API to groups and elements | # o-------------------------------------------------------------------------------+ snit::type contentmanager { pragma -hasinstances no pragma -hastypeinfo no pragma -hastypedestroy no # ------------------------------------------------------------------------------- # Methods to create, destroy, configure and use groups and elements # ------------------------------------------------------------------------------- typemethod getpath { args } { set path {} foreach name $args { # strings beginning with - are options, end getting path if { [string equal [string index $name 0] "-"] } { break } if { [string equal $path {}] } { set path $name } else { set path $path.$name } } return $path } typemethod gettree { args } { set tree {} foreach name $args { if { [string equal [string index $name 0] "-"] } { break } else { lappend tree $name } } return $tree } typemethod getopts { args } { set opts {} foreach opt $args { if { [string equal [string index $opt 0] "-"] } { set val [lindex $args [expr {[lsearch $args $opt] + 1}]] lappend opts $opt $val continue } else { continue } } return $opts } typemethod add { _type args } { set path [eval $type getpath $args] set opts [eval $type getopts $args] set tree [eval $type gettree $args] # Check item doesn't already exist if { [info command $path] != {} } { error "$_type '$path' already exists" return {} } switch $_type { group { eval group $path -tree [list $tree] $opts # If this isn't a toplevel group... if { [llength $tree] > 1 } { # ...set it's state to its parent's state and register with its parent set parent [eval $type getpath [lrange $tree 0 end-1]] $path configure -state [$parent cget -state] set id [lindex $tree end] $parent register $id } else { set id $tree } } element { eval element $path -tree [list $tree] $opts # If this isn't a toplevel element... if { [llength $tree] > 1 } { # ...set it's state to its parent's state and register with its parent set parent [eval $type getpath [lrange $tree 0 end-1]] $path configure -state [$parent cget -state] set id [lindex $tree end] $parent register $id } else { set id $tree } } attachment { eval element $path -tree [list $tree] $opts # Set it's state to its parent's state and attach it to its parent set parent [eval $type getpath [lrange $tree 0 end-1]] $path configure -state [$parent cget -state] set id [lindex $tree end] $parent attach $id } default { error "unknown item type '${_type}'" } } return $id } typemethod insert { index _type args } { # Check index is okay if { ![string is integer $index] && $index != "end" } { error "invalid insert index '$index'" } set path [eval $type getpath $args] set opts [eval $type getopts $args] set tree [eval $type gettree $args] # Check item doesn't already exist if { [info command $path] != {} } { error "$_type '$path' already exists" return {} } if { [string equal $_type "group"] } { set parent [eval $type getpath [lrange $tree 0 end-1]] eval group $path -tree [list $tree] $opts # If this isn't a toplevel group... if { [llength $tree] > 1 } { # ...set it's state to its parent's state and register with its parent set parent [eval $type getpath [lrange $tree 0 end-1]] $path configure -state [$parent cget -state] set id [lindex $tree end] $parent register $id $index } else { set id $tree } } elseif { [string equal $_type "element"] } { eval element $path -tree [list $tree] $opts # If this isn't a toplevel element... if { [llength $tree] > 1 } { # ...set it's state to its parent's state and register with its parent set parent [eval $type getpath [lrange $tree 0 end-1]] $path configure -state [$parent cget -state] set id [lindex $tree end] $parent register $id $index } else { set id $tree } } return $id } typemethod delete { args } { set path [eval $type getpath $args] set tree [eval $type gettree $args] $path destroy } typemethod configure { args } { set path [eval $type getpath $args] set opts [eval $type getopts $args] $path configurelist $opts } typemethod cget { args } { set tree [lrange $args 0 end-1] set opt [lindex $args end] set path [eval $type getpath $tree] return [$path cget $opt] } typemethod children { args } { set path [eval $type getpath $args] return [$path children] } typemethod coords { args } { set tree [lrange $args 0 end-2] set coords [lrange $args end-1 end] foreach ord $coords { if { ![string is integer $ord] } { error "cant user non-numeric '$ord' value as ordinate" } } set path [eval $type getpath $tree] eval $path coords $coords } typemethod getcoords { args } { set path [eval $type getpath $args] return [eval $path coords] } typemethod width { args } { set path [eval $type getpath $args] return [eval $path cget -width] } typemethod height { args } { set path [eval $type getpath $args] return [eval $path cget -height] } typemethod move { args } { set tree [lrange $args 0 end-2] set vector [lrange $args end-1 end] set path [eval $type getpath $tree] eval $path move $vector } typemethod bind { args } { set tree [lrange $args 0 end-2] set path [eval $type getpath $tree] set pattern [lindex $args end-1] set command [lindex $args end] eval $path bind $pattern [list $command] } typemethod show { args } { set path [eval $type getpath $args] set opts [eval $type getopts $args] eval $path show $opts } typemethod hide { args } { set path [eval $type getpath $args] set opts [eval $type getopts $args] eval $path hide $opts } typemethod toggle { args } { set path [eval $type getpath $args] eval $path toggle } typemethod sort { args } { set lvlopt [lsearch $args -level] if { $lvlopt == -1 } { set level r } else { set level [lindex $args [expr {$lvlopt + 1}]] } set path [eval $type getpath $args] eval $path sort $level } typemethod type { args } { set path [eval $type getpath $args] return [eval $path type] } typemethod register { args } { set tree [eval $type gettree $args] set path [eval $type getpath [lrange $args 0 end-1]] set id [lindex $tree end] $path register $id } typemethod unregister { args } { set tree [eval $type gettree $args] set path [eval $type getpath [lrange $args 0 end-1]] set id [lindex $tree end] $path unregister $id } } snit::type group { # Parent options option -widget -configuremethod SetWidget option -parent option -id option -tree # Dimension options option -align -default left option -orient -default vertical option -height -default 0 -configuremethod SetHeight option -valign -default top option -width -default 0 -configuremethod SetWidth # Padding options option -padx -default 0 option -pady -default 0 option -ipadx -default 0 option -ipady -default 0 # State options option -omnipresent -default no option -state -default normal -configuremethod SetState # Position variables variable xPos variable yPos # Children variables variable items variable hiddenitems variable bboxid # Attachment variables variable attachments # Afterid variables variable afterid # Binding variables variable havebinding constructor { args } { set xPos 0 set yPos 0 set items {} set bboxid {} set attachments {} array set afterid {sort {}} set havebinding 0 $self configurelist $args } destructor { catch { foreach item $items { set tree $options(-tree) lappend tree $item eval contentmanager delete $tree } } catch { $options(-widget) delete $bboxid } catch { eval contentmanager unregister $options(-tree) } } method type { } { return "group" } method SetWidget { opt val } { set options(-widget) $val set bboxid [$val create rect 0 0 0 0 -fill "" -outline "" -state hidden] } method SetWidth { opt val } { set options(-width) $val if { ![string equal $bboxid ""] } { $options(-widget) coords $bboxid $xPos $yPos [expr {$xPos + $val}] [expr {$yPos + $options(-height)}] } } method SetHeight { opt val } { set options(-height) $val if { [$self GotWidget] } { $options(-widget) coords $bboxid $xPos $yPos [expr {$xPos + $options(-width)}] [expr {$yPos + $val}] } } method SetState { opt val } { set options(-state) $val switch $val { "partlyhidden" { $self hide } "hidden" { $self hide } "normal" { $self show } } } method GotWidget { } { if { ![string equal $bboxid ""] } { return 1 } else { return 0 } } method register { id {idx ""} } { if { [string equal $idx ""] } { lappend items $id } else { set items [linsert $items $idx $id] } } method unregister { id } { set idx [lsearch $items $id] set list1 [lrange $items 0 [expr {$idx - 1}]] set list2 [lrange $items [expr {$idx + 1}] end] set items [concat $list1 $list2] } method children { } { return $items } method attach { id } { lappend attachments $id } method bind { pat cmd {mode "bbox"} } { if { [string equal $cmd {}] } { set havebinding 0 $options(-widget) itemconfigure $bboxid -state hidden } else { set havebinding 1 if { $mode == "bbox" } { $options(-widget) itemconfigure $bboxid -state normal } } switch $mode { "bbox" { $options(-widget) bind $bboxid $pat $cmd } "components" { foreach item $items { set tree $options(-tree) lappend tree $item eval contentmanager bind $tree $pat [list $cmd] } } } } method coords { {x {}} {y {}} } { if { [string equal $x {}] } { return "$xPos $yPos" } elseif { $x == $xPos && $y == $yPos } { return } set dx [expr {$x - $xPos}] set dy [expr {$y - $yPos}] $self move $dx $dy } method move { dx {dy {}} } { if { $dx == 0 } { if { $dy == 0 || [string equal $dy {}] } { return } } incr xPos $dx if { [string equal $dy {}] } { foreach item $items { set tree $options(-tree) lappend tree $item eval contentmanager move $tree $dx } if { [$self GotWidget] } { $options(-widget) move $bboxid $dx } } else { incr yPos $dy foreach item $items { set tree $options(-tree) lappend tree $item eval contentmanager move $tree $dx $dy } if { [$self GotWidget] } { $options(-widget) move $bboxid $dx $dy } } $self PlaceAttachments } method show { args } { if { [string equal $args {}] } { set level r } else { set level [lindex $args 1] } foreach item $items { set tree $options(-tree) lappend tree $item if { [eval contentmanager cget $tree -omnipresent] } { continue } if { [string is integer $level] && $level > 0 } { eval contentmanager show $tree -level [expr {$level - 1}] } elseif { $level == "r" } { eval contentmanager show $tree } } foreach attachment $attachments { if { [eval contentmanager cget $tree -omnipresent] } { continue } else { set tree $options(-tree) lappend tree $attachment eval contentmanager show $tree } } set options(-state) normal if { $havebinding } { $options(-widget) itemconfigure $bboxid -state normal } } method hide { args } { if { [string equal $args {}] } { set force 0 } else { set force [lindex $args 1] } set omnipresent 0 foreach item $items { set tree $options(-tree) lappend tree $item if { [eval contentmanager cget $tree -omnipresent] && !$force } { set omnipresent 1 continue } eval contentmanager hide $tree } foreach attachment $attachments { if { [eval contentmanager cget $tree -omnipresent] } { continue } else { set tree $options(-tree) lappend tree $attachment eval contentmanager hide $tree } } if { $omnipresent && !$force } { set options(-state) "partlyhidden" } else { set options(-state) "hidden" } $options(-widget) itemconfigure $bboxid -state hidden } method toggle { } { switch $options(-state) { "normal" { $self hide } "hidden" { $self show } "partlyhidden" { $self show } } } method sort { {level r} } { # Initial coords set x [expr {$xPos + $options(-ipadx)}] set y [expr {$yPos + $options(-ipady)}] set width 0 set height 0 # Which way are we sorting (horizontally or vertically) switch $options(-orient) { "horizontal" { set itempady 0 foreach item $items { set tree $options(-tree) lappend tree $item # If the item is hidden, skip it if { [string equal [eval contentmanager cget $tree -state] "hidden"] } { continue } # Sort the item if { [string is integer $level] && $level > 0 } { eval contentmanager sort $tree -level [expr {$level - 1}] } elseif { [string equal $level r] } { eval contentmanager sort $tree -level r } set itempadx [eval contentmanager cget $tree -padx] set itempady [eval contentmanager cget $tree -pady] set itemwidth [eval contentmanager width $tree] set itemheight [eval contentmanager height $tree] incr x $itempadx incr y $itempady eval contentmanager coords $tree $x $y incr x $itempadx incr y -$itempady incr x $itemwidth # Is this the tallest item so far? if { $itemheight > $height } { set height $itemheight } } set width [expr {$x - $xPos + $options(-ipadx)}] incr height [expr {(2 * $options(-ipady)) + $itempady}] $self configure -height $height $self configure -width $width # Align the items with each other $self AlignItems } "vertical" { set itempadx 0 foreach item $items { set tree $options(-tree) lappend tree $item # If the item is hidden, skip it if { [string equal [eval contentmanager cget $tree -state] "hidden"] } { continue } if { [string is integer $level] && $level > 0 } { eval contentmanager sort $tree -level [expr {$level - 1}] } elseif { [string equal $level r] } { eval contentmanager sort $tree -level r } set itempadx [eval contentmanager cget $tree -padx] set itempady [eval contentmanager cget $tree -pady] set itemwidth [eval contentmanager width $tree] set itemheight [eval contentmanager height $tree] incr x $itempadx incr y $itempady eval contentmanager coords $tree $x $y incr x -$itempadx incr y $itempady incr y $itemheight # Is this the widest item so far? if { $itemwidth > $width } { set width $itemwidth } } set height [expr {$y - $yPos + $options(-ipady)}] incr width [expr {(2 * $options(-ipadx)) + $itempadx}] $self configure -width $width $self configure -height $height # Align the elements with each other $self AlignItems } } $options(-widget) raise $bboxid } method AlignItems { } { set width $options(-width) set height $options(-height) switch $options(-orient) { "horizontal" { foreach item $items { set tree $options(-tree) lappend tree $item set valign [eval contentmanager cget $tree -valign] set h [eval contentmanager cget $tree -height] set pady [eval contentmanager cget $tree -pady] switch $valign { "center" { eval contentmanager move $tree 0 [expr {($height / 2) - ($h / 2) - $options(-ipady) - $pady}] } "middle" { eval contentmanager move $tree 0 [expr {($height / 2) - ($h / 2) - $options(-ipady) - $pady}] } "bottom" { eval contentmanager move $tree 0 [expr {$height - $h - $options(-ipady) - $pady}] } } } } "vertical" { foreach item $items { set tree $options(-tree) lappend tree $item set align [eval contentmanager cget $tree -align] set w [eval contentmanager cget $tree -width] set padx [eval contentmanager cget $tree -padx] switch $align { "center" { eval contentmanager move $tree [expr {($width / 2) - ($w / 2) - $options(-ipadx) - $padx}] 0 } "middle" { eval contentmanager move $tree [expr {($width / 2) - ($w / 2) - $options(-ipadx) - $padx}] 0 } "right" { eval contentmanager move $tree [expr {$width - $w - $options(-ipadx) - $padx}] 0 } } } } } } method PlaceAttachments { } { foreach attachment $attachments { set tree $options(-tree) lappend tree $attachment set attx [expr {$xPos + [eval contentmanager cget $tree -padx]}] set atty [expr {$yPos + [eval contentmanager cget $tree -pady]}] eval contentmanager coords $tree $attx $atty } } } snit::type element { # Parent options option -widget -configuremethod SetWidget option -tag -configuremethod SetTag option -tree # Dimension options option -align -default left option -height -default 0 -configuremethod SetHeight -cgetmethod GetHeight option -valign -default top option -width -default 0 -configuremethod SetWidth -cgetmethod GetWidth # Padding options option -padx -default 0 option -pady -default 0 option -ipadx -default 0 -configuremethod Sort option -ipady -default 0 -configuremethod Sort # State options option -omnipresent -default no option -state -default normal -configuremethod SetState # Children variables variable bboxid # Attachment variables variable attachments # Binding variables variable havebinding variable xPos variable yPos constructor { args } { set xPos 0 set yPos 0 set bboxid {} set attachments {} set havebinding 0 $self configurelist $args } destructor { catch { $options(-widget) delete $bboxid eval contentmanager unregister $options(-tree) } } method type { } { return "element" } method attach { id } { lappend attachments $id } method SetWidget { opt val } { set options(-widget) $val set bboxid [$val create rect 0 0 0 0 -fill "" -outline "" -state normal] } method SetWidth { opt val } { set options(-width) $val if { [$self GotWidget] } { $options(-widget) coords $bboxid $xPos $yPos [expr {$xPos + $val}] [expr {$yPos + $options(-height)}] } } method GetWidth { opt } { if { [string equal $options(-state) "hidden"] } { return 0 } else { return $options(-width) } } method SetHeight { opt val } { set options(-height) $val if { [$self GotWidget] } { $options(-widget) coords $bboxid $xPos $yPos [expr {$xPos + $options(-width)}] [expr {$yPos + $val}] } } method SetState { opt val } { set options(-state) $val switch $val { "partlyhidden" { $self hide } "hidden" { $self hide } "normal" { $self show } } } method GetHeight { opt } { if { [string equal $options(-state) "hidden"] } { return 0 } else { return $options(-height) } } method GotWidget { } { if { [string equal $options(-widget) ""] } { return 0 } else { return 1 } } method bind { pat cmd {mode {bbox}} } { if { [string equal $cmd {}] } { set havebinding 0 } else { set havebinding 1 } if { [$self GotWidget] } { $options(-widget) bind $options(-tag) $pat $cmd $options(-widget) bind $bboxid $pat $cmd $options(-widget) itemconfigure $bboxid -state normal } } method coords { {x {}} {y {}} } { if { [string equal $x {}] } { return "$xPos $yPos" } set xPos $x set yPos $y set tagx [expr {$x + $options(-ipadx)}] set tagy [expr {$y + $options(-ipady)}] $options(-widget) coords $options(-tag) $tagx $tagy $options(-widget) coords $bboxid $xPos $yPos [expr {$xPos + $options(-width)}] [expr {$yPos + $options(-height)}] foreach tag $attachments { $options(-widget) coords $tag $xPos $yPos } } method move { dx {dy {}} } { #if { $dx == 0 } { # if { $dy == 0 || [string equal $dy {}] } { # return # } #} if { [string equal $dy ""] } { $options(-widget) move $options(-tag) $dx $options(-widget) move $bboxid $dx incr xPos $dx } else { $options(-widget) move $options(-tag) $dx $dy $options(-widget) move $bboxid $dx $dy incr xPos $dx incr yPos $dy } $self PlaceAttachments } method show { args } { if { [$self GotWidget] } { set options(-state) "normal" $options(-widget) itemconfigure $options(-tag) -state normal if { $havebinding } { $options(-widget) itemconfigure $bboxid -state normal } foreach attachment $attachments { if { [eval contentmanager cget $tree -omnipresent] } { continue } else { set tree $options(-tree) lappend tree $attachment eval contentmanager show $tree } } } } method hide { args } { if { [$self GotWidget] } { if { !$options(-omnipresent) } { set options(-state) "hidden" $options(-widget) itemconfigure $options(-tag) -state hidden $options(-widget) itemconfigure $bboxid -state hidden } foreach attachment $attachments { if { [eval contentmanager cget $tree -omnipresent] } { continue } else { set tree $options(-tree) lappend tree $attachment eval contentmanager hide $tree } } } } method toggle { } { switch $options(-state) { "normal" { $self hide } "hidden" { $self show } } } method SetTag { opt val } { set options(-tag) $val $self sort } method Sort { {opt {}} {val {}} } { set options($opt) $val $self sort } method sort { {level {}} } { set bbox [$options(-widget) bbox $options(-tag)] $options(-widget) raise $bboxid # Catch empty items if { [string equal $bbox {}] } { $self configure -height 0 -width 0 return } set bboxwidth [expr {[lindex $bbox 2] - [lindex $bbox 0] + (2 * $options(-ipadx))}] set bboxheight [expr {[lindex $bbox 3] - [lindex $bbox 1] + (2 * $options(-ipady))}] $self configure -height $bboxheight -width $bboxwidth } method PlaceAttachments { } { foreach attachment $attachments { set tree $options(-tree) lappend tree $attachment set attx [expr {$xPos + [eval contentmanager cget $tree -padx]}] set atty [expr {$yPos + [eval contentmanager cget $tree -pady]}] eval contentmanager coords $tree $attx $atty } } } amsn-0.98.9/utils/toolbar/0000755000175000017500000000000011757711633015206 5ustar billiobbilliobamsn-0.98.9/utils/toolbar/toolbar.tcl0000644000175000017500000004647410374654324017370 0ustar billiobbilliob# o----------------------o # | name: toolbar.tcl | # | author: tom jenkins | # | date: 07/06/06 | # o----------------------o # -------------------------------------------------- # toolbar - create and manipulate toolbar widgets # -------------------------------------------------- snit::widget toolbar { typevariable backgroundimg typevariable buttonimg typevariable buttondownimg typevariable moreimg typevariable background_border typevariable button_border typeconstructor { # Load images ::skin::setPixmap toolbar_background toolbar_background.png ::skin::setPixmap toolbar_button toolbar_button.png ::skin::setPixmap toolbar_button_down toolbar_button_down.png ::skin::setPixmap toolbar_more toolbar_more.png set backgroundimg [::skin::loadPixmap toolbar_background] set buttonimg [::skin::loadPixmap toolbar_button] set buttondownimg [::skin::loadPixmap toolbar_button_down] set moreimg [::skin::loadPixmap toolbar_more] set background_border {5 5 5 5} set button_border {5 5 5 5} } # Options option -bgimage -configuremethod SetBgImage option -bgborder -default {5 5 5 5} option -buttonimage -configuremethod SetButtonImage option -buttonborder -default {5 5 5 5} option -activeforeground -configuremethod SetActiveForeground -default black option -activefg -configuremethod SetActiveForeground -default black option -disabledforeground -configuremethod SetDisabledForeground -default grey option -disabledfg -configuremethod SetDisabledForeground -default grey option -fg -configuremethod SetForeground -default black option -foreground -configuremethod SetForeground -default black option -itempadx -default 2 -configuremethod SetPadding option -itempady -default 2 -configuremethod SetPadding option -itemipadx -default 4 -configuremethod SetPadding option -itemipady -default 4 -configuremethod SetPadding option -ipadx -default 2 -configuremethod SetPadding option -ipady -default 2 -configuremethod SetPadding option -orient -default horizontal -configuremethod SetOrient option -viewmode -default 2 -configuremethod SetViewMode # Let canvas handle options delegate option * to canvas except { -bgimage -buttonimage -itempadx -itempady -orient } # Use a frame for our base hulltype frame # Canvas and menu components component canvas component viewmenu # Variables variable shell ;# outer contentmanager group variable items ;# list of items variable itemid ;# unique id for each item variable config ;# array to store names of config objects variable background ;# scalable-bg for background image variable backgroundid ;# id of background image on canvas variable button ;# scalable-bg for toolbar button variable buttondown ;# scalable-bg for toolbar button, pressed variable buttonid ;# id of toolbar button on canvas variable more ;# group to hold button to show toolbar items not visible (i.e. because toolbar is too small) variable moreid ;# id of more button image on canvas variable afterid ;# array used to process only the last in a batch of identical commands constructor { args } { $hull configure -relief flat -bd 0 # Create canvas (we will draw everything on this) and menu install canvas using canvas $self.c -height 0 -highlightthickness 0 -relief flat -borderwidth 0 install viewmenu using menu $self.view -tearoff 0 # Add commands to view menu $viewmenu add command -label "Icons only" -command "$self configure -viewmode 0" $viewmenu add command -label "Text only" -command "$self configure -viewmode 1" $viewmenu add command -label "Text and icons" -command "$self configure -viewmode 2" # Create outer contentmanager group 'shell' set shell [contentmanager add group $self.shell -widget $canvas -orient horizontal -ipadx $options(-ipadx) -ipady $options(-ipady)] # Add group to hold the items, inside shell contentmanager add group $shell items \ -widget $canvas -orient horizontal # Create background scalable-bg set background [scalable-bg $self.background \ -source $backgroundimg -resizemethod scale\ -border $options(-bgborder)] # Put it on the canvas set backgroundid [$canvas create image 0 0 -anchor nw -image [$background name]] # Create toolbar button scalable-bg set button [scalable-bg $self.button \ -source $buttonimg -resizemethod scale \ -border $options(-buttonborder)] set buttondown [scalable-bg $self.buttondown \ -source $buttondownimg -resizemethod scale \ -border $options(-buttonborder)] # Put it on the canvas (hidden for now, we aren't hovering any items) set buttonid [$canvas create image 0 0 -anchor nw -image [$button name] -state hidden] # Create 'more' button on canvas set moreid [$canvas create image 0 0 -anchor nw -image $moreimg] # Create the group and element for the 'more' button contentmanager add group $shell more -widget $canvas -valign center contentmanager add element $shell more button -widget $canvas -tag $moreid # Hide it for now (no items yet!) contentmanager hide $shell more button # Initial values for variables set items {} set itemid 0 array set afterid {sort {}} # Parse and apply arguments given at creation time $self configurelist $args # Pack our canvas in the frame (hull) pack $canvas -expand true -fill both # Bind the canvas bind $canvas "$self Configure %w %h" ;# When resizing, we want to do things like resize background image bind $canvas "tk_popup $viewmenu %X %Y" ;# Right mouse click on toolbar to pop up view menu } destructor { catch { contentmanager delete $self.shell } catch { after cancel $afterid(sort) } ;# Don't want it trying to do $w sort when $w doesn't exist anymore! catch { destroy $background } ;# Get rid of background scalable-bg catch { destroy $button } ;# Get rid of toolbar button scalable-bg catch { destroy $buttondown } ;# Get rid of toolbar button scalable-bg } # ----------------------------------------------------------------------------------------------- # Configure - called when the canvas changes size. Updates size of background images and checks # if we need to show the 'more' button # w - width of canvas # h - height of canvas # ----------------------------------------------------------------------------------------------- method Configure { w h } { # Resize the background image $background configure -width $w -height $h # Check if we need to show the 'more' button, and hide items that don't completely fit set tw 0 set i 0 foreach item $items { set iw [contentmanager cget $shell items $item -width] set padx [contentmanager cget $shell items $item -padx] incr tw [expr {$iw + (2 * $padx)}] if { $tw > [expr {$w + $padx}] } { break } contentmanager show $shell items $item -level 0 incr i 1 } set outofview [lrange $items $i end] foreach item $outofview { contentmanager hide $shell items $item } # Position the 'more' button if { [llength $outofview] > 0 } { contentmanager show $shell more button $self sort contentmanager coords $shell more [expr {$w - [contentmanager cget $shell more -width] - $options(-itempadx)}] [lindex [contentmanager getcoords $shell more] 1] } else { contentmanager hide $shell more button $self sort } } # ------------------------------------------------- # Methods to change options # ------------------------------------------------- method SetBgImage { option value } { set options(-bgimage) $value $background configure -source $value } method SetButtonImage { option value } { set options(-buttonimage) $value $button configure -source $value } method SetActiveForeground { option value } { set options(-activeforeground) $value set options(-activefg) $value foreach item $items { $canvas itemconfigure [$config($item) cget -textid] -fill $value } } method SetDisabledForeground { option value } { set options(-disabledforeground) $value set options(-disabledfg) $value } method SetForeground { option value } { set options(-foreground) $value set options(-fg) $value } method SetOrient { option value } { set options(-orient) $value contentmanager configure $shell items -orient $value } method SetPadding { option value } { set options($option) $value foreach item $items { contentmanager configure $shell items $item -padx $options(-padx) -pady $options(-pady) contentmanager configure $shell items $item icon -padx $options(-itemipadx) -pady $options(-itemipady) contentmanager configure $shell items $item text -padx $options(-itemipadx) -pady $options(-itemipady) } $self sort } method SetViewMode { option value } { if { $value == $options(-viewmode) } { return } set options(-viewmode) $value $self ApplyViewMode $self sort } # ----------------------------------------------------------------------------------- # ApplyViewMode - Hides/shows text/icons depending on the view mode # ----------------------------------------------------------------------------------- method ApplyViewMode { {item "all"} } { switch $options(-viewmode) { 0 { # Icons only if { $item == "all" } { foreach item $items { contentmanager show $shell items $item icon contentmanager hide $shell items $item text } } else { contentmanager show $shell items $item icon contentmanager hide $shell items $item text } } 1 { # Text only if { $item == "all" } { foreach item $items { contentmanager show $shell items $item text contentmanager hide $shell items $item icon } } else { contentmanager show $shell items $item text contentmanager hide $shell items $item icon } } 2 { if { $item == "all" } { # Icons and text foreach item $items { contentmanager show $shell items $item text contentmanager show $shell items $item icon } } else { contentmanager show $shell items $item text contentmanager show $shell items $item icon } } } } # -------------------------------------------------------------- # add - adds an item to the toolbar # _type - the type of item to add. can be command or cascade # args - arguments to pass to the item # -------------------------------------------------------------- method add { _type args } { lappend args -activefg $options(-activefg) -disabledfg $options(-disabledfg) -fg $options(-fg) switch $_type { command { eval $self CreateCommand end $args } cascade { } } lappend items $itemid $self ApplyViewMode $itemid incr itemid 1 # Sort $self sort } method insert { index _type args } { lappend args -activefg $options(-activefg) -disabledfg $options(-disabledfg) -fg $options(-fg) switch $_type { command { eval $self CreateCommand $index $args } cascade { } } set items [linsert $items $index $itemid] $self ApplyViewMode $itemid incr itemid 1 # Sort $self sort } method CreateCommand { index args } { contentmanager insert $index group $shell items $itemid -widget $canvas \ -ipadx $options(-itemipadx) \ -ipady $options(-itemipady) \ -valign bottom set imgtag [$canvas create image 0 0 -anchor nw] set txttag [$canvas create text 0 0 -anchor nw] contentmanager add element $shell items $itemid icon -widget $canvas \ -align center \ -padx $options(-itemipadx) \ -pady $options(-itemipady) \ -tag $imgtag contentmanager add element $shell items $itemid text -widget $canvas \ -align center \ -padx $options(-itemipadx) \ -pady $options(-itemipady) \ -tag $txttag set config($itemid) [toolbarItemConfig $self.$itemid.config \ -canvas $canvas \ -tree [list $shell items $itemid] \ -imageid $imgtag \ -textid $txttag \ -activefg $options(-activefg) \ -disabledfg $options(-disabledfg) \ -fg $options(-fg)] $config($itemid) configurelist $args if { [$config($itemid) cget -text] == {} } { contentmanager hide $shell items $itemid text } if { [$config($itemid) cget -image] == {} } { contentmanager hide $shell items $itemid icon } # Bind for showing button on hover contentmanager bind $shell items $itemid "+$self Enter $itemid" contentmanager bind $shell items $itemid "+$self Enter $itemid 1" contentmanager bind $shell items $itemid "+$self Leave $itemid" contentmanager bind $shell items $itemid "+$self Press $itemid" contentmanager bind $shell items $itemid "+$self Release $itemid %x %y" } # ------------------------------------------------------------------------------------------------------------------------ # delete - deletes an item or range of items from the toolbar # index - the index of either the item to delete, or the start of the range of items to delete (if index2 is specified) # index2 - the index of the end of the range of items to delete # ------------------------------------------------------------------------------------------------------------------------ method delete { index {index2 {}} } { if { $index == "all" } { set index 0 set index2 end } if { $index2 == {} } { set index2 $index } set delrange [lrange $items $index $index2] foreach $item $delrange { contentmanager delete $shell items $item } $self sort } # -------------------------------------------------------------- # itemconfigure - pass arguments to an existing item # index - the index of the item to configure # args - the set of arguments to configure it with # -------------------------------------------------------------- method itemconfigure { index args } { $config([lindex $items $index]) configurelist $args $self sort } # -------------------------------------------------------------- # itemcget - get the value of an option from an item # index - the index of the item to query # option - the option of which to get the value # -------------------------------------------------------------- method itemcget { index option } { return [$config([lindex $items $index]) cget $option] } # -------------------------------------------------------------- # Select - select (show toolbar button behind) an item # id - unique id for the item (NOT the index) # -------------------------------------------------------------- method Enter { id {b 0} } { if { $b == 1 } { $canvas itemconfigure $buttonid -image [$buttondown name] -state normal } else { $canvas itemconfigure $buttonid -image [$button name] -state normal } $self Select $id } method Leave { id } { $self Select none if { [$config($id) cget -state] != "disabled" } { $canvas itemconfigure [$config($id) cget -imageid] -image [$config($id) cget -image] $canvas itemconfigure [$config($id) cget -textid] -fill [$config($id) cget -fg] } } method Select { id } { if { $id == "none" || [$config($id) cget -state] == "disabled" } { $canvas itemconfigure $buttonid -state hidden return } set xy [contentmanager getcoords $shell items $id] set w [contentmanager cget $shell items $id -width] set h [contentmanager cget $shell items $id -height] $buttondown configure -width $w -height $h $button configure -width $w -height $h eval $canvas coords $buttonid $xy } # -------------------------------------------------------------- # Select - select (show toolbar button behind) an item # id - unique id for the item (NOT the index) # -------------------------------------------------------------- method Press { id } { if { $id == "none" || [$config($id) cget -state] == "disabled" } { $canvas itemconfigure $buttonid -state hidden return } set xy [contentmanager getcoords $shell items $id] set w [contentmanager cget $shell items $id -width] set h [contentmanager cget $shell items $id -height] eval $canvas coords $buttonid $xy $buttondown configure -width $w -height $h $canvas itemconfigure $buttonid -image [$buttondown name] -state normal } method Release { id x y } { set coords [eval contentmanager getcoords $shell items $id] set cx [$canvas canvasx $x] set cy [$canvas canvasy $y] set ix0 [lindex $coords 0] set ix1 [expr {$ix0 + [eval contentmanager cget $shell items $id -width]}] set iy0 [lindex $coords 1] set iy1 [expr {$iy0 + [eval contentmanager cget $shell items $id -height]}] if { $cx >= $ix0 && $cx <= $ix1 && $cy >= $iy0 && $cy <= $iy1 && [$config($id) cget -state] != "disabled" } { $canvas itemconfigure $buttonid -image [$button name] eval [$config($id) cget -command] } } # ------------------------------------------------------------------------------------------------ # sort - wraps SortItems, stops lots of SortItems being executed at once, only runs the last one # ------------------------------------------------------------------------------------------------ method sort { } { after cancel $afterid(sort) set afterid(sort) [after 1 "$self SortItems"] } # -------------------------------------------------------------- # SortItems - sort the items and resize the toolbar to fit # -------------------------------------------------------------- method SortItems { } { contentmanager sort $shell $canvas configure -height [contentmanager cget $shell -height] } } # ---------------------------------------------------------------------- # toolbarItemConfig - stores and processes options for toolbar items # ---------------------------------------------------------------------- snit::type toolbarItemConfig { option -activefg option -activeimage -configuremethod SetActiveImage option -canvas option -command -configuremethod SetCommand option -disabledfg option -disabledimage option -fg option -image -configuremethod SetImage option -imageid option -state -configuremethod SetState option -text -configuremethod SetText option -textid option -tree method SetActiveImage { option value } { set options(-activeimage) $value eval contentmanager bind $options(-tree) [list "+$self Enter"] } method SetCommand { option value } { set options(-command) $value } method SetImage { option value } { set options(-image) $value set tag [eval contentmanager cget $options(-tree) icon -tag] $options(-canvas) itemconfigure $tag -image $value if { $value == {} } { eval contentmanager hide $options(-tree) icon } else { eval contentmanager show $options(-tree) icon } eval contentmanager bind $options(-tree) [list "+$self Leave"] } method SetState { option value } { set options(-state) $value switch $value { active { $options(-canvas) itemconfigure $options(-imageid) -image $options(-activeimage) $options(-canvas) itemconfigure $options(-textid) -fill $options(-activefg) } disabled { $options(-canvas) itemconfigure $options(-imageid) -image $options(-disabledimage) $options(-canvas) itemconfigure $options(-textid) -fill $options(-disabledfg) } normal { $options(-canvas) itemconfigure $options(-imageid) -image $options(-image) $options(-canvas) itemconfigure $options(-textid) -fill $options(-fg) } } } method SetText { option value } { set options(-text) $value set tag [eval contentmanager cget $options(-tree) text -tag] $options(-canvas) itemconfigure $tag -text $value if { $value == {} } { eval contentmanager hide $options(-tree) text } else { eval contentmanager show $options(-tree) text } } method Leave { } { if { $options(-state) != "disabled" } { $self configure -state normal } } method Enter { } { if { $options(-state) != "disabled" } { $self configure -state active } } }amsn-0.98.9/utils/sasl/0000755000175000017500000000000011757711633014506 5ustar billiobbilliobamsn-0.98.9/utils/sasl/ntlm.tcl0000644000175000017500000003245211303021241016142 0ustar billiobbilliob# ntlm.tcl - Copyright (C) 2005 Pat Thoyts # # This is an implementation of Microsoft's NTLM authentication mechanism. # # References: # http://www.innovation.ch/java/ntlm.html # http://davenport.sourceforge.net/ntlm.html # # ------------------------------------------------------------------------- # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # ------------------------------------------------------------------------- package require Tcl 8.2; # tcl minimum version package require SASL 1.0; # tcllib 1.7 package require des 1.0; # tcllib 1.8 package require md4; # tcllib 1.4 namespace eval ::SASL { namespace eval NTLM { variable version 1.1.1 variable rcsid {$Id: ntlm.tcl,v 1.8 2007/08/26 00:36:45 patthoyts Exp $} array set NTLMFlags { unicode 0x00000001 oem 0x00000002 req_target 0x00000004 unknown 0x00000008 sign 0x00000010 seal 0x00000020 datagram 0x00000040 lmkey 0x00000080 netware 0x00000100 ntlm 0x00000200 unknown 0x00000400 unknown 0x00000800 domain 0x00001000 server 0x00002000 share 0x00004000 NTLM2 0x00008000 targetinfo 0x00800000 128bit 0x20000000 keyexch 0x40000000 56bit 0x80000000 } } } # ------------------------------------------------------------------------- proc ::SASL::NTLM::NTLM {context challenge args} { upvar #0 $context ctx incr ctx(step) switch -exact -- $ctx(step) { 1 { set ctx(realm) [eval [linsert $ctx(callback) end $context realm]] set ctx(hostname) [eval [linsert $ctx(callback) end $context hostname]] set ctx(response) [CreateGreeting $ctx(realm) $ctx(hostname)] set result 1 } 2 { array set params [Decode $challenge] set user [eval [linsert $ctx(callback) end $context username]] set pass [eval [linsert $ctx(callback) end $context password]] if {[info exists params(domain)]} { set ctx(realm) $params(domain) } set ctx(response) [CreateResponse \ $ctx(realm) $ctx(hostname) \ $user $pass $params(nonce) $params(flags)] Decode $ctx(response) set result 0 } default { return -code error "invalid state \"$ctx(step)" } } return $result } # ------------------------------------------------------------------------- # NTLM client implementation # ------------------------------------------------------------------------- # The NMLM greeting. This is sent by the client to the server to initiate # the challenge response handshake. # This message contains the hostname (not domain qualified) and the # NT domain name for authentication. # proc ::SASL::NTLM::CreateGreeting {domainname hostname {flags {}}} { set domain [encoding convertto ascii $domainname] set host [encoding convertto ascii $hostname] set d_len [string length $domain] set h_len [string length $host] set d_off [expr {32 + $h_len}] if {[llength $flags] == 0} { set flags {unicode oem ntlm server domain req_target} } set msg [binary format a8iississi \ "NTLMSSP\x00" 1 [Flags $flags] \ $d_len $d_len $d_off \ $h_len $h_len 32] append msg $host $domain return $msg } # Create a NTLM server challenge. This is sent by a server in response to # a client type 1 message. The content of the type 2 message is variable # and depends upon the flags set by the client and server choices. # proc ::SASL::NTLM::CreateChallenge {domainname} { SASL::md5_init set target [encoding convertto ascii $domainname] set t_len [string length $target] set nonce [string range [binary format h* [SASL::CreateNonce]] 0 7] set pad [string repeat \0 8] set context [string repeat \0 8] set msg [binary format a8issii \ "NTLMSSP\x00" 2 \ $t_len $t_len 48 \ [Flags {ntlm unicode}]] append msg $nonce $pad $context $pad $target return $msg } # Compose the final client response. This contains the encoded username # and password, along with the server nonce value. # proc ::SASL::NTLM::CreateResponse {domainname hostname username passwd nonce flags} { set lm_resp [LMhash $passwd $nonce] set nt_resp [NThash $passwd $nonce] set domain [string toupper $domainname] set host [string toupper $hostname] set user $username set unicode [expr {$flags & 0x00000001}] if {$unicode} { set domain [to_unicode_le $domain] set host [to_unicode_le $host] set user [to_unicode_le $user] } set l_len [string length $lm_resp]; # LM response length set n_len [string length $nt_resp]; # NT response length set d_len [string length $domain]; # Domain name length set h_len [string length $host]; # Host name length set u_len [string length $user]; # User name length set s_len 0 ; # Session key length # The offsets to strings appended to the structure set d_off [expr {0x40}]; # Fixed offset to Domain buffer set u_off [expr {$d_off + $d_len}]; # Offset to user buffer set h_off [expr {$u_off + $u_len}]; # Offset to host buffer set l_off [expr {$h_off + $h_len}]; # Offset to LM hash set n_off [expr {$l_off + $l_len}]; # Offset to NT hash set s_off [expr {$n_off + $n_len}]; # Offset to Session key set msg [binary format a8is4s4s4s4s4s4i \ "NTLMSSP\x00" 3 \ [list $l_len $l_len $l_off 0] \ [list $n_len $n_len $n_off 0] \ [list $d_len $d_len $d_off 0] \ [list $u_len $u_len $u_off 0] \ [list $h_len $h_len $h_off 0] \ [list $s_len $s_len $s_off 0] \ $flags] append msg $domain $user $host $lm_resp $nt_resp return $msg } proc ::SASL::NTLM::Debug {msg} { array set d [Decode $msg] if {[info exists d(flags)]} { set d(flags) [list [format 0x%08x $d(flags)] [decodeflags $d(flags)]] } if {[info exists d(nonce)]} { set d(nonce) [base64::encode $d(nonce)] } if {[info exists d(lmhash)]} { set d(lmhash) [base64::encode $d(lmhash)] } if {[info exists d(nthash)]} { set d(nthash) [base64::encode $d(nthash)] } return [array get d] } proc ::SASL::NTLM::Decode {msg} { #puts [Debug $msg] binary scan $msg a7ci protocol zero type switch -exact -- $type { 1 { binary scan $msg @12ississi flags dlen dlen2 doff hlen hlen2 hoff binary scan $msg @${hoff}a${hlen} host binary scan $msg @${doff}a${dlen} domain return [list type $type flags [format 0x%08x $flags] \ domain $domain host $host] } 2 { binary scan $msg @12ssiia8a8 dlen dlen2 doff flags nonce pad set domain {}; binary scan $msg @${doff}a${dlen} domain set unicode [expr {$flags & 0x00000001}] if {$unicode} { set domain [from_unicode_le $domain] } binary scan $nonce H* nonce_h binary scan $pad H* pad_h return [list type $type flags [format 0x%08x $flags] \ domain $domain nonce $nonce] } 3 { binary scan $msg @12ssissississississii \ lmlen lmlen2 lmoff \ ntlen ntlen2 ntoff \ dlen dlen2 doff \ ulen ulen2 uoff \ hlen hlen2 hoff \ slen slen2 soff \ flags set domain {}; binary scan $msg @${doff}a${dlen} domain set user {}; binary scan $msg @${uoff}a${ulen} user set host {}; binary scan $msg @${hoff}a${hlen} host set unicode [expr {$flags & 0x00000001}] if {$unicode} { set domain [from_unicode_le $domain] set user [from_unicode_le $user] set host [from_unicode_le $host] } binary scan $msg @${ntoff}a${ntlen} ntdata binary scan $msg @${lmoff}a${lmlen} lmdata binary scan $ntdata H* ntdata_h binary scan $lmdata H* lmdata_h return [list type $type flags [format 0x%08x $flags]\ domain $domain host $host user $user \ lmhash $lmdata nthash $ntdata] } default { return -code error "invalid NTLM data: type not recognised" } } } proc ::SASL::NTLM::decodeflags {value} { variable NTLMFlags set result {} foreach {flag mask} [array get NTLMFlags] { if {$value & ($mask & 0xffffffff)} { lappend result $flag } } return $result } proc ::SASL::NTLM::Flags {flags} { variable NTLMFlags set result 0 foreach flag $flags { if {![info exists NTLMFlags($flag)]} { return -code error "invalid ntlm flag \"$flag\"" } set result [expr {$result | $NTLMFlags($flag)}] } return $result } # Convert a string to unicode in little endian byte order. proc ::SASL::NTLM::to_unicode_le {str} { set result [encoding convertto unicode $str] if {[string equal $::tcl_platform(byteOrder) "bigEndian"]} { set r {} ; set n 0 while {[binary scan $result @${n}cc a b] == 2} { append r [binary format cc $b $a] incr n 2 } set result $r } return $result } # Convert a little-endian unicode string to utf-8. proc ::SASL::NTLM::from_unicode_le {str} { if {[string equal $::tcl_platform(byteOrder) "bigEndian"]} { set r {} ; set n 0 while {[binary scan $str @${n}cc a b] == 2} { append r [binary format cc $b $a] incr n 2 } set str $r } return [encoding convertfrom unicode $str] } proc ::SASL::NTLM::LMhash {password nonce} { set magic "\x4b\x47\x53\x21\x40\x23\x24\x25" set hash "" set password [string range [string toupper $password][string repeat \0 14] 0 13] foreach key [CreateDesKeys $password] { append hash [DES::des -dir encrypt -weak -mode ecb -key $key $magic] } append hash [string repeat \0 5] set res "" foreach key [CreateDesKeys $hash] { append res [DES::des -dir encrypt -weak -mode ecb -key $key $nonce] } return $res } proc ::SASL::NTLM::NThash {password nonce} { set pass [to_unicode_le $password] set hash [md4::md4 $pass] append hash [string repeat \x00 5] set res "" foreach key [CreateDesKeys $hash] { append res [DES::des -dir encrypt -weak -mode ecb -key $key $nonce] } return $res } # Convert a password into a 56 bit DES key according to the NTLM specs. # We do NOT fix the parity of each byte. If we did, then bit 0 of each # byte should be adjusted to give the byte odd parity. # proc ::SASL::NTLM::CreateDesKeys {key} { # pad to 7 byte boundary with nuls. set mod [expr {[string length $key] % 7}] if {$mod != 0} { append key [string repeat "\0" [expr {7 - $mod}]] } set len [string length $key] set r "" for {set n 0} {$n < $len} {incr n 7} { binary scan $key @${n}c7 bytes set b {} lappend b [expr { [lindex $bytes 0] & 0xFF}] lappend b [expr {(([lindex $bytes 0] & 0x01) << 7) | (([lindex $bytes 1] >> 1) & 0x7F)}] lappend b [expr {(([lindex $bytes 1] & 0x03) << 6) | (([lindex $bytes 2] >> 2) & 0x3F)}] lappend b [expr {(([lindex $bytes 2] & 0x07) << 5) | (([lindex $bytes 3] >> 3) & 0x1F)}] lappend b [expr {(([lindex $bytes 3] & 0x0F) << 4) | (([lindex $bytes 4] >> 4) & 0x0F)}] lappend b [expr {(([lindex $bytes 4] & 0x1F) << 3) | (([lindex $bytes 5] >> 5) & 0x07)}] lappend b [expr {(([lindex $bytes 5] & 0x3F) << 2) | (([lindex $bytes 6] >> 6) & 0x03)}] lappend b [expr {(([lindex $bytes 6] & 0x7F) << 1)}] lappend r [binary format c* $b] } return $r; } # This is slower than the above in Tcl 8.4.9 proc ::SASL::NTLM::CreateDesKeys2 {key} { # pad to 7 byte boundary with nuls. append key [string repeat "\0" [expr {7 - ([string length $key] % 7)}]] binary scan $key B* bin set len [string length $bin] set r "" for {set n 0} {$n < $len} {incr n} { append r [string range $bin $n [incr n 6]] 0 } # needs spliting into 8 byte keys. return [binary format B* $r] } # ------------------------------------------------------------------------- # Register this SASL mechanism with the Tcllib SASL package. # if {[llength [package provide SASL]] != 0} { ::SASL::register NTLM 50 ::SASL::NTLM::NTLM } package provide SASL::NTLM $::SASL::NTLM::version # ------------------------------------------------------------------------- # # Local variables: # indent-tabs-mode: nil # End: amsn-0.98.9/utils/sasl/pkgIndex.tcl0000644000175000017500000000101011303021241016723 0ustar billiobbilliob# pkgIndex.tcl -*- tcl -*- # Copyright (C) 2005 Pat Thoyts # $Id: pkgIndex.tcl,v 1.11 2008/01/29 00:51:39 patthoyts Exp $ if {![package vsatisfies [package provide Tcl] 8.2]} { # PRAGMA: returnok return } package ifneeded SASL 1.3.2 [list source [file join $dir sasl.tcl]] package ifneeded SASL::NTLM 1.1.1 [list source [file join $dir ntlm.tcl]] package ifneeded SASL::XGoogleToken 1.0.1 [list source [file join $dir gtoken.tcl]] amsn-0.98.9/utils/sasl/gtoken.tcl0000644000175000017500000000614211303021241016454 0ustar billiobbilliob# gtoken.tcl - Copyright (C) 2006 Pat Thoyts # # This is an implementation of Google's X-GOOGLE-TOKEN authentication # mechanism. This actually passes the login details to the Google # accounts server which gives us a short lived token that may be passed # over an insecure link. # # ------------------------------------------------------------------------- # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # ------------------------------------------------------------------------- package require Tcl 8.2 package require SASL package require http package require tls namespace eval ::SASL { namespace eval XGoogleToken { variable version 1.0.1 variable rcsid {$Id: gtoken.tcl,v 1.4 2007/08/26 00:36:45 patthoyts Exp $} variable URLa https://www.google.com/accounts/ClientAuth variable URLb https://www.google.com/accounts/IssueAuthToken # Should use autoproxy and register autoproxy::tls_socket # Leave to application author? if {![info exists ::http::urlTypes(https)]} { http::register https 443 tls::socket } } } proc ::SASL::XGoogleToken::client {context challenge args} { upvar #0 $context ctx variable URLa variable URLb set reply "" set err "" if {$ctx(step) != 0} { return -code error "unexpected state: X-GOOGLE-TOKEN has only 1 step" } set username [eval $ctx(callback) [list $context username]] set password [eval $ctx(callback) [list $context password]] set query [http::formatQuery Email $username Passwd $password \ PersistentCookie false source googletalk] set tok [http::geturl $URLa -query $query -timeout 30000] if {[http::status $tok] eq "ok"} { foreach line [split [http::data $tok] \n] { array set g [split $line =] } if {![info exists g(Error)]} { set query [http::formatQuery SID $g(SID) LSID $g(LSID) \ service mail Session true] set tok2 [http::geturl $URLb -query $query -timeout 30000] if {[http::status $tok2] eq "ok"} { set reply "\0$username\0[http::data $tok2]" } else { set err [http::error $tok2] } http::cleanup $tok2 } else { set err "Invalid username or password" } } else { set err [http::error $tok] } http::cleanup $tok if {[string length $err] > 0} { return -code error $err } else { set ctx(response) $reply incr ctx(step) } return 0 } # ------------------------------------------------------------------------- # Register this SASL mechanism with the Tcllib SASL package. # if {[llength [package provide SASL]] != 0} { ::SASL::register X-GOOGLE-TOKEN 40 ::SASL::XGoogleToken::client } package provide SASL::XGoogleToken $::SASL::XGoogleToken::version # ------------------------------------------------------------------------- # # Local variables: # indent-tabs-mode: nil # End: amsn-0.98.9/utils/sasl/sasl.tcl0000644000175000017500000005246711303021241016142 0ustar billiobbilliob# sasl.tcl - Copyright (C) 2005 Pat Thoyts # # This is an implementation of a general purpose SASL library for use in # Tcl scripts. # # References: # Myers, J., "Simple Authentication and Security Layer (SASL)", # RFC 2222, October 1997. # Rose, M.T., "TclSASL", "http://beepcore-tcl.sourceforge.net/tclsasl.html" # # ------------------------------------------------------------------------- # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # ------------------------------------------------------------------------- package require Tcl 8.2 namespace eval ::SASL { variable version 1.3.2 variable rcsid {$Id: sasl.tcl,v 1.12 2008/01/29 00:51:39 patthoyts Exp $} variable uid if {![info exists uid]} { set uid 0 } variable mechanisms if {![info exists mechanisms]} { set mechanisms [list] } } # SASL::mechanisms -- # # Return a list of available SASL mechanisms. By default only the # client implementations are given but if type is set to server then # the list of available server mechanisms is returned. # No mechanism with a preference value less than 'minimum' will be # returned. # The list is sorted by the security preference with the most secure # mechanisms given first. # proc ::SASL::mechanisms {{type client} {minimum 0}} { variable mechanisms set r [list] foreach mech $mechanisms { if {[lindex $mech 0] < $minimum} { continue } switch -exact -- $type { client { if {[string length [lindex $mech 2]] > 0} { lappend r [lindex $mech 1] } } server { if {[string length [lindex $mech 3]] > 0} { lappend r [lindex $mech 1] } } default { return -code error "invalid type \"$type\":\ must be either client or server" } } } return $r } # SASL::register -- # # Register a new SASL mechanism with a security preference. Higher # preference values are chosen before lower valued mechanisms. # If no server implementation is available then an empty string # should be provided for the serverproc parameter. # proc ::SASL::register {mechanism preference clientproc {serverproc {}}} { variable mechanisms set ndx [lsearch -regexp $mechanisms $mechanism] set mech [list $preference $mechanism $clientproc $serverproc] if {$ndx == -1} { lappend mechanisms $mech } else { set mechanisms [lreplace $mechanisms $ndx $ndx $mech] } set mechanisms [lsort -index 0 -decreasing -integer $mechanisms] return } # SASL::uid -- # # Return a unique integer. # proc ::SASL::uid {} { variable uid return [incr uid] } # SASL::response -- # # Get the reponse string from the SASL state. # proc ::SASL::response {context} { upvar #0 $context ctx return $ctx(response) } # SASL::reset -- # # Reset the SASL state. This permits the same instance to be reused # for a new round of authentication. # proc ::SASL::reset {context {step 0}} { upvar #0 $context ctx array set ctx [list step $step response "" valid false count 0] return $context } # SASL::cleanup -- # # Free any resources used with the SASL state. # proc ::SASL::cleanup {context} { if {[info exists $context]} { unset $context } return } # SASL::new -- # # Create a new SASL instance. # proc ::SASL::new {args} { set context [namespace current]::[uid] upvar #0 $context ctx array set ctx [list mech {} callback {} proc {} service smtp server {} \ step 0 response "" valid false type client count 0] eval [linsert $args 0 [namespace origin configure] $context] return $context } # SASL::configure -- # # Configure the SASL state. # proc ::SASL::configure {context args} { variable mechanisms upvar #0 $context ctx while {[string match -* [set option [lindex $args 0]]]} { switch -exact -- $option { -service { set ctx(service) [Pop args 1] } -server - -serverFQDN { set ctx(server) [Pop args 1] } -mech - -mechanism { set mech [string toupper [Pop args 1]] set ctx(proc) {} foreach m $mechanisms { if {[string equal [lindex $m 1] $mech]} { set ctx(mech) $mech if {[string equal $ctx(type) "server"]} { set ctx(proc) [lindex $m 3] } else { set ctx(proc) [lindex $m 2] } break } } if {[string equal $ctx(proc) {}]} { return -code error "mechanism \"$mech\" not available:\ must be one of those given by \[sasl::mechanisms\]" } } -callback - -callbacks { set ctx(callback) [Pop args 1] } -type { set type [Pop args 1] if {[lsearch -exact {server client} $type] != -1} { set ctx(type) $type if {![string equal $ctx(mech) ""]} { configure $context -mechanism $ctx(mech) } } else { return -code error "bad value \"$type\":\ must be either client or server" } } default { return -code error "bad option \"$option\":\ must be one of -mechanism, -service, -server -type\ or -callbacks" } } Pop args } } proc ::SASL::step {context challenge args} { upvar #0 $context ctx incr ctx(count) return [eval [linsert $args 0 $ctx(proc) $context $challenge]] } proc ::SASL::Pop {varname {nth 0}} { upvar $varname args set r [lindex $args $nth] set args [lreplace $args $nth $nth] return $r } proc ::SASL::md5_init {} { variable md5_inited if {[info exists md5_inited]} {return} else {set md5_inited 1} # Deal with either version of md5. We'd like version 2 but someone # may have already loaded version 1. set md5major [lindex [split [package require md5] .] 0] if {$md5major < 2} { # md5 v1, no options, and returns a hex string ready for us. proc ::SASL::md5_hex {data} { return [::md5::md5 $data] } proc ::SASL::md5_bin {data} { return [binary format H* [::md5::md5 $data]] } proc ::SASL::hmac_hex {pass data} { return [::md5::hmac $pass $data] } proc ::SASL::hmac_bin {pass data} { return [binary format H* [::md5::hmac $pass $data]] } } else { # md5 v2 requires -hex to return hash as hex-encoded non-binary string. proc ::SASL::md5_hex {data} { return [string tolower [::md5::md5 -hex $data]] } proc ::SASL::md5_bin {data} { return [::md5::md5 $data] } proc ::SASL::hmac_hex {pass data} { return [::md5::hmac -hex -key $pass $data] } proc ::SASL::hmac_bin {pass data} { return [::md5::hmac -key $pass $data] } } } # ------------------------------------------------------------------------- # CRAM-MD5 SASL MECHANISM # # Implementation of the Challenge-Response Authentication Mechanism # (RFC2195). # # Comments: # This mechanism passes a server generated string containing # a timestamp and has the client generate an MD5 HMAC using the # shared secret as the key and the server string as the data. # The downside of this protocol is that the server must have access # to the plaintext password. # proc ::SASL::CRAM-MD5:client {context challenge args} { upvar #0 $context ctx md5_init if {$ctx(step) != 0} { return -code error "unexpected state: CRAM-MD5 has only 1 step" } if {[string length $challenge] == 0} { set ctx(response) "" return 1 } set password [eval $ctx(callback) [list $context password]] set username [eval $ctx(callback) [list $context username]] set reply [hmac_hex $password $challenge] set reply "$username [string tolower $reply]" set ctx(response) $reply incr ctx(step) return 0 } proc ::SASL::CRAM-MD5:server {context clientrsp args} { upvar #0 $context ctx md5_init incr ctx(step) switch -exact -- $ctx(step) { 1 { set ctx(realm) [eval $ctx(callback) [list $context realm]] set ctx(response) "<[pid].[clock seconds]@$ctx(realm)>" return 1 } 2 { foreach {user hash} $clientrsp break set hash [string tolower $hash] set pass [eval $ctx(callback) [list $context password $user $ctx(realm)]] set check [hmac_bin $pass $ctx(response)] binary scan $check H* cx if {[string equal $cx $hash]} { return 0 } else { return -code error "authentication failed" } } default { return -code error "invalid state" } } } ::SASL::register CRAM-MD5 30 ::SASL::CRAM-MD5:client ::SASL::CRAM-MD5:server # ------------------------------------------------------------------------- # PLAIN SASL MECHANISM # # Implementation of the single step login SASL mechanism (RFC2595). # # Comments: # A single step mechanism in which the authorization ID, the # authentication ID and password are all transmitted in plain # text. This should not be used unless the channel is secured by # some other means (such as SSL/TLS). # proc ::SASL::PLAIN:client {context challenge args} { upvar #0 $context ctx incr ctx(step) set authzid [eval $ctx(callback) [list $context login]] set username [eval $ctx(callback) [list $context username]] set password [eval $ctx(callback) [list $context password]] set ctx(response) "$authzid\x00$username\x00$password" return 0 } proc ::SASL::PLAIN:server {context clientrsp args} { upvar \#0 $context ctx if {[string length $clientrsp] < 1} { set ctx(response) "" return 1 } else { foreach {authzid authid pass} [split $clientrsp \0] break set realm [eval $ctx(callback) [list $context realm]] set check [eval $ctx(callback) [list $context password $authid $realm]] if {[string equal $pass $check]} { return 0 } else { return -code error "authentication failed" } } } ::SASL::register PLAIN 10 ::SASL::PLAIN:client ::SASL::PLAIN:server # ------------------------------------------------------------------------- # LOGIN SASL MECHANISM # # Implementation of the two step login SASL mechanism. # # Comments: # This is an unofficial but widely deployed SASL mechanism somewhat # akin to the PLAIN mechanism. Both the authentication ID and password # are transmitted in plain text in response to server prompts. # # NOT RECOMMENDED for use in new protocol implementations. # proc ::SASL::LOGIN:client {context challenge args} { upvar #0 $context ctx if {$ctx(step) == 0 && [string length $challenge] == 0} { set ctx(response) "" return 1 } incr ctx(step) switch -exact -- $ctx(step) { 1 { set ctx(response) [eval $ctx(callback) [list $context username]] set r 1 } 2 { set ctx(response) [eval $ctx(callback) [list $context password]] set r 0 } default { return -code error "unexpected state \"$ctx(step)\":\ LOGIN has only 2 steps" } } return $r } proc ::SASL::LOGIN:server {context clientrsp args} { upvar #0 $context ctx incr ctx(step) switch -exact -- $ctx(step) { 1 { set ctx(response) "Username:" return 1 } 2 { set ctx(username) $clientrsp set ctx(response) "Password:" return 1 } 3 { set user $ctx(username) set realm [eval $ctx(callback) [list $context realm]] set pass [eval $ctx(callback) [list $context password $user $realm]] if {[string equal $clientrsp $pass]} { return 0 } else { return -code error "authentication failed" } } default { return -code error "invalid state" } } } ::SASL::register LOGIN 20 ::SASL::LOGIN:client ::SASL::LOGIN:server # ------------------------------------------------------------------------- # ANONYMOUS SASL MECHANISM # # Implementation of the ANONYMOUS SASL mechanism (RFC2245). # # Comments: # # proc ::SASL::ANONYMOUS:client {context challenge args} { upvar #0 $context ctx set user [eval $ctx(callback) [list $context username]] set realm [eval $ctx(callback) [list $context realm]] set ctx(response) $user@$realm return 0 } proc ::SASL::ANONYMOUS:server {context clientrsp args} { upvar #0 $context ctx set ctx(response) "" if {[string length $clientrsp] < 1} { if {$ctx(count) > 2} { return -code error "authentication failed" } return 1 } else { set ctx(trace) $clientrsp return 0 } } ::SASL::register ANONYMOUS 5 ::SASL::ANONYMOUS:client ::SASL::ANONYMOUS:server # ------------------------------------------------------------------------- # DIGEST-MD5 SASL MECHANISM # # Implementation of the DIGEST-MD5 SASL mechanism (RFC2831). # # Comments: # proc ::SASL::DIGEST-MD5:client {context challenge args} { upvar #0 $context ctx md5_init if {$ctx(step) == 0 && [string length $challenge] == 0} { if {[info exists ctx(challenge)]} { set challenge $ctx(challenge) } else { set ctx(response) "" return 1 } } incr ctx(step) set result 0 switch -exact -- $ctx(step) { 1 { set ctx(challenge) $challenge array set params [DigestParameters $challenge] if {![info exists ctx(noncecount)]} { set ctx(noncecount) 0 } set nonce $params(nonce) set cnonce [CreateNonce] set noncecount [format %08u [incr ctx(noncecount)]] set qop auth # support the 'charset' parameter. set username [eval $ctx(callback) [list $context username]] set password [eval $ctx(callback) [list $context password]] set encoding iso8859-1 if {[info exists params(charset)]} { set encoding $params(charset) } set username [encoding convertto $encoding $username] set password [encoding convertto $encoding $password] if {[info exists params(realm)]} { set realm $params(realm) } else { set realm [eval $ctx(callback) [list $context realm]] } set uri "$ctx(service)/$realm" set R [DigestResponse $username $realm $password $uri \ $qop $nonce $noncecount $cnonce] set ctx(response) "username=\"$username\",realm=\"$realm\",nonce=\"$nonce\",nc=\"$noncecount\",cnonce=\"$cnonce\",digest-uri=\"$uri\",response=\"$R\",qop=$qop" if {[info exists params(charset)]} { append ctx(response) ",charset=$params(charset)" } set result 1 } 2 { set ctx(response) "" set result 0 } default { return -code error "invalid state" } } return $result } proc ::SASL::DIGEST-MD5:server {context challenge args} { upvar #0 $context ctx md5_init incr ctx(step) set result 0 switch -exact -- $ctx(step) { 1 { set realm [eval $ctx(callback) [list $context realm]] set ctx(nonce) [CreateNonce] set ctx(nc) 0 set ctx(response) "realm=\"$realm\",nonce=\"$ctx(nonce)\",qop=\"auth\",charset=utf-8,algorithm=md5-sess" set result 1 } 2 { array set params [DigestParameters $challenge] set realm [eval $ctx(callback) [list $context realm]] set password [eval $ctx(callback)\ [list $context password $params(username) $realm]] set uri "$ctx(service)/$realm" set nc [format %08u [expr {$ctx(nc) + 1}]] set R [DigestResponse $params(username) $realm $password \ $uri auth $ctx(nonce) $nc $params(cnonce)] if {[string equal $R $params(response)]} { set R2 [DigestResponse $params(username) $realm $password \ $uri auth $ctx(nonce) $nc $params(cnonce)] set ctx(response) "rspauth=$R2" incr ctx(nc) set result 1 } else { return -code error "authentication failed" } } 3 { set ctx(response) "" set result 0 } default { return -code error "invalid state" } } return $result } # RFC 2831 2.1 # Char categories as per spec... # Build up a regexp for splitting the challenge into key value pairs. proc ::SASL::DigestParameters {challenge} { set sep "\\\]\\\[\\\\()<>@,;:\\\"\\\?=\\\{\\\} \t" set tok {0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\-\|\~\!\#\$\%\&\*\+\.\^\_\`} set sqot {(?:\'(?:\\.|[^\'\\])*\')} set dqot {(?:\"(?:\\.|[^\"\\])*\")} set parameters {} regsub -all "(\[${tok}\]+)=(${dqot}|(?:\[${tok}\]+))(?:\[${sep}\]+|$)" $challenge {\1 \2 } parameters return $parameters } # RFC 2831 2.1.2.1 # proc ::SASL::DigestResponse {user realm pass uri qop nonce noncecount cnonce} { set A1 [md5_bin "$user:$realm:$pass"] set A2 "AUTHENTICATE:$uri" if {![string equal $qop "auth"]} { append A2 :[string repeat 0 32] } set A1h [md5_hex "${A1}:$nonce:$cnonce"] set A2h [md5_hex $A2] set R [md5_hex $A1h:$nonce:$noncecount:$cnonce:$qop:$A2h] return $R } # RFC 2831 2.1.2.2 # proc ::SASL::DigestResponse2 {user realm pass uri qop nonce noncecount cnonce} { set A1 [md5_bin "$user:$realm:$pass"] set A2 ":$uri" if {![string equal $qop "auth"]} { append A2 :[string repeat 0 32] } set A1h [md5_hex "${A1}:$nonce:$cnonce"] set A2h [md5_hex $A2] set R [md5_hex $A1h:$nonce:$noncecount:$cnonce:$qop:$A2h] return $R } # Get 16 random bytes for a nonce value. If we can use /dev/random, do so # otherwise we hash some values. # proc ::SASL::CreateNonce {} { set bytes {} if {[file readable /dev/urandom]} { catch { set f [open /dev/urandom r] fconfigure $f -translation binary -buffering none set bytes [read $f 16] close $f } } if {[string length $bytes] < 1} { set bytes [md5_bin [clock seconds]:[pid]:[expr {rand()}]] } return [binary scan $bytes h* r; set r] } ::SASL::register DIGEST-MD5 40 \ ::SASL::DIGEST-MD5:client ::SASL::DIGEST-MD5:server # ------------------------------------------------------------------------- # OTP SASL MECHANISM # # Implementation of the OTP SASL mechanism (RFC2444). # # Comments: # # RFC 2289: A One-Time Password System # RFC 2444: OTP SASL Mechanism # RFC 2243: OTP Extended Responses # Client initializes with authid\0authzid # Server responds with extended OTP responses # eg: otp-md5 498 bi32123 ext # Client responds with otp result as: # hex:xxxxxxxxxxxxxxxx # or # word:WWWW WWW WWWW WWWW WWWW # # To support changing the otp sequence the extended commands have: # init-hex::: # eg: init-hex:xxxxxxxxxxxx:md5 499 seed987:xxxxxxxxxxxxxx # or init-word proc ::SASL::OTP:client {context challenge args} { upvar #0 $context ctx package require otp incr ctx(step) switch -exact -- $ctx(step) { 1 { set authzid [eval $ctx(callback) [list $context login]] set username [eval $ctx(callback) [list $context username]] set ctx(response) "$authzid\x00$username" set cont 1 } 2 { foreach {type count seed ext} $challenge break set type [lindex [split $type -] 1] if {[lsearch -exact {md4 md5 sha1 rmd160} $type] == -1} { return -code error "unsupported digest algorithm \"$type\":\ must be one of md4, md5, sha1 or rmd160" } set challenge [lrange $challenge 3 end] set password [eval $ctx(callback) [list $context password]] set otp [::otp::otp-$type -word -seed $seed \ -count $count $password] if {[string match "ext*" $ext]} { set otp word:$otp } set ctx(response) $otp set cont 0 } default { return -code error "unexpected state \"$ctx(step)\":\ the SASL OTP mechanism only has 2 steps" } } return $cont } ::SASL::register OTP 45 ::SASL::OTP:client # ------------------------------------------------------------------------- package provide SASL $::SASL::version # ------------------------------------------------------------------------- # # Local variables: # indent-tabs-mode: nil # End: amsn-0.98.9/utils/voipcontrols/0000755000175000017500000000000011757711633016305 5ustar billiobbilliobamsn-0.98.9/utils/voipcontrols/pkgIndex.tcl0000644000175000017500000000036211145660457020561 0ustar billiobbilliobpackage ifneeded voipcontrols 0.1 [ format { set olddir [pwd] cd "%s" if {[catch {source [file join voipcontrols.tcl]} err]} { cd $olddir error "error while loading package voipcontrols: $err" } else { cd $olddir } } [list $dir]] amsn-0.98.9/utils/voipcontrols/voipcontrols.tcl0000644000175000017500000002651111243371757021556 0ustar billiobbilliob package require snit package provide voipcontrols 0.1 snit::widget voipcontrol { option -orient -default "vertical" -readonly yes option -mixerframesize -default 10 -readonly yes option -buttonframesize -default 22 -readonly yes option -bg -default white -configuremethod SetBackground option -state -default normal -configuremethod SetState component mixerframe component mutecheckbutton component endcallbutton delegate option -endcallimage to endcallbutton as -image delegate option -endcallcommand to endcallbutton as -command delegate option -endcallstate to endcallbutton as -state delegate option -mutedimage to mutecheckbutton delegate option -unmutedimage to mutecheckbutton delegate option -mutevariable to mutecheckbutton delegate option -mutecommand to mutecheckbutton delegate option -mutestate to mutecheckbutton as -state delegate option -volumefrom to mixerframe delegate option -volumeto to mixerframe delegate option -levelfrom to mixerframe delegate option -levelto to mixerframe delegate option -volumevariable to mixerframe as -variable delegate option -volumecommand to mixerframe as -command delegate option -volumestate to mixerframe as -state delegate method setLevel to mixerframe delegate method Mute to mutecheckbutton delegate method UnMute to mutecheckbutton delegate option * to hull constructor {args} { set mixerframe [voipmixer ${win}.mixerframe] set buttonframe [frame ${win}.buttonframe] set mutecheckbutton [mutecheckbutton ${buttonframe}.mute] set endcallbutton [button ${buttonframe}.endcall -relief flat -image {}] $self configurelist $args #creating mixerframe again since $options(-orient) is not set yet and the component must exist when configurelist is called... destroy $mixerframe set mixerframe [voipmixer ${win}.mixerframe -orient $options(-orient) -mutecheckbutton $mutecheckbutton] $self configurelist $args if { $options(-orient) == "vertical" } { pack $mutecheckbutton $endcallbutton place $mixerframe -width $options(-mixerframesize) -relheight 1 place $buttonframe -x $options(-mixerframesize) -width $options(-buttonframesize) -relheight 1 } else { pack $mutecheckbutton $endcallbutton -side right place $mixerframe -height $options(-mixerframesize) -relwidth 1 place $buttonframe -y $options(-mixerframesize) -height $options(-buttonframesize) -relwidth 1 } } method SetBackground {option value} { set options($option) $value $win configure -background $value $mixerframe configure -background $value $win.buttonframe configure -background $value $mutecheckbutton configure -background $value $win.buttonframe.endcall configure -background $value } method SetState {option value} { set options($option) $value $mixerframe configure -state $value $endcallbutton configure -state $value $mutecheckbutton configure -state $value } method getSize {} { set size $options(-mixerframesize) incr size $options(-buttonframesize) return $size } } snit::widgetadaptor mutecheckbutton { variable muted option -mutedimage -default {} -configuremethod SetImage option -unmutedimage -default {} -configuremethod SetImage option -mutevariable -default {} option -mutecommand -default {} delegate option * to hull delegate method * to hull constructor {args} { installhull using button -relief flat -image {} -command [list $self invoke] $self configurelist $args set muted 0 if {[info exists ::$options(-mutevariable)]} { if {[set ::$options(-mutevariable)]} { set muted 1 } else { set muted 0 } } $self configure -image $options(-unmutedimage) } method SetImage {option value} { set options($option) $value if {$muted} { $self configure -image $options(-mutedimage) } else { $self configure -image $options(-unmutedimage) } } method Mute {} { if {!$muted} { $self configure -image $options(-mutedimage) set muted 1 if {[info exists ::$options(-mutevariable)]} { set ::$options(-mutevariable) $muted } if { $options(-mutecommand) != {} } { eval $options(-mutecommand) } } } method UnMute {} { if {$muted} { $self configure -image $options(-unmutedimage) set muted 0 if {[info exists ::$options(-mutevariable)]} { set ::$options(-mutevariable) $muted } if { $options(-mutecommand) != {} } { eval $options(-mutecommand) } } } method invoke {} { if {$muted} { $self configure -image $options(-unmutedimage) set muted 0 } else { $self configure -image $options(-mutedimage) set muted 1 } if {[info exists ::$options(-mutevariable)]} { set ::$options(-mutevariable) $muted } if { $options(-mutecommand) != {} } { eval $options(-mutecommand) } } } snit::widget voipmixer { option -mutecheckbutton -readonly yes -default "" option -volumefrom -default -25 option -volumeto -default 15 option -levelfrom -default -20 option -levelto -default 0 option -selectsize -default 5 -configuremethod SetSelectSize option -variable -default {} -configuremethod SetVariable option -command -default {} option -orient -default "vertical" -readonly yes option -state -default normal delegate option * to hull constructor {args} { frame ${win}.fill place ${win}.fill -relheight 1 -relwidth 1 frame ${win}.select -background black $self configurelist $args bind ${win}.select "$self Motion" if {![catch {tk windowingsystem} wsystem] && $wsystem != "x11"} { bind ${win} "$self MouseWheel" bind ${win}.fill "$self MouseWheel" bind ${win}.select "$self MouseWheel" } else { bind ${win} "$self MoveSelect 0" bind ${win}.fill "$self MoveSelect 0" bind ${win}.select "$self MoveSelect 0" bind ${win} "$self MoveSelect 1" bind ${win}.fill "$self MoveSelect 1" bind ${win}.select "$self MoveSelect 1" } } method MoveSelect {{up 1}} { if { $options(-state) != "normal"} {return} set val [expr {double([set ::$options(-variable)]) - double($options(-volumefrom))}] set val [expr {$val / (double($options(-volumeto)) - double($options(-volumefrom)))}] if {$up == 1} { set val [expr {$val + 0.1}] } else { set val [expr {$val - 0.1}] } if { $options(-orient) == "vertical" } { set size [winfo height ${win}] set max [expr {1-double($options(-selectsize))/double(${size})}] set rel [expr {1-$val}] } else { set size [winfo width ${win}] set max [expr {1-double($options(-selectsize))/double(${size})}] set rel $val } if {$rel > $max} { set rel $max } else { if {$rel < 0} { set rel 0 } } if { $options(-mutecheckbutton) != ""} { if { $options(-orient) == "vertical" } { if {$rel >= 0.95} { $options(-mutecheckbutton) Mute } else { $options(-mutecheckbutton) UnMute } } else { if {$rel <= 0.05} { $options(-mutecheckbutton) Mute } else { $options(-mutecheckbutton) UnMute } } } if { $options(-orient) == "vertical" } { place configure ${win}.select -rely $rel } else { place configure ${win}.select -relx $rel } if {[info exists ::$options(-variable)]} { if { $options(-orient) == "vertical" } { set val [expr {1-$rel/$max}] set val [expr {$options(-volumefrom) + $val * ($options(-volumeto) - $options(-volumefrom))}] set ::$options(-variable) $val if { $options(-command) != {} } { eval $options(-command) $val } } else { set val [expr {$rel/$max}] set val [expr {$options(-volumefrom) + $val * ($options(-volumeto) - $options(-volumefrom))}] set ::$options(-variable) $val if { $options(-command) != {} } { eval $options(-command) $val } } } } method MouseWheel {} { if {%D>0} { $self MoveSelect 1 } else { $self MoveSelect 0 } } method Motion {} { if { $options(-state) != "normal"} {return} if { $options(-orient) == "vertical" } { set size [winfo height ${win}] set max [expr {1-double($options(-selectsize))/double(${size})}] set rel [expr {double([winfo pointery ${win}] - [winfo rooty ${win}])/double(${size})}] } else { set size [winfo width ${win}] set max [expr {1-double($options(-selectsize))/double(${size})}] set rel [expr {double([winfo pointerx ${win}] - [winfo rootx ${win}])/double(${size})}] } if {$rel > $max} { set rel $max } else { if {$rel < 0} { set rel 0 } } if { $options(-mutecheckbutton) != "" } { if { $options(-orient) == "vertical" } { if {$rel >= 0.95} { $options(-mutecheckbutton) Mute } else { $options(-mutecheckbutton) UnMute } } else { if {$rel <= 0.05} { $options(-mutecheckbutton) Mute } else { $options(-mutecheckbutton) UnMute } } } if { $options(-orient) == "vertical" } { place configure ${win}.select -rely ${rel} } else { place configure ${win}.select -relx ${rel} } if {[info exists ::$options(-variable)]} { if { $options(-orient) == "vertical" } { set val [expr {1-$rel/$max}] set val [expr {$options(-volumefrom) + $val * ($options(-volumeto) - $options(-volumefrom))}] set ::$options(-variable) $val if { $options(-command) != {} } { eval $options(-command) $val } } else { set val [expr {$rel/$max}] set val [expr {$options(-volumefrom) + $val * ($options(-volumeto) - $options(-volumefrom))}] set ::$options(-variable) $val if { $options(-command) != {} } { eval $options(-command) $val } } } } method SetSelectSize {option value} { set options($option) $value if { $options(-orient) == "vertical" } { ${win}.select configure -height $value place ${win}.select -height $value } else { ${win}.select configure -width $value place ${win}.select -width $value } } method SetVariable { option value} { set options($option) $value if {![info exists ::$options(-variable)] || [set ::$options(-variable)] > $options(-volumeto) || [set ::$options(-variable)] < $options(-volumefrom)} { set ::$options(-variable) [expr {$options(-volumefrom) + 0.5 * (double($options(-volumeto)) - double($options(-volumefrom)))}] } set val [expr {double([set ::$options(-variable)]) - double($options(-volumefrom))}] set val [expr {$val / (double($options(-volumeto)) - double($options(-volumefrom)))}] if { $options(-orient) == "vertical" } { set val [expr {1-$val}] place ${win}.select -relx 0 -rely ${val} -relwidth 1 -height $options(-selectsize) } else { place ${win}.select -rely 0 -relx ${val} -relheight 1 -width $options(-selectsize) } } method setLevel {value} { if { $options(-state) != "normal"} {return} if {[expr {$value == "-inf"}] || [expr {$value == "inf"}] } { set value $options(-levelfrom) } set relsize [expr {double($value) - double($options(-levelfrom))}] set relsize [expr {$relsize / (double($options(-levelto)) - double($options(-levelfrom)))}] if { $options(-orient) == "vertical" } { place conf $win.fill -relheight $relsize place conf $win.fill -rely [expr {1-$relsize}] } else { place conf $win.fill -relwidth $relsize } if {[expr $relsize > 0.5]} { set R e1 binary scan [binary format i [expr {int(2*(1.0-$relsize)*225)}]] H2 G } else { set G e1 binary scan [binary format i [expr {int(2*$relsize*225)}]] H2 R } set B 00 ${win}.fill configure -background \#${R}${G}${B} } } amsn-0.98.9/utils/voipcontrols/test.tcl0000644000175000017500000000150011203640746017754 0ustar billiobbilliob#!/usr/bin/env wish lappend auto_path "../" package require voipcontrols #wm attributes wm title . "voipcontrol test" wm geometry . 200x200 update variable var set var 0.75 set var2 0.15 proc showValue {value} { puts "value=$value" } voipcontrol .sm -volumevariable var -volumecommand [list showValue] voipcontrol .sm2 -orient horizontal -height 25 place .sm -width 25 -relheight 1 place .sm2 -height 25 -relwidth 1 -width -25 -x 25 update puts "[winfo width .sm] [winfo height .sm]" puts "============" puts "[winfo width .sm2] [winfo height .sm2]" proc timer {sm limit delay {value 0}} { variable var variable var2 puts "var=$var\tvar2=$var2" $sm setLevel $value incr value if {$value >= $limit} {set value -20} after $delay [list timer $sm $limit $delay $value] } timer .sm 0 200 -20 timer .sm2 0 200 -20 amsn-0.98.9/utils/webcamsn/0000755000175000017500000000000011757711723015343 5ustar billiobbilliobamsn-0.98.9/utils/webcamsn/README0000644000175000017500000000255210225230720016205 0ustar billiobbilliobABOUT ----- libmimic is an open source video encoding/decoding library for Mimic V2.x- encoded content (fourCC: ML20), which is the encoding used by MSN Messenger for webcam conversations. It was written because there was no third-party MSN-client that supported this feature due to this proprietary/unknown codec involved. I didn't like this lack of interoperability, so I decided to do something about it. After studying the official MSN-client a little closer, it became clear that the codec involved was statically linked into the executable, so there was no easy way to use the codec code through Wine. So for fun, and challenge, I reverse-engineered the original implementation by studying the massive amount of assembly code involved, and after a lot of hard work I ended up with this implementation in C. It should be noted that reverse-engineering for interoperability is 100% legal here in Norway (and in most European countries). THANKS ------ Special thanks to Rob Taylor and the rest of the Farsight-team for all the feedback and inspiration during development, you guys rock! :-) BOTTOM LINE ----------- If you like my work and decide to use it in your project, please feel free to credit me. I put a lot of time and hard work into this, so I hope others will find it useful. Well, enough chit chat, enjoy! :-) Ole André Vadla Ravnås oleavr at gmail dot com amsn-0.98.9/utils/webcamsn/NEWS0000644000175000017500000000000010225230720016006 0ustar billiobbilliobamsn-0.98.9/utils/webcamsn/pkgIndex.tcl0000644000175000017500000000075011031756705017614 0ustar billiobbilliob# Tcl package index file, version 1.0 if {[package vcompare [info tclversion] 8.4] < 0} return if {[file exists [file join $dir [info tclversion] webcamsn[info shared]]]} { package ifneeded webcamsn 0.1 "package require Tk; [list load [file join $dir [info tclversion] webcamsn[info shared]] webcamsn];package provide webcamsn 0.1" } else { package ifneeded webcamsn 0.1 "package require Tk; [list load [file join $dir webcamsn[info shared]] webcamsn];package provide webcamsn 0.1" } amsn-0.98.9/utils/webcamsn/8.5/0000755000175000017500000000000011757711723015655 5ustar billiobbilliobamsn-0.98.9/utils/webcamsn/COPYING0000644000175000017500000006347610225230720016374 0ustar billiobbilliob GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! amsn-0.98.9/utils/webcamsn/src/0000755000175000017500000000000011757711633016132 5ustar billiobbilliobamsn-0.98.9/utils/webcamsn/src/encode.c0000644000175000017500000003106410734050401017516 0ustar billiobbilliob/* Copyright (C) 2005 Ole André Vadla Ravnås * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #define _USE_MATH_DEFINES #include #include "mimic-private.h" #ifndef M_LN10 //Not defined in VS6 #define M_LN10 2.30258509299404568402 #endif #define LUMINANCE_THRESHOLD 32.0f #define CHROMINANCE_THRESHOLD 36.0f static void encode_main(MimCtx *ctx, guchar *out_buf, gboolean is_pframe); /** * Encode a MIMIC-encoded frame from RGB data. * * @param ctx the mimic context * @param input_buffer buffer containing pixeldata in RGB 24-bpp packed pixel top-down format * @param output_buffer buffer that will receive the MIMIC-encoded frame * (use #mimic_get_property to determine the required buffer size) * @param output_length pointer to an integer that receives the length of the encoded data * written to output_buffer * @param make_keyframe whether the encoder should make this frame a keyframe * @returns #TRUE on success */ gboolean mimic_encode_frame(MimCtx *ctx, const guchar *input_buffer, guchar *output_buffer, gint *output_length, gboolean make_keyframe) { guchar *output_y, *output_cb, *output_cr; /* * Some sanity checks. */ if (ctx == NULL || input_buffer == NULL || output_buffer == NULL || output_length == NULL) { return FALSE; } if (!ctx->encoder_initialized) return FALSE; /* * Initialize state. */ ctx->chunk_ptr = (guint32 *) (output_buffer + 20); ctx->cur_chunk = 0; ctx->cur_chunk_len = 0; if (ctx->frame_num == 0) make_keyframe = TRUE; /* * Write header. */ memset(output_buffer, 0, 20); *((guint16 *) (output_buffer + 0)) = GUINT16_TO_LE(256); *((guint16 *) (output_buffer + 2)) = GUINT16_TO_LE(ctx->quality); *((guint16 *) (output_buffer + 4)) = GUINT16_TO_LE(ctx->frame_width); *((guint16 *) (output_buffer + 6)) = GUINT16_TO_LE(ctx->frame_height); *((guint32 *) (output_buffer + 12)) = GUINT32_TO_LE((make_keyframe == 0)); *(output_buffer + 16) = ctx->num_coeffs; *(output_buffer + 17) = 0; /* * Perform RGB to YUV 420 conversion. */ output_y = ctx->cur_frame_buf; output_cr = ctx->cur_frame_buf + ctx->y_size; output_cb = ctx->cur_frame_buf + ctx->y_size + ctx->crcb_size; _rgb_to_yuv(input_buffer, output_y, output_cb, output_cr, ctx->frame_width, ctx->frame_height); /* * Encode frame. */ encode_main(ctx, output_buffer, (make_keyframe == FALSE)); /* * Write out any pending bits to stream by zero-padding with 32 bits. */ _write_bits(ctx, 0, 32); /* * Calculate bytes written. */ *output_length = (guchar *) ctx->chunk_ptr - output_buffer; /* * Increment frame counter. */ ctx->frame_num++; return TRUE; } static gdouble compare_blocks(const guchar *p1, const guchar *p2, gint stride, gint row_count, gboolean is_chrom); /* * encode_main * * Main encoding loop. */ static void encode_main(MimCtx *ctx, guchar *out_buf, gboolean is_pframe) { gint x, y, i, offset, chrom_ch; gint dct_block[64]; guchar *src, *dst, *p1, *p2; gdouble match; gboolean encoded; /* * Round down small differences in luminance channel. */ if (is_pframe) { p1 = ctx->cur_frame_buf; p2 = ctx->prev_frame_buf; for (i = 0; i < ctx->y_size; i++) { if (abs(p2[0] - p1[0]) < 7) p1[0] = p2[0]; p1++; p2++; } } /* * Encode Y plane. */ for (y = 0; y < ctx->num_vblocks_y; y++) { for (x = 0; x < ctx->num_hblocks_y; x++) { /* Calculate final offset into buffer. */ offset = (ctx->y_stride * 8 * y) + (x * 8); src = NULL; encoded = FALSE; if (is_pframe) { /* Is the current block similar enough to what it was in the previous frame? */ match = compare_blocks(ctx->cur_frame_buf + offset, ctx->prev_frame_buf + offset, ctx->y_stride, 8, FALSE); if (match > LUMINANCE_THRESHOLD) { /* Yes: write out '1' to indicate a no-change condition. */ _write_bits(ctx, 1, 1); src = ctx->prev_frame_buf + offset; encoded = TRUE; } else { /* No: Is the current block similar enough to what it was in one * of the (up to) 15 last frames preceding the previous? */ gint best_index = 0; gdouble best_match = 0.0; gint num_backrefs = ctx->frame_num - 1; if (num_backrefs > 15) num_backrefs = 15; for (i = 1; i <= num_backrefs; i++) { match = compare_blocks(ctx->buf_ptrs[(ctx->ptr_index + i) % 16] + offset, ctx->cur_frame_buf + offset, ctx->y_stride, 8, FALSE); if (match > LUMINANCE_THRESHOLD && match > best_match) { best_index = i; best_match = match; } } if (best_index != 0) { /* Yes: write out '01' to indicate a "change but like previous"-condition, * followed by 4 bits containing the back-reference. */ _write_bits(ctx, 0, 1); _write_bits(ctx, 1, 1); _write_bits(ctx, best_index, 4); src = ctx->buf_ptrs[(ctx->ptr_index + best_index) % 16] + offset; encoded = TRUE; } } } if (!encoded) { /* Keyframe or in any case no? ;-) Well, encode it then. */ if (is_pframe) { _write_bits(ctx, 0, 1); _write_bits(ctx, 0, 1); } _fdct_quant_block(ctx, dct_block, ctx->cur_frame_buf + offset, ctx->y_stride, FALSE, ctx->num_coeffs); _vlc_encode_block(ctx, dct_block, ctx->num_coeffs); } /* And if there was some kind of no-change condition, * we want to copy the previous block. */ if (src != NULL) { dst = ctx->cur_frame_buf + offset; for (i = 0; i < 8; i++) { memcpy(dst, src, 8); src += ctx->y_stride; dst += ctx->y_stride; } } } } /* * Encode Cr and Cb planes. */ for (chrom_ch = 0; chrom_ch < 2; chrom_ch++) { /* Calculate base offset into buffer. */ gint base_offset = ctx->y_size + (ctx->crcb_size * chrom_ch); for (y = 0; y < ctx->num_vblocks_cbcr; y++) { guchar tmp_block[64]; guint num_rows = 8; /* The last row of blocks in chrominance for 160x120 resolution * is half the normal height and must be accounted for. */ if (y + 1 == ctx->num_vblocks_cbcr && ctx->frame_height % 16 != 0) num_rows = 4; for (x = 0; x < ctx->num_hblocks_cbcr; x++) { /* Calculate final offset into buffer. */ offset = base_offset + (ctx->crcb_stride * 8 * y) + (x * 8); src = NULL; encoded = FALSE; if (is_pframe) { /* Is the current block similar enough to what it was in the previous frame? */ match = compare_blocks(ctx->prev_frame_buf + offset, ctx->cur_frame_buf + offset, ctx->crcb_stride, num_rows, TRUE); if (match > CHROMINANCE_THRESHOLD) { /* Yes: write out '0' to indicate a no-change condition. */ _write_bits(ctx, 0, 1); encoded = TRUE; src = ctx->prev_frame_buf + offset; dst = ctx->cur_frame_buf + offset; for (i = 0; i < num_rows; i++) { memcpy(dst, src, 8); src += ctx->crcb_stride; dst += ctx->crcb_stride; } } } if (!encoded) { /* Keyframe or just not similar enough? ;-) Well, encode it then. */ if (is_pframe) _write_bits(ctx, 1, 1); /* Use a temporary array to handle cases where the * current block is not of normal height (see above). */ src = ctx->cur_frame_buf + offset; dst = tmp_block; for (i = 0; i < 8; i++) { memcpy(dst, src, 8); if (i < (num_rows - 1)) src += ctx->crcb_stride; dst += 8; } _fdct_quant_block(ctx, dct_block, tmp_block, 8, TRUE, ctx->num_coeffs); _vlc_encode_block(ctx, dct_block, ctx->num_coeffs); } } } } /* * Make a copy of the current frame and store in * the circular pointer list of 16 entries. */ ctx->prev_frame_buf = ctx->buf_ptrs[ctx->ptr_index]; memcpy(ctx->prev_frame_buf, ctx->cur_frame_buf, ctx->y_size + (ctx->crcb_size * 2)); if (--ctx->ptr_index < 0) ctx->ptr_index = 15; } /* * compare_blocks * * Helper-function used to compare two blocks and * determine how similar they are. */ static gdouble compare_blocks(const guchar *p1, const guchar *p2, gint stride, gint row_count, gboolean is_chrom) { gint i, j, sum; gdouble d; sum = 0; for (i = 0; i < row_count; i++) { for (j = 0; j < 8; j++) { gint d = p2[j] - p1[j]; sum += d * d; } p1 += stride; p2 += stride; } if (is_chrom) { if (row_count == 8) d = sum * 0.015625; else d = sum * 0.03125; } else { d = sum / 64; } if (d == 0.0f) return 100.0f; else return (10.0f * log(65025.0f / d)) / M_LN10; } amsn-0.98.9/utils/webcamsn/src/vlc_common.c0000644000175000017500000022514110647521273020433 0ustar billiobbilliob/* Copyright (C) 2005 Ole André Vadla Ravnås * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "mimic-private.h" guchar _col_zag[64] = { 0, 8, 1, 2, 9, 16, 24, 17, 10, 3, 4, 11, 18, 25, 32, 40, 33, 26, 19, 12, 5, 6, 13, 20, 27, 34, 41, 48, 56, 49, 42, 35, 28, 21, 14, 7, 15, 22, 29, 36, 43, 50, 57, 58, 51, 44, 37, 30, 23, 31, 38, 45, 52, 59, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 }; VlcSymbol _vlc_alphabet[16][128] = { /* * base alphabet - no zeroes prefixed */ { { 3, 0x1, 0, 0 }, { 4, 0x7, 0, 0 }, { 4, 0x5, 0, 0 }, { 6, 0x27, 0, 0 }, { 6, 0x25, 0, 0 }, { 6, 0x23, 0, 0 }, { 6, 0x21, 0, 0 }, { 8, 0xcf, 0, 0 }, { 8, 0xcd, 0, 0 }, { 8, 0xcb, 0, 0 }, { 8, 0xc9, 0, 0 }, { 8, 0xc7, 0, 0 }, { 8, 0xc5, 0, 0 }, { 8, 0xc3, 0, 0 }, { 8, 0xc1, 0, 0 }, { 10, 0x35f, 0, 0 }, { 10, 0x35d, 0, 0 }, { 10, 0x35b, 0, 0 }, { 10, 0x359, 0, 0 }, { 10, 0x357, 0, 0 }, { 10, 0x355, 0, 0 }, { 10, 0x353, 0, 0 }, { 10, 0x351, 0, 0 }, { 10, 0x34f, 0, 0 }, { 10, 0x34d, 0, 0 }, { 10, 0x34b, 0, 0 }, { 10, 0x349, 0, 0 }, { 10, 0x347, 0, 0 }, { 10, 0x345, 0, 0 }, { 10, 0x343, 0, 0 }, { 10, 0x341, 0, 0 }, { 12, 0xeff, 0, 0 }, { 12, 0xefd, 0, 0 }, { 12, 0xefb, 0, 0 }, { 12, 0xef9, 0, 0 }, { 12, 0xef7, 0, 0 }, { 12, 0xef5, 0, 0 }, { 12, 0xef3, 0, 0 }, { 12, 0xef1, 0, 0 }, { 12, 0xeef, 0, 0 }, { 12, 0xeed, 0, 0 }, { 12, 0xeeb, 0, 0 }, { 12, 0xee9, 0, 0 }, { 12, 0xee7, 0, 0 }, { 12, 0xee5, 0, 0 }, { 12, 0xee3, 0, 0 }, { 12, 0xee1, 0, 0 }, { 12, 0xedf, 0, 0 }, { 12, 0xedd, 0, 0 }, { 12, 0xedb, 0, 0 }, { 12, 0xed9, 0, 0 }, { 12, 0xed7, 0, 0 }, { 12, 0xed5, 0, 0 }, { 12, 0xed3, 0, 0 }, { 12, 0xed1, 0, 0 }, { 12, 0xecf, 0, 0 }, { 12, 0xecd, 0, 0 }, { 12, 0xecb, 0, 0 }, { 12, 0xec9, 0, 0 }, { 12, 0xec7, 0, 0 }, { 12, 0xec5, 0, 0 }, { 12, 0xec3, 0, 0 }, { 12, 0xec1, 0, 0 }, { 17, 0x1fd7f, 0, 0 }, { 17, 0x1fd7d, 0, 0 }, { 17, 0x1fd7b, 0, 0 }, { 17, 0x1fd79, 0, 0 }, { 17, 0x1fd77, 0, 0 }, { 17, 0x1fd75, 0, 0 }, { 17, 0x1fd73, 0, 0 }, { 17, 0x1fd71, 0, 0 }, { 17, 0x1fd6f, 0, 0 }, { 17, 0x1fd6d, 0, 0 }, { 17, 0x1fd6b, 0, 0 }, { 17, 0x1fd69, 0, 0 }, { 17, 0x1fd67, 0, 0 }, { 17, 0x1fd65, 0, 0 }, { 17, 0x1fd63, 0, 0 }, { 17, 0x1fd61, 0, 0 }, { 17, 0x1fd5f, 0, 0 }, { 17, 0x1fd5d, 0, 0 }, { 17, 0x1fd5b, 0, 0 }, { 17, 0x1fd59, 0, 0 }, { 17, 0x1fd57, 0, 0 }, { 17, 0x1fd55, 0, 0 }, { 17, 0x1fd53, 0, 0 }, { 17, 0x1fd51, 0, 0 }, { 17, 0x1fd4f, 0, 0 }, { 17, 0x1fd4d, 0, 0 }, { 17, 0x1fd4b, 0, 0 }, { 17, 0x1fd49, 0, 0 }, { 17, 0x1fd47, 0, 0 }, { 17, 0x1fd45, 0, 0 }, { 17, 0x1fd43, 0, 0 }, { 17, 0x1fd41, 0, 0 }, { 17, 0x1fd3f, 0, 0 }, { 17, 0x1fd3d, 0, 0 }, { 17, 0x1fd3b, 0, 0 }, { 17, 0x1fd39, 0, 0 }, { 17, 0x1fd37, 0, 0 }, { 17, 0x1fd35, 0, 0 }, { 17, 0x1fd33, 0, 0 }, { 17, 0x1fd31, 0, 0 }, { 17, 0x1fd2f, 0, 0 }, { 17, 0x1fd2d, 0, 0 }, { 17, 0x1fd2b, 0, 0 }, { 17, 0x1fd29, 0, 0 }, { 17, 0x1fd27, 0, 0 }, { 17, 0x1fd25, 0, 0 }, { 17, 0x1fd23, 0, 0 }, { 17, 0x1fd21, 0, 0 }, { 17, 0x1fd1f, 0, 0 }, { 17, 0x1fd1d, 0, 0 }, { 17, 0x1fd1b, 0, 0 }, { 17, 0x1fd19, 0, 0 }, { 17, 0x1fd17, 0, 0 }, { 17, 0x1fd15, 0, 0 }, { 17, 0x1fd13, 0, 0 }, { 17, 0x1fd11, 0, 0 }, { 17, 0x1fd0f, 0, 0 }, { 17, 0x1fd0d, 0, 0 }, { 17, 0x1fd0b, 0, 0 }, { 17, 0x1fd09, 0, 0 }, { 17, 0x1fd07, 0, 0 }, { 17, 0x1fd05, 0, 0 }, { 17, 0x1fd03, 0, 0 }, { 17, 0x1fd01, 0, 0 }, { 17, 0x1fd01, 0, 0 } }, /* * prefixed with 1 zero */ { { 5, 0x17, 0, 0 }, { 8, 0xe7, 0, 0 }, { 8, 0xe5, 0, 0 }, { 9, 0x1d7, 0, 0 }, { 9, 0x1d5, 0, 0 }, { 9, 0x1d3, 0, 0 }, { 9, 0x1d1, 0, 0 }, { 12, 0xf8f, 0, 0 }, { 12, 0xf8d, 0, 0 }, { 12, 0xf8b, 0, 0 }, { 12, 0xf89, 0, 0 }, { 12, 0xf87, 0, 0 }, { 12, 0xf85, 0, 0 }, { 12, 0xf83, 0, 0 }, { 12, 0xf81, 0, 0 }, { 15, 0x7f1f, 0, 0 }, { 15, 0x7f1d, 0, 0 }, { 15, 0x7f1b, 0, 0 }, { 15, 0x7f19, 0, 0 }, { 15, 0x7f17, 0, 0 }, { 15, 0x7f15, 0, 0 }, { 15, 0x7f13, 0, 0 }, { 15, 0x7f11, 0, 0 }, { 15, 0x7f0f, 0, 0 }, { 15, 0x7f0d, 0, 0 }, { 15, 0x7f0b, 0, 0 }, { 15, 0x7f09, 0, 0 }, { 15, 0x7f07, 0, 0 }, { 15, 0x7f05, 0, 0 }, { 15, 0x7f03, 0, 0 }, { 15, 0x7f01, 0, 0 }, { 16, 0xfe7f, 0, 0 }, { 16, 0xfe7d, 0, 0 }, { 16, 0xfe7b, 0, 0 }, { 16, 0xfe79, 0, 0 }, { 16, 0xfe77, 0, 0 }, { 16, 0xfe75, 0, 0 }, { 16, 0xfe73, 0, 0 }, { 16, 0xfe71, 0, 0 }, { 16, 0xfe6f, 0, 0 }, { 16, 0xfe6d, 0, 0 }, { 16, 0xfe6b, 0, 0 }, { 16, 0xfe69, 0, 0 }, { 16, 0xfe67, 0, 0 }, { 16, 0xfe65, 0, 0 }, { 16, 0xfe63, 0, 0 }, { 16, 0xfe61, 0, 0 }, { 16, 0xfe5f, 0, 0 }, { 16, 0xfe5d, 0, 0 }, { 16, 0xfe5b, 0, 0 }, { 16, 0xfe59, 0, 0 }, { 16, 0xfe57, 0, 0 }, { 16, 0xfe55, 0, 0 }, { 16, 0xfe53, 0, 0 }, { 16, 0xfe51, 0, 0 }, { 16, 0xfe4f, 0, 0 }, { 16, 0xfe4d, 0, 0 }, { 16, 0xfe4b, 0, 0 }, { 16, 0xfe49, 0, 0 }, { 16, 0xfe47, 0, 0 }, { 16, 0xfe45, 0, 0 }, { 16, 0xfe43, 0, 0 }, { 16, 0xfe41, 0, 0 }, { 27, 0x7fffff9, 7, 0x7f }, { 27, 0x7fffff9, 7, 0x7d }, { 27, 0x7fffff9, 7, 0x7b }, { 27, 0x7fffff9, 7, 0x79 }, { 27, 0x7fffff9, 7, 0x77 }, { 27, 0x7fffff9, 7, 0x75 }, { 27, 0x7fffff9, 7, 0x73 }, { 27, 0x7fffff9, 7, 0x71 }, { 27, 0x7fffff9, 7, 0x6f }, { 27, 0x7fffff9, 7, 0x6d }, { 27, 0x7fffff9, 7, 0x6b }, { 27, 0x7fffff9, 7, 0x69 }, { 27, 0x7fffff9, 7, 0x67 }, { 27, 0x7fffff9, 7, 0x65 }, { 27, 0x7fffff9, 7, 0x63 }, { 27, 0x7fffff9, 7, 0x61 }, { 27, 0x7fffff9, 7, 0x5f }, { 27, 0x7fffff9, 7, 0x5d }, { 27, 0x7fffff9, 7, 0x5b }, { 27, 0x7fffff9, 7, 0x59 }, { 27, 0x7fffff9, 7, 0x57 }, { 27, 0x7fffff9, 7, 0x55 }, { 27, 0x7fffff9, 7, 0x53 }, { 27, 0x7fffff9, 7, 0x51 }, { 27, 0x7fffff9, 7, 0x4f }, { 27, 0x7fffff9, 7, 0x4d }, { 27, 0x7fffff9, 7, 0x4b }, { 27, 0x7fffff9, 7, 0x49 }, { 27, 0x7fffff9, 7, 0x47 }, { 27, 0x7fffff9, 7, 0x45 }, { 27, 0x7fffff9, 7, 0x43 }, { 27, 0x7fffff9, 7, 0x41 }, { 27, 0x7fffff9, 7, 0x3f }, { 27, 0x7fffff9, 7, 0x3d }, { 27, 0x7fffff9, 7, 0x3b }, { 27, 0x7fffff9, 7, 0x39 }, { 27, 0x7fffff9, 7, 0x37 }, { 27, 0x7fffff9, 7, 0x35 }, { 27, 0x7fffff9, 7, 0x33 }, { 27, 0x7fffff9, 7, 0x31 }, { 27, 0x7fffff9, 7, 0x2f }, { 27, 0x7fffff9, 7, 0x2d }, { 27, 0x7fffff9, 7, 0x2b }, { 27, 0x7fffff9, 7, 0x29 }, { 27, 0x7fffff9, 7, 0x27 }, { 27, 0x7fffff9, 7, 0x25 }, { 27, 0x7fffff9, 7, 0x23 }, { 27, 0x7fffff9, 7, 0x21 }, { 27, 0x7fffff9, 7, 0x1f }, { 27, 0x7fffff9, 7, 0x1d }, { 27, 0x7fffff9, 7, 0x1b }, { 27, 0x7fffff9, 7, 0x19 }, { 27, 0x7fffff9, 7, 0x17 }, { 27, 0x7fffff9, 7, 0x15 }, { 27, 0x7fffff9, 7, 0x13 }, { 27, 0x7fffff9, 7, 0x11 }, { 27, 0x7fffff9, 7, 0xf }, { 27, 0x7fffff9, 7, 0xd }, { 27, 0x7fffff9, 7, 0xb }, { 27, 0x7fffff9, 7, 0x9 }, { 27, 0x7fffff9, 7, 0x7 }, { 27, 0x7fffff9, 7, 0x5 }, { 27, 0x7fffff9, 7, 0x3 }, { 27, 0x7fffff9, 7, 0x1 }, { 27, 0x7fffff9, 7, 0x1 } }, /* * prefixed with 2 zeroes */ { { 6, 0x37, 0, 0 }, { 9, 0x1ef, 0, 0 }, { 9, 0x1ed, 0, 0 }, { 12, 0xfd7, 0, 0 }, { 12, 0xfd5, 0, 0 }, { 12, 0xfd3, 0, 0 }, { 12, 0xfd1, 0, 0 }, { 13, 0x1fbf, 0, 0 }, { 13, 0x1fbd, 0, 0 }, { 13, 0x1fbb, 0, 0 }, { 13, 0x1fb9, 0, 0 }, { 13, 0x1fb7, 0, 0 }, { 13, 0x1fb5, 0, 0 }, { 13, 0x1fb3, 0, 0 }, { 13, 0x1fb1, 0, 0 }, { 25, 0x1ffff7f, 0, 0 }, { 25, 0x1ffff7d, 0, 0 }, { 25, 0x1ffff7b, 0, 0 }, { 25, 0x1ffff79, 0, 0 }, { 25, 0x1ffff77, 0, 0 }, { 25, 0x1ffff75, 0, 0 }, { 25, 0x1ffff73, 0, 0 }, { 25, 0x1ffff71, 0, 0 }, { 25, 0x1ffff6f, 0, 0 }, { 25, 0x1ffff6d, 0, 0 }, { 25, 0x1ffff6b, 0, 0 }, { 25, 0x1ffff69, 0, 0 }, { 25, 0x1ffff67, 0, 0 }, { 25, 0x1ffff65, 0, 0 }, { 25, 0x1ffff63, 0, 0 }, { 25, 0x1ffff61, 0, 0 }, { 30, 0x3ffffe3f, 0, 0 }, { 30, 0x3ffffe3d, 0, 0 }, { 30, 0x3ffffe3b, 0, 0 }, { 30, 0x3ffffe39, 0, 0 }, { 30, 0x3ffffe37, 0, 0 }, { 30, 0x3ffffe35, 0, 0 }, { 30, 0x3ffffe33, 0, 0 }, { 30, 0x3ffffe31, 0, 0 }, { 30, 0x3ffffe2f, 0, 0 }, { 30, 0x3ffffe2d, 0, 0 }, { 30, 0x3ffffe2b, 0, 0 }, { 30, 0x3ffffe29, 0, 0 }, { 30, 0x3ffffe27, 0, 0 }, { 30, 0x3ffffe25, 0, 0 }, { 30, 0x3ffffe23, 0, 0 }, { 30, 0x3ffffe21, 0, 0 }, { 30, 0x3ffffe1f, 0, 0 }, { 30, 0x3ffffe1d, 0, 0 }, { 30, 0x3ffffe1b, 0, 0 }, { 30, 0x3ffffe19, 0, 0 }, { 30, 0x3ffffe17, 0, 0 }, { 30, 0x3ffffe15, 0, 0 }, { 30, 0x3ffffe13, 0, 0 }, { 30, 0x3ffffe11, 0, 0 }, { 30, 0x3ffffe0f, 0, 0 }, { 30, 0x3ffffe0d, 0, 0 }, { 30, 0x3ffffe0b, 0, 0 }, { 30, 0x3ffffe09, 0, 0 }, { 30, 0x3ffffe07, 0, 0 }, { 30, 0x3ffffe05, 0, 0 }, { 30, 0x3ffffe03, 0, 0 }, { 30, 0x3ffffe01, 0, 0 }, { 27, 0x7fffffa, 7, 0x7f }, { 27, 0x7fffffa, 7, 0x7d }, { 27, 0x7fffffa, 7, 0x7b }, { 27, 0x7fffffa, 7, 0x79 }, { 27, 0x7fffffa, 7, 0x77 }, { 27, 0x7fffffa, 7, 0x75 }, { 27, 0x7fffffa, 7, 0x73 }, { 27, 0x7fffffa, 7, 0x71 }, { 27, 0x7fffffa, 7, 0x6f }, { 27, 0x7fffffa, 7, 0x6d }, { 27, 0x7fffffa, 7, 0x6b }, { 27, 0x7fffffa, 7, 0x69 }, { 27, 0x7fffffa, 7, 0x67 }, { 27, 0x7fffffa, 7, 0x65 }, { 27, 0x7fffffa, 7, 0x63 }, { 27, 0x7fffffa, 7, 0x61 }, { 27, 0x7fffffa, 7, 0x5f }, { 27, 0x7fffffa, 7, 0x5d }, { 27, 0x7fffffa, 7, 0x5b }, { 27, 0x7fffffa, 7, 0x59 }, { 27, 0x7fffffa, 7, 0x57 }, { 27, 0x7fffffa, 7, 0x55 }, { 27, 0x7fffffa, 7, 0x53 }, { 27, 0x7fffffa, 7, 0x51 }, { 27, 0x7fffffa, 7, 0x4f }, { 27, 0x7fffffa, 7, 0x4d }, { 27, 0x7fffffa, 7, 0x4b }, { 27, 0x7fffffa, 7, 0x49 }, { 27, 0x7fffffa, 7, 0x47 }, { 27, 0x7fffffa, 7, 0x45 }, { 27, 0x7fffffa, 7, 0x43 }, { 27, 0x7fffffa, 7, 0x41 }, { 27, 0x7fffffa, 7, 0x3f }, { 27, 0x7fffffa, 7, 0x3d }, { 27, 0x7fffffa, 7, 0x3b }, { 27, 0x7fffffa, 7, 0x39 }, { 27, 0x7fffffa, 7, 0x37 }, { 27, 0x7fffffa, 7, 0x35 }, { 27, 0x7fffffa, 7, 0x33 }, { 27, 0x7fffffa, 7, 0x31 }, { 27, 0x7fffffa, 7, 0x2f }, { 27, 0x7fffffa, 7, 0x2d }, { 27, 0x7fffffa, 7, 0x2b }, { 27, 0x7fffffa, 7, 0x29 }, { 27, 0x7fffffa, 7, 0x27 }, { 27, 0x7fffffa, 7, 0x25 }, { 27, 0x7fffffa, 7, 0x23 }, { 27, 0x7fffffa, 7, 0x21 }, { 27, 0x7fffffa, 7, 0x1f }, { 27, 0x7fffffa, 7, 0x1d }, { 27, 0x7fffffa, 7, 0x1b }, { 27, 0x7fffffa, 7, 0x19 }, { 27, 0x7fffffa, 7, 0x17 }, { 27, 0x7fffffa, 7, 0x15 }, { 27, 0x7fffffa, 7, 0x13 }, { 27, 0x7fffffa, 7, 0x11 }, { 27, 0x7fffffa, 7, 0xf }, { 27, 0x7fffffa, 7, 0xd }, { 27, 0x7fffffa, 7, 0xb }, { 27, 0x7fffffa, 7, 0x9 }, { 27, 0x7fffffa, 7, 0x7 }, { 27, 0x7fffffa, 7, 0x5 }, { 27, 0x7fffffa, 7, 0x3 }, { 27, 0x7fffffa, 7, 0x1 }, { 27, 0x7fffffa, 7, 0x1 } }, /* * prefixed with 3 zeroes */ { { 7, 0x71, 0, 0 }, { 10, 0x3ef, 0, 0 }, { 10, 0x3ed, 0, 0 }, { 17, 0x1ffdf, 0, 0 }, { 17, 0x1ffdd, 0, 0 }, { 17, 0x1ffdb, 0, 0 }, { 17, 0x1ffd9, 0, 0 }, { 21, 0x1fffbf, 0, 0 }, { 21, 0x1fffbd, 0, 0 }, { 21, 0x1fffbb, 0, 0 }, { 21, 0x1fffb9, 0, 0 }, { 21, 0x1fffb7, 0, 0 }, { 21, 0x1fffb5, 0, 0 }, { 21, 0x1fffb3, 0, 0 }, { 21, 0x1fffb1, 0, 0 }, { 26, 0x3ffff1f, 0, 0 }, { 26, 0x3ffff1d, 0, 0 }, { 26, 0x3ffff1b, 0, 0 }, { 26, 0x3ffff19, 0, 0 }, { 26, 0x3ffff17, 0, 0 }, { 26, 0x3ffff15, 0, 0 }, { 26, 0x3ffff13, 0, 0 }, { 26, 0x3ffff11, 0, 0 }, { 26, 0x3ffff0f, 0, 0 }, { 26, 0x3ffff0d, 0, 0 }, { 26, 0x3ffff0b, 0, 0 }, { 26, 0x3ffff09, 0, 0 }, { 26, 0x3ffff07, 0, 0 }, { 26, 0x3ffff05, 0, 0 }, { 26, 0x3ffff03, 0, 0 }, { 26, 0x3ffff01, 0, 0 }, { 30, 0x3ffffe7f, 0, 0 }, { 30, 0x3ffffe7d, 0, 0 }, { 30, 0x3ffffe7b, 0, 0 }, { 30, 0x3ffffe79, 0, 0 }, { 30, 0x3ffffe77, 0, 0 }, { 30, 0x3ffffe75, 0, 0 }, { 30, 0x3ffffe73, 0, 0 }, { 30, 0x3ffffe71, 0, 0 }, { 30, 0x3ffffe6f, 0, 0 }, { 30, 0x3ffffe6d, 0, 0 }, { 30, 0x3ffffe6b, 0, 0 }, { 30, 0x3ffffe69, 0, 0 }, { 30, 0x3ffffe67, 0, 0 }, { 30, 0x3ffffe65, 0, 0 }, { 30, 0x3ffffe63, 0, 0 }, { 30, 0x3ffffe61, 0, 0 }, { 30, 0x3ffffe5f, 0, 0 }, { 30, 0x3ffffe5d, 0, 0 }, { 30, 0x3ffffe5b, 0, 0 }, { 30, 0x3ffffe59, 0, 0 }, { 30, 0x3ffffe57, 0, 0 }, { 30, 0x3ffffe55, 0, 0 }, { 30, 0x3ffffe53, 0, 0 }, { 30, 0x3ffffe51, 0, 0 }, { 30, 0x3ffffe4f, 0, 0 }, { 30, 0x3ffffe4d, 0, 0 }, { 30, 0x3ffffe4b, 0, 0 }, { 30, 0x3ffffe49, 0, 0 }, { 30, 0x3ffffe47, 0, 0 }, { 30, 0x3ffffe45, 0, 0 }, { 30, 0x3ffffe43, 0, 0 }, { 30, 0x3ffffe41, 0, 0 }, { 27, 0x7fffffb, 7, 0x7f }, { 27, 0x7fffffb, 7, 0x7d }, { 27, 0x7fffffb, 7, 0x7b }, { 27, 0x7fffffb, 7, 0x79 }, { 27, 0x7fffffb, 7, 0x77 }, { 27, 0x7fffffb, 7, 0x75 }, { 27, 0x7fffffb, 7, 0x73 }, { 27, 0x7fffffb, 7, 0x71 }, { 27, 0x7fffffb, 7, 0x6f }, { 27, 0x7fffffb, 7, 0x6d }, { 27, 0x7fffffb, 7, 0x6b }, { 27, 0x7fffffb, 7, 0x69 }, { 27, 0x7fffffb, 7, 0x67 }, { 27, 0x7fffffb, 7, 0x65 }, { 27, 0x7fffffb, 7, 0x63 }, { 27, 0x7fffffb, 7, 0x61 }, { 27, 0x7fffffb, 7, 0x5f }, { 27, 0x7fffffb, 7, 0x5d }, { 27, 0x7fffffb, 7, 0x5b }, { 27, 0x7fffffb, 7, 0x59 }, { 27, 0x7fffffb, 7, 0x57 }, { 27, 0x7fffffb, 7, 0x55 }, { 27, 0x7fffffb, 7, 0x53 }, { 27, 0x7fffffb, 7, 0x51 }, { 27, 0x7fffffb, 7, 0x4f }, { 27, 0x7fffffb, 7, 0x4d }, { 27, 0x7fffffb, 7, 0x4b }, { 27, 0x7fffffb, 7, 0x49 }, { 27, 0x7fffffb, 7, 0x47 }, { 27, 0x7fffffb, 7, 0x45 }, { 27, 0x7fffffb, 7, 0x43 }, { 27, 0x7fffffb, 7, 0x41 }, { 27, 0x7fffffb, 7, 0x3f }, { 27, 0x7fffffb, 7, 0x3d }, { 27, 0x7fffffb, 7, 0x3b }, { 27, 0x7fffffb, 7, 0x39 }, { 27, 0x7fffffb, 7, 0x37 }, { 27, 0x7fffffb, 7, 0x35 }, { 27, 0x7fffffb, 7, 0x33 }, { 27, 0x7fffffb, 7, 0x31 }, { 27, 0x7fffffb, 7, 0x2f }, { 27, 0x7fffffb, 7, 0x2d }, { 27, 0x7fffffb, 7, 0x2b }, { 27, 0x7fffffb, 7, 0x29 }, { 27, 0x7fffffb, 7, 0x27 }, { 27, 0x7fffffb, 7, 0x25 }, { 27, 0x7fffffb, 7, 0x23 }, { 27, 0x7fffffb, 7, 0x21 }, { 27, 0x7fffffb, 7, 0x1f }, { 27, 0x7fffffb, 7, 0x1d }, { 27, 0x7fffffb, 7, 0x1b }, { 27, 0x7fffffb, 7, 0x19 }, { 27, 0x7fffffb, 7, 0x17 }, { 27, 0x7fffffb, 7, 0x15 }, { 27, 0x7fffffb, 7, 0x13 }, { 27, 0x7fffffb, 7, 0x11 }, { 27, 0x7fffffb, 7, 0xf }, { 27, 0x7fffffb, 7, 0xd }, { 27, 0x7fffffb, 7, 0xb }, { 27, 0x7fffffb, 7, 0x9 }, { 27, 0x7fffffb, 7, 0x7 }, { 27, 0x7fffffb, 7, 0x5 }, { 27, 0x7fffffb, 7, 0x3 }, { 27, 0x7fffffb, 7, 0x1 }, { 27, 0x7fffffb, 7, 0x1 } }, /* * prefixed with 4 zeroes */ { { 8, 0xf1, 0, 0 }, { 11, 0x7e3, 0, 0 }, { 11, 0x7e1, 0, 0 }, { 18, 0x3ffc7, 0, 0 }, { 18, 0x3ffc5, 0, 0 }, { 18, 0x3ffc3, 0, 0 }, { 18, 0x3ffc1, 0, 0 }, { 22, 0x3fff8f, 0, 0 }, { 22, 0x3fff8d, 0, 0 }, { 22, 0x3fff8b, 0, 0 }, { 22, 0x3fff89, 0, 0 }, { 22, 0x3fff87, 0, 0 }, { 22, 0x3fff85, 0, 0 }, { 22, 0x3fff83, 0, 0 }, { 22, 0x3fff81, 0, 0 }, { 26, 0x3ffff3f, 0, 0 }, { 26, 0x3ffff3d, 0, 0 }, { 26, 0x3ffff3b, 0, 0 }, { 26, 0x3ffff39, 0, 0 }, { 26, 0x3ffff37, 0, 0 }, { 26, 0x3ffff35, 0, 0 }, { 26, 0x3ffff33, 0, 0 }, { 26, 0x3ffff31, 0, 0 }, { 26, 0x3ffff2f, 0, 0 }, { 26, 0x3ffff2d, 0, 0 }, { 26, 0x3ffff2b, 0, 0 }, { 26, 0x3ffff29, 0, 0 }, { 26, 0x3ffff27, 0, 0 }, { 26, 0x3ffff25, 0, 0 }, { 26, 0x3ffff23, 0, 0 }, { 26, 0x3ffff21, 0, 0 }, { 30, 0x3ffffebf, 0, 0 }, { 30, 0x3ffffebd, 0, 0 }, { 30, 0x3ffffebb, 0, 0 }, { 30, 0x3ffffeb9, 0, 0 }, { 30, 0x3ffffeb7, 0, 0 }, { 30, 0x3ffffeb5, 0, 0 }, { 30, 0x3ffffeb3, 0, 0 }, { 30, 0x3ffffeb1, 0, 0 }, { 30, 0x3ffffeaf, 0, 0 }, { 30, 0x3ffffead, 0, 0 }, { 30, 0x3ffffeab, 0, 0 }, { 30, 0x3ffffea9, 0, 0 }, { 30, 0x3ffffea7, 0, 0 }, { 30, 0x3ffffea5, 0, 0 }, { 30, 0x3ffffea3, 0, 0 }, { 30, 0x3ffffea1, 0, 0 }, { 30, 0x3ffffe9f, 0, 0 }, { 30, 0x3ffffe9d, 0, 0 }, { 30, 0x3ffffe9b, 0, 0 }, { 30, 0x3ffffe99, 0, 0 }, { 30, 0x3ffffe97, 0, 0 }, { 30, 0x3ffffe95, 0, 0 }, { 30, 0x3ffffe93, 0, 0 }, { 30, 0x3ffffe91, 0, 0 }, { 30, 0x3ffffe8f, 0, 0 }, { 30, 0x3ffffe8d, 0, 0 }, { 30, 0x3ffffe8b, 0, 0 }, { 30, 0x3ffffe89, 0, 0 }, { 30, 0x3ffffe87, 0, 0 }, { 30, 0x3ffffe85, 0, 0 }, { 30, 0x3ffffe83, 0, 0 }, { 30, 0x3ffffe81, 0, 0 }, { 28, 0xffffff8, 7, 0x7f }, { 28, 0xffffff8, 7, 0x7d }, { 28, 0xffffff8, 7, 0x7b }, { 28, 0xffffff8, 7, 0x79 }, { 28, 0xffffff8, 7, 0x77 }, { 28, 0xffffff8, 7, 0x75 }, { 28, 0xffffff8, 7, 0x73 }, { 28, 0xffffff8, 7, 0x71 }, { 28, 0xffffff8, 7, 0x6f }, { 28, 0xffffff8, 7, 0x6d }, { 28, 0xffffff8, 7, 0x6b }, { 28, 0xffffff8, 7, 0x69 }, { 28, 0xffffff8, 7, 0x67 }, { 28, 0xffffff8, 7, 0x65 }, { 28, 0xffffff8, 7, 0x63 }, { 28, 0xffffff8, 7, 0x61 }, { 28, 0xffffff8, 7, 0x5f }, { 28, 0xffffff8, 7, 0x5d }, { 28, 0xffffff8, 7, 0x5b }, { 28, 0xffffff8, 7, 0x59 }, { 28, 0xffffff8, 7, 0x57 }, { 28, 0xffffff8, 7, 0x55 }, { 28, 0xffffff8, 7, 0x53 }, { 28, 0xffffff8, 7, 0x51 }, { 28, 0xffffff8, 7, 0x4f }, { 28, 0xffffff8, 7, 0x4d }, { 28, 0xffffff8, 7, 0x4b }, { 28, 0xffffff8, 7, 0x49 }, { 28, 0xffffff8, 7, 0x47 }, { 28, 0xffffff8, 7, 0x45 }, { 28, 0xffffff8, 7, 0x43 }, { 28, 0xffffff8, 7, 0x41 }, { 28, 0xffffff8, 7, 0x3f }, { 28, 0xffffff8, 7, 0x3d }, { 28, 0xffffff8, 7, 0x3b }, { 28, 0xffffff8, 7, 0x39 }, { 28, 0xffffff8, 7, 0x37 }, { 28, 0xffffff8, 7, 0x35 }, { 28, 0xffffff8, 7, 0x33 }, { 28, 0xffffff8, 7, 0x31 }, { 28, 0xffffff8, 7, 0x2f }, { 28, 0xffffff8, 7, 0x2d }, { 28, 0xffffff8, 7, 0x2b }, { 28, 0xffffff8, 7, 0x29 }, { 28, 0xffffff8, 7, 0x27 }, { 28, 0xffffff8, 7, 0x25 }, { 28, 0xffffff8, 7, 0x23 }, { 28, 0xffffff8, 7, 0x21 }, { 28, 0xffffff8, 7, 0x1f }, { 28, 0xffffff8, 7, 0x1d }, { 28, 0xffffff8, 7, 0x1b }, { 28, 0xffffff8, 7, 0x19 }, { 28, 0xffffff8, 7, 0x17 }, { 28, 0xffffff8, 7, 0x15 }, { 28, 0xffffff8, 7, 0x13 }, { 28, 0xffffff8, 7, 0x11 }, { 28, 0xffffff8, 7, 0xf }, { 28, 0xffffff8, 7, 0xd }, { 28, 0xffffff8, 7, 0xb }, { 28, 0xffffff8, 7, 0x9 }, { 28, 0xffffff8, 7, 0x7 }, { 28, 0xffffff8, 7, 0x5 }, { 28, 0xffffff8, 7, 0x3 }, { 28, 0xffffff8, 7, 0x1 }, { 0, 0, 0, 0 } }, /* * prefixed with 5 zeroes */ { { 8, 0xf3, 0, 0 }, { 11, 0x7e7, 0, 0 }, { 11, 0x7e5, 0, 0 }, { 18, 0x3ffcf, 0, 0 }, { 18, 0x3ffcd, 0, 0 }, { 18, 0x3ffcb, 0, 0 }, { 18, 0x3ffc9, 0, 0 }, { 22, 0x3fff9f, 0, 0 }, { 22, 0x3fff9d, 0, 0 }, { 22, 0x3fff9b, 0, 0 }, { 22, 0x3fff99, 0, 0 }, { 22, 0x3fff97, 0, 0 }, { 22, 0x3fff95, 0, 0 }, { 22, 0x3fff93, 0, 0 }, { 22, 0x3fff91, 0, 0 }, { 26, 0x3ffff5f, 0, 0 }, { 26, 0x3ffff5d, 0, 0 }, { 26, 0x3ffff5b, 0, 0 }, { 26, 0x3ffff59, 0, 0 }, { 26, 0x3ffff57, 0, 0 }, { 26, 0x3ffff55, 0, 0 }, { 26, 0x3ffff53, 0, 0 }, { 26, 0x3ffff51, 0, 0 }, { 26, 0x3ffff4f, 0, 0 }, { 26, 0x3ffff4d, 0, 0 }, { 26, 0x3ffff4b, 0, 0 }, { 26, 0x3ffff49, 0, 0 }, { 26, 0x3ffff47, 0, 0 }, { 26, 0x3ffff45, 0, 0 }, { 26, 0x3ffff43, 0, 0 }, { 26, 0x3ffff41, 0, 0 }, { 30, 0x3ffffeff, 0, 0 }, { 30, 0x3ffffefd, 0, 0 }, { 30, 0x3ffffefb, 0, 0 }, { 30, 0x3ffffef9, 0, 0 }, { 30, 0x3ffffef7, 0, 0 }, { 30, 0x3ffffef5, 0, 0 }, { 30, 0x3ffffef3, 0, 0 }, { 30, 0x3ffffef1, 0, 0 }, { 30, 0x3ffffeef, 0, 0 }, { 30, 0x3ffffeed, 0, 0 }, { 30, 0x3ffffeeb, 0, 0 }, { 30, 0x3ffffee9, 0, 0 }, { 30, 0x3ffffee7, 0, 0 }, { 30, 0x3ffffee5, 0, 0 }, { 30, 0x3ffffee3, 0, 0 }, { 30, 0x3ffffee1, 0, 0 }, { 30, 0x3ffffedf, 0, 0 }, { 30, 0x3ffffedd, 0, 0 }, { 30, 0x3ffffedb, 0, 0 }, { 30, 0x3ffffed9, 0, 0 }, { 30, 0x3ffffed7, 0, 0 }, { 30, 0x3ffffed5, 0, 0 }, { 30, 0x3ffffed3, 0, 0 }, { 30, 0x3ffffed1, 0, 0 }, { 30, 0x3ffffecf, 0, 0 }, { 30, 0x3ffffecd, 0, 0 }, { 30, 0x3ffffecb, 0, 0 }, { 30, 0x3ffffec9, 0, 0 }, { 30, 0x3ffffec7, 0, 0 }, { 30, 0x3ffffec5, 0, 0 }, { 30, 0x3ffffec3, 0, 0 }, { 30, 0x3ffffec1, 0, 0 }, { 28, 0xffffff9, 7, 0x7f }, { 28, 0xffffff9, 7, 0x7d }, { 28, 0xffffff9, 7, 0x7b }, { 28, 0xffffff9, 7, 0x79 }, { 28, 0xffffff9, 7, 0x77 }, { 28, 0xffffff9, 7, 0x75 }, { 28, 0xffffff9, 7, 0x73 }, { 28, 0xffffff9, 7, 0x71 }, { 28, 0xffffff9, 7, 0x6f }, { 28, 0xffffff9, 7, 0x6d }, { 28, 0xffffff9, 7, 0x6b }, { 28, 0xffffff9, 7, 0x69 }, { 28, 0xffffff9, 7, 0x67 }, { 28, 0xffffff9, 7, 0x65 }, { 28, 0xffffff9, 7, 0x63 }, { 28, 0xffffff9, 7, 0x61 }, { 28, 0xffffff9, 7, 0x5f }, { 28, 0xffffff9, 7, 0x5d }, { 28, 0xffffff9, 7, 0x5b }, { 28, 0xffffff9, 7, 0x59 }, { 28, 0xffffff9, 7, 0x57 }, { 28, 0xffffff9, 7, 0x55 }, { 28, 0xffffff9, 7, 0x53 }, { 28, 0xffffff9, 7, 0x51 }, { 28, 0xffffff9, 7, 0x4f }, { 28, 0xffffff9, 7, 0x4d }, { 28, 0xffffff9, 7, 0x4b }, { 28, 0xffffff9, 7, 0x49 }, { 28, 0xffffff9, 7, 0x47 }, { 28, 0xffffff9, 7, 0x45 }, { 28, 0xffffff9, 7, 0x43 }, { 28, 0xffffff9, 7, 0x41 }, { 28, 0xffffff9, 7, 0x3f }, { 28, 0xffffff9, 7, 0x3d }, { 28, 0xffffff9, 7, 0x3b }, { 28, 0xffffff9, 7, 0x39 }, { 28, 0xffffff9, 7, 0x37 }, { 28, 0xffffff9, 7, 0x35 }, { 28, 0xffffff9, 7, 0x33 }, { 28, 0xffffff9, 7, 0x31 }, { 28, 0xffffff9, 7, 0x2f }, { 28, 0xffffff9, 7, 0x2d }, { 28, 0xffffff9, 7, 0x2b }, { 28, 0xffffff9, 7, 0x29 }, { 28, 0xffffff9, 7, 0x27 }, { 28, 0xffffff9, 7, 0x25 }, { 28, 0xffffff9, 7, 0x23 }, { 28, 0xffffff9, 7, 0x21 }, { 28, 0xffffff9, 7, 0x1f }, { 28, 0xffffff9, 7, 0x1d }, { 28, 0xffffff9, 7, 0x1b }, { 28, 0xffffff9, 7, 0x19 }, { 28, 0xffffff9, 7, 0x17 }, { 28, 0xffffff9, 7, 0x15 }, { 28, 0xffffff9, 7, 0x13 }, { 28, 0xffffff9, 7, 0x11 }, { 28, 0xffffff9, 7, 0xf }, { 28, 0xffffff9, 7, 0xd }, { 28, 0xffffff9, 7, 0xb }, { 28, 0xffffff9, 7, 0x9 }, { 28, 0xffffff9, 7, 0x7 }, { 28, 0xffffff9, 7, 0x5 }, { 28, 0xffffff9, 7, 0x3 }, { 28, 0xffffff9, 7, 0x1 }, { 0, 0, 0, 0 } }, /* * prefixed with 6 zeroes */ { { 8, 0xf5, 0, 0 }, { 14, 0x3feb, 0, 0 }, { 14, 0x3fe9, 0, 0 }, { 18, 0x3ffd7, 0, 0 }, { 18, 0x3ffd5, 0, 0 }, { 18, 0x3ffd3, 0, 0 }, { 18, 0x3ffd1, 0, 0 }, { 22, 0x3fffaf, 0, 0 }, { 22, 0x3fffad, 0, 0 }, { 22, 0x3fffab, 0, 0 }, { 22, 0x3fffa9, 0, 0 }, { 22, 0x3fffa7, 0, 0 }, { 22, 0x3fffa5, 0, 0 }, { 22, 0x3fffa3, 0, 0 }, { 22, 0x3fffa1, 0, 0 }, { 26, 0x3ffff7f, 0, 0 }, { 26, 0x3ffff7d, 0, 0 }, { 26, 0x3ffff7b, 0, 0 }, { 26, 0x3ffff79, 0, 0 }, { 26, 0x3ffff77, 0, 0 }, { 26, 0x3ffff75, 0, 0 }, { 26, 0x3ffff73, 0, 0 }, { 26, 0x3ffff71, 0, 0 }, { 26, 0x3ffff6f, 0, 0 }, { 26, 0x3ffff6d, 0, 0 }, { 26, 0x3ffff6b, 0, 0 }, { 26, 0x3ffff69, 0, 0 }, { 26, 0x3ffff67, 0, 0 }, { 26, 0x3ffff65, 0, 0 }, { 26, 0x3ffff63, 0, 0 }, { 26, 0x3ffff61, 0, 0 }, { 31, 0x7ffffe3f, 0, 0 }, { 31, 0x7ffffe3d, 0, 0 }, { 31, 0x7ffffe3b, 0, 0 }, { 31, 0x7ffffe39, 0, 0 }, { 31, 0x7ffffe37, 0, 0 }, { 31, 0x7ffffe35, 0, 0 }, { 31, 0x7ffffe33, 0, 0 }, { 31, 0x7ffffe31, 0, 0 }, { 31, 0x7ffffe2f, 0, 0 }, { 31, 0x7ffffe2d, 0, 0 }, { 31, 0x7ffffe2b, 0, 0 }, { 31, 0x7ffffe29, 0, 0 }, { 31, 0x7ffffe27, 0, 0 }, { 31, 0x7ffffe25, 0, 0 }, { 31, 0x7ffffe23, 0, 0 }, { 31, 0x7ffffe21, 0, 0 }, { 31, 0x7ffffe1f, 0, 0 }, { 31, 0x7ffffe1d, 0, 0 }, { 31, 0x7ffffe1b, 0, 0 }, { 31, 0x7ffffe19, 0, 0 }, { 31, 0x7ffffe17, 0, 0 }, { 31, 0x7ffffe15, 0, 0 }, { 31, 0x7ffffe13, 0, 0 }, { 31, 0x7ffffe11, 0, 0 }, { 31, 0x7ffffe0f, 0, 0 }, { 31, 0x7ffffe0d, 0, 0 }, { 31, 0x7ffffe0b, 0, 0 }, { 31, 0x7ffffe09, 0, 0 }, { 31, 0x7ffffe07, 0, 0 }, { 31, 0x7ffffe05, 0, 0 }, { 31, 0x7ffffe03, 0, 0 }, { 31, 0x7ffffe01, 0, 0 }, { 28, 0xffffffa, 7, 0x7f }, { 28, 0xffffffa, 7, 0x7d }, { 28, 0xffffffa, 7, 0x7b }, { 28, 0xffffffa, 7, 0x79 }, { 28, 0xffffffa, 7, 0x77 }, { 28, 0xffffffa, 7, 0x75 }, { 28, 0xffffffa, 7, 0x73 }, { 28, 0xffffffa, 7, 0x71 }, { 28, 0xffffffa, 7, 0x6f }, { 28, 0xffffffa, 7, 0x6d }, { 28, 0xffffffa, 7, 0x6b }, { 28, 0xffffffa, 7, 0x69 }, { 28, 0xffffffa, 7, 0x67 }, { 28, 0xffffffa, 7, 0x65 }, { 28, 0xffffffa, 7, 0x63 }, { 28, 0xffffffa, 7, 0x61 }, { 28, 0xffffffa, 7, 0x5f }, { 28, 0xffffffa, 7, 0x5d }, { 28, 0xffffffa, 7, 0x5b }, { 28, 0xffffffa, 7, 0x59 }, { 28, 0xffffffa, 7, 0x57 }, { 28, 0xffffffa, 7, 0x55 }, { 28, 0xffffffa, 7, 0x53 }, { 28, 0xffffffa, 7, 0x51 }, { 28, 0xffffffa, 7, 0x4f }, { 28, 0xffffffa, 7, 0x4d }, { 28, 0xffffffa, 7, 0x4b }, { 28, 0xffffffa, 7, 0x49 }, { 28, 0xffffffa, 7, 0x47 }, { 28, 0xffffffa, 7, 0x45 }, { 28, 0xffffffa, 7, 0x43 }, { 28, 0xffffffa, 7, 0x41 }, { 28, 0xffffffa, 7, 0x3f }, { 28, 0xffffffa, 7, 0x3d }, { 28, 0xffffffa, 7, 0x3b }, { 28, 0xffffffa, 7, 0x39 }, { 28, 0xffffffa, 7, 0x37 }, { 28, 0xffffffa, 7, 0x35 }, { 28, 0xffffffa, 7, 0x33 }, { 28, 0xffffffa, 7, 0x31 }, { 28, 0xffffffa, 7, 0x2f }, { 28, 0xffffffa, 7, 0x2d }, { 28, 0xffffffa, 7, 0x2b }, { 28, 0xffffffa, 7, 0x29 }, { 28, 0xffffffa, 7, 0x27 }, { 28, 0xffffffa, 7, 0x25 }, { 28, 0xffffffa, 7, 0x23 }, { 28, 0xffffffa, 7, 0x21 }, { 28, 0xffffffa, 7, 0x1f }, { 28, 0xffffffa, 7, 0x1d }, { 28, 0xffffffa, 7, 0x1b }, { 28, 0xffffffa, 7, 0x19 }, { 28, 0xffffffa, 7, 0x17 }, { 28, 0xffffffa, 7, 0x15 }, { 28, 0xffffffa, 7, 0x13 }, { 28, 0xffffffa, 7, 0x11 }, { 28, 0xffffffa, 7, 0xf }, { 28, 0xffffffa, 7, 0xd }, { 28, 0xffffffa, 7, 0xb }, { 28, 0xffffffa, 7, 0x9 }, { 28, 0xffffffa, 7, 0x7 }, { 28, 0xffffffa, 7, 0x5 }, { 28, 0xffffffa, 7, 0x3 }, { 28, 0xffffffa, 7, 0x1 }, { 0, 0, 0, 0 } }, /* * prefixed with 7 zeroes */ { { 9, 0x1f3, 0, 0 }, { 14, 0x3fef, 0, 0 }, { 14, 0x3fed, 0, 0 }, { 18, 0x3ffdf, 0, 0 }, { 18, 0x3ffdd, 0, 0 }, { 18, 0x3ffdb, 0, 0 }, { 18, 0x3ffd9, 0, 0 }, { 22, 0x3fffbf, 0, 0 }, { 22, 0x3fffbd, 0, 0 }, { 22, 0x3fffbb, 0, 0 }, { 22, 0x3fffb9, 0, 0 }, { 22, 0x3fffb7, 0, 0 }, { 22, 0x3fffb5, 0, 0 }, { 22, 0x3fffb3, 0, 0 }, { 22, 0x3fffb1, 0, 0 }, { 27, 0x7ffff1f, 0, 0 }, { 27, 0x7ffff1d, 0, 0 }, { 27, 0x7ffff1b, 0, 0 }, { 27, 0x7ffff19, 0, 0 }, { 27, 0x7ffff17, 0, 0 }, { 27, 0x7ffff15, 0, 0 }, { 27, 0x7ffff13, 0, 0 }, { 27, 0x7ffff11, 0, 0 }, { 27, 0x7ffff0f, 0, 0 }, { 27, 0x7ffff0d, 0, 0 }, { 27, 0x7ffff0b, 0, 0 }, { 27, 0x7ffff09, 0, 0 }, { 27, 0x7ffff07, 0, 0 }, { 27, 0x7ffff05, 0, 0 }, { 27, 0x7ffff03, 0, 0 }, { 27, 0x7ffff01, 0, 0 }, { 31, 0x7ffffe7f, 0, 0 }, { 31, 0x7ffffe7d, 0, 0 }, { 31, 0x7ffffe7b, 0, 0 }, { 31, 0x7ffffe79, 0, 0 }, { 31, 0x7ffffe77, 0, 0 }, { 31, 0x7ffffe75, 0, 0 }, { 31, 0x7ffffe73, 0, 0 }, { 31, 0x7ffffe71, 0, 0 }, { 31, 0x7ffffe6f, 0, 0 }, { 31, 0x7ffffe6d, 0, 0 }, { 31, 0x7ffffe6b, 0, 0 }, { 31, 0x7ffffe69, 0, 0 }, { 31, 0x7ffffe67, 0, 0 }, { 31, 0x7ffffe65, 0, 0 }, { 31, 0x7ffffe63, 0, 0 }, { 31, 0x7ffffe61, 0, 0 }, { 31, 0x7ffffe5f, 0, 0 }, { 31, 0x7ffffe5d, 0, 0 }, { 31, 0x7ffffe5b, 0, 0 }, { 31, 0x7ffffe59, 0, 0 }, { 31, 0x7ffffe57, 0, 0 }, { 31, 0x7ffffe55, 0, 0 }, { 31, 0x7ffffe53, 0, 0 }, { 31, 0x7ffffe51, 0, 0 }, { 31, 0x7ffffe4f, 0, 0 }, { 31, 0x7ffffe4d, 0, 0 }, { 31, 0x7ffffe4b, 0, 0 }, { 31, 0x7ffffe49, 0, 0 }, { 31, 0x7ffffe47, 0, 0 }, { 31, 0x7ffffe45, 0, 0 }, { 31, 0x7ffffe43, 0, 0 }, { 31, 0x7ffffe41, 0, 0 }, { 28, 0xffffffb, 7, 0x7f }, { 28, 0xffffffb, 7, 0x7d }, { 28, 0xffffffb, 7, 0x7b }, { 28, 0xffffffb, 7, 0x79 }, { 28, 0xffffffb, 7, 0x77 }, { 28, 0xffffffb, 7, 0x75 }, { 28, 0xffffffb, 7, 0x73 }, { 28, 0xffffffb, 7, 0x71 }, { 28, 0xffffffb, 7, 0x6f }, { 28, 0xffffffb, 7, 0x6d }, { 28, 0xffffffb, 7, 0x6b }, { 28, 0xffffffb, 7, 0x69 }, { 28, 0xffffffb, 7, 0x67 }, { 28, 0xffffffb, 7, 0x65 }, { 28, 0xffffffb, 7, 0x63 }, { 28, 0xffffffb, 7, 0x61 }, { 28, 0xffffffb, 7, 0x5f }, { 28, 0xffffffb, 7, 0x5d }, { 28, 0xffffffb, 7, 0x5b }, { 28, 0xffffffb, 7, 0x59 }, { 28, 0xffffffb, 7, 0x57 }, { 28, 0xffffffb, 7, 0x55 }, { 28, 0xffffffb, 7, 0x53 }, { 28, 0xffffffb, 7, 0x51 }, { 28, 0xffffffb, 7, 0x4f }, { 28, 0xffffffb, 7, 0x4d }, { 28, 0xffffffb, 7, 0x4b }, { 28, 0xffffffb, 7, 0x49 }, { 28, 0xffffffb, 7, 0x47 }, { 28, 0xffffffb, 7, 0x45 }, { 28, 0xffffffb, 7, 0x43 }, { 28, 0xffffffb, 7, 0x41 }, { 28, 0xffffffb, 7, 0x3f }, { 28, 0xffffffb, 7, 0x3d }, { 28, 0xffffffb, 7, 0x3b }, { 28, 0xffffffb, 7, 0x39 }, { 28, 0xffffffb, 7, 0x37 }, { 28, 0xffffffb, 7, 0x35 }, { 28, 0xffffffb, 7, 0x33 }, { 28, 0xffffffb, 7, 0x31 }, { 28, 0xffffffb, 7, 0x2f }, { 28, 0xffffffb, 7, 0x2d }, { 28, 0xffffffb, 7, 0x2b }, { 28, 0xffffffb, 7, 0x29 }, { 28, 0xffffffb, 7, 0x27 }, { 28, 0xffffffb, 7, 0x25 }, { 28, 0xffffffb, 7, 0x23 }, { 28, 0xffffffb, 7, 0x21 }, { 28, 0xffffffb, 7, 0x1f }, { 28, 0xffffffb, 7, 0x1d }, { 28, 0xffffffb, 7, 0x1b }, { 28, 0xffffffb, 7, 0x19 }, { 28, 0xffffffb, 7, 0x17 }, { 28, 0xffffffb, 7, 0x15 }, { 28, 0xffffffb, 7, 0x13 }, { 28, 0xffffffb, 7, 0x11 }, { 28, 0xffffffb, 7, 0xf }, { 28, 0xffffffb, 7, 0xd }, { 28, 0xffffffb, 7, 0xb }, { 28, 0xffffffb, 7, 0x9 }, { 28, 0xffffffb, 7, 0x7 }, { 28, 0xffffffb, 7, 0x5 }, { 28, 0xffffffb, 7, 0x3 }, { 28, 0xffffffb, 7, 0x1 }, { 0, 0, 0, 0 } }, /* * prefixed with 8 zeroes */ { { 9, 0x1f5, 0, 0 }, { 15, 0x7fe3, 0, 0 }, { 15, 0x7fe1, 0, 0 }, { 19, 0x7ffc7, 0, 0 }, { 19, 0x7ffc5, 0, 0 }, { 19, 0x7ffc3, 0, 0 }, { 19, 0x7ffc1, 0, 0 }, { 23, 0x7fff8f, 0, 0 }, { 23, 0x7fff8d, 0, 0 }, { 23, 0x7fff8b, 0, 0 }, { 23, 0x7fff89, 0, 0 }, { 23, 0x7fff87, 0, 0 }, { 23, 0x7fff85, 0, 0 }, { 23, 0x7fff83, 0, 0 }, { 23, 0x7fff81, 0, 0 }, { 27, 0x7ffff3f, 0, 0 }, { 27, 0x7ffff3d, 0, 0 }, { 27, 0x7ffff3b, 0, 0 }, { 27, 0x7ffff39, 0, 0 }, { 27, 0x7ffff37, 0, 0 }, { 27, 0x7ffff35, 0, 0 }, { 27, 0x7ffff33, 0, 0 }, { 27, 0x7ffff31, 0, 0 }, { 27, 0x7ffff2f, 0, 0 }, { 27, 0x7ffff2d, 0, 0 }, { 27, 0x7ffff2b, 0, 0 }, { 27, 0x7ffff29, 0, 0 }, { 27, 0x7ffff27, 0, 0 }, { 27, 0x7ffff25, 0, 0 }, { 27, 0x7ffff23, 0, 0 }, { 27, 0x7ffff21, 0, 0 }, { 31, 0x7ffffebf, 0, 0 }, { 31, 0x7ffffebd, 0, 0 }, { 31, 0x7ffffebb, 0, 0 }, { 31, 0x7ffffeb9, 0, 0 }, { 31, 0x7ffffeb7, 0, 0 }, { 31, 0x7ffffeb5, 0, 0 }, { 31, 0x7ffffeb3, 0, 0 }, { 31, 0x7ffffeb1, 0, 0 }, { 31, 0x7ffffeaf, 0, 0 }, { 31, 0x7ffffead, 0, 0 }, { 31, 0x7ffffeab, 0, 0 }, { 31, 0x7ffffea9, 0, 0 }, { 31, 0x7ffffea7, 0, 0 }, { 31, 0x7ffffea5, 0, 0 }, { 31, 0x7ffffea3, 0, 0 }, { 31, 0x7ffffea1, 0, 0 }, { 31, 0x7ffffe9f, 0, 0 }, { 31, 0x7ffffe9d, 0, 0 }, { 31, 0x7ffffe9b, 0, 0 }, { 31, 0x7ffffe99, 0, 0 }, { 31, 0x7ffffe97, 0, 0 }, { 31, 0x7ffffe95, 0, 0 }, { 31, 0x7ffffe93, 0, 0 }, { 31, 0x7ffffe91, 0, 0 }, { 31, 0x7ffffe8f, 0, 0 }, { 31, 0x7ffffe8d, 0, 0 }, { 31, 0x7ffffe8b, 0, 0 }, { 31, 0x7ffffe89, 0, 0 }, { 31, 0x7ffffe87, 0, 0 }, { 31, 0x7ffffe85, 0, 0 }, { 31, 0x7ffffe83, 0, 0 }, { 31, 0x7ffffe81, 0, 0 }, { 29, 0x1ffffff8, 7, 0x7f }, { 29, 0x1ffffff8, 7, 0x7d }, { 29, 0x1ffffff8, 7, 0x7b }, { 29, 0x1ffffff8, 7, 0x79 }, { 29, 0x1ffffff8, 7, 0x77 }, { 29, 0x1ffffff8, 7, 0x75 }, { 29, 0x1ffffff8, 7, 0x73 }, { 29, 0x1ffffff8, 7, 0x71 }, { 29, 0x1ffffff8, 7, 0x6f }, { 29, 0x1ffffff8, 7, 0x6d }, { 29, 0x1ffffff8, 7, 0x6b }, { 29, 0x1ffffff8, 7, 0x69 }, { 29, 0x1ffffff8, 7, 0x67 }, { 29, 0x1ffffff8, 7, 0x65 }, { 29, 0x1ffffff8, 7, 0x63 }, { 29, 0x1ffffff8, 7, 0x61 }, { 29, 0x1ffffff8, 7, 0x5f }, { 29, 0x1ffffff8, 7, 0x5d }, { 29, 0x1ffffff8, 7, 0x5b }, { 29, 0x1ffffff8, 7, 0x59 }, { 29, 0x1ffffff8, 7, 0x57 }, { 29, 0x1ffffff8, 7, 0x55 }, { 29, 0x1ffffff8, 7, 0x53 }, { 29, 0x1ffffff8, 7, 0x51 }, { 29, 0x1ffffff8, 7, 0x4f }, { 29, 0x1ffffff8, 7, 0x4d }, { 29, 0x1ffffff8, 7, 0x4b }, { 29, 0x1ffffff8, 7, 0x49 }, { 29, 0x1ffffff8, 7, 0x47 }, { 29, 0x1ffffff8, 7, 0x45 }, { 29, 0x1ffffff8, 7, 0x43 }, { 29, 0x1ffffff8, 7, 0x41 }, { 29, 0x1ffffff8, 7, 0x3f }, { 29, 0x1ffffff8, 7, 0x3d }, { 29, 0x1ffffff8, 7, 0x3b }, { 29, 0x1ffffff8, 7, 0x39 }, { 29, 0x1ffffff8, 7, 0x37 }, { 29, 0x1ffffff8, 7, 0x35 }, { 29, 0x1ffffff8, 7, 0x33 }, { 29, 0x1ffffff8, 7, 0x31 }, { 29, 0x1ffffff8, 7, 0x2f }, { 29, 0x1ffffff8, 7, 0x2d }, { 29, 0x1ffffff8, 7, 0x2b }, { 29, 0x1ffffff8, 7, 0x29 }, { 29, 0x1ffffff8, 7, 0x27 }, { 29, 0x1ffffff8, 7, 0x25 }, { 29, 0x1ffffff8, 7, 0x23 }, { 29, 0x1ffffff8, 7, 0x21 }, { 29, 0x1ffffff8, 7, 0x1f }, { 29, 0x1ffffff8, 7, 0x1d }, { 29, 0x1ffffff8, 7, 0x1b }, { 29, 0x1ffffff8, 7, 0x19 }, { 29, 0x1ffffff8, 7, 0x17 }, { 29, 0x1ffffff8, 7, 0x15 }, { 29, 0x1ffffff8, 7, 0x13 }, { 29, 0x1ffffff8, 7, 0x11 }, { 29, 0x1ffffff8, 7, 0xf }, { 29, 0x1ffffff8, 7, 0xd }, { 29, 0x1ffffff8, 7, 0xb }, { 29, 0x1ffffff8, 7, 0x9 }, { 29, 0x1ffffff8, 7, 0x7 }, { 29, 0x1ffffff8, 7, 0x5 }, { 29, 0x1ffffff8, 7, 0x3 }, { 29, 0x1ffffff8, 7, 0x1 }, { 0, 0, 0, 0 } }, /* * prefixed with 9 zeroes */ { { 11, 0x7f7, 0, 0 }, { 15, 0x7fe7, 0, 0 }, { 15, 0x7fe5, 0, 0 }, { 19, 0x7ffcf, 0, 0 }, { 19, 0x7ffcd, 0, 0 }, { 19, 0x7ffcb, 0, 0 }, { 19, 0x7ffc9, 0, 0 }, { 23, 0x7fff9f, 0, 0 }, { 23, 0x7fff9d, 0, 0 }, { 23, 0x7fff9b, 0, 0 }, { 23, 0x7fff99, 0, 0 }, { 23, 0x7fff97, 0, 0 }, { 23, 0x7fff95, 0, 0 }, { 23, 0x7fff93, 0, 0 }, { 23, 0x7fff91, 0, 0 }, { 27, 0x7ffff5f, 0, 0 }, { 27, 0x7ffff5d, 0, 0 }, { 27, 0x7ffff5b, 0, 0 }, { 27, 0x7ffff59, 0, 0 }, { 27, 0x7ffff57, 0, 0 }, { 27, 0x7ffff55, 0, 0 }, { 27, 0x7ffff53, 0, 0 }, { 27, 0x7ffff51, 0, 0 }, { 27, 0x7ffff4f, 0, 0 }, { 27, 0x7ffff4d, 0, 0 }, { 27, 0x7ffff4b, 0, 0 }, { 27, 0x7ffff49, 0, 0 }, { 27, 0x7ffff47, 0, 0 }, { 27, 0x7ffff45, 0, 0 }, { 27, 0x7ffff43, 0, 0 }, { 27, 0x7ffff41, 0, 0 }, { 31, 0x7ffffeff, 0, 0 }, { 31, 0x7ffffefd, 0, 0 }, { 31, 0x7ffffefb, 0, 0 }, { 31, 0x7ffffef9, 0, 0 }, { 31, 0x7ffffef7, 0, 0 }, { 31, 0x7ffffef5, 0, 0 }, { 31, 0x7ffffef3, 0, 0 }, { 31, 0x7ffffef1, 0, 0 }, { 31, 0x7ffffeef, 0, 0 }, { 31, 0x7ffffeed, 0, 0 }, { 31, 0x7ffffeeb, 0, 0 }, { 31, 0x7ffffee9, 0, 0 }, { 31, 0x7ffffee7, 0, 0 }, { 31, 0x7ffffee5, 0, 0 }, { 31, 0x7ffffee3, 0, 0 }, { 31, 0x7ffffee1, 0, 0 }, { 31, 0x7ffffedf, 0, 0 }, { 31, 0x7ffffedd, 0, 0 }, { 31, 0x7ffffedb, 0, 0 }, { 31, 0x7ffffed9, 0, 0 }, { 31, 0x7ffffed7, 0, 0 }, { 31, 0x7ffffed5, 0, 0 }, { 31, 0x7ffffed3, 0, 0 }, { 31, 0x7ffffed1, 0, 0 }, { 31, 0x7ffffecf, 0, 0 }, { 31, 0x7ffffecd, 0, 0 }, { 31, 0x7ffffecb, 0, 0 }, { 31, 0x7ffffec9, 0, 0 }, { 31, 0x7ffffec7, 0, 0 }, { 31, 0x7ffffec5, 0, 0 }, { 31, 0x7ffffec3, 0, 0 }, { 31, 0x7ffffec1, 0, 0 }, { 29, 0x1ffffff9, 7, 0x7f }, { 29, 0x1ffffff9, 7, 0x7d }, { 29, 0x1ffffff9, 7, 0x7b }, { 29, 0x1ffffff9, 7, 0x79 }, { 29, 0x1ffffff9, 7, 0x77 }, { 29, 0x1ffffff9, 7, 0x75 }, { 29, 0x1ffffff9, 7, 0x73 }, { 29, 0x1ffffff9, 7, 0x71 }, { 29, 0x1ffffff9, 7, 0x6f }, { 29, 0x1ffffff9, 7, 0x6d }, { 29, 0x1ffffff9, 7, 0x6b }, { 29, 0x1ffffff9, 7, 0x69 }, { 29, 0x1ffffff9, 7, 0x67 }, { 29, 0x1ffffff9, 7, 0x65 }, { 29, 0x1ffffff9, 7, 0x63 }, { 29, 0x1ffffff9, 7, 0x61 }, { 29, 0x1ffffff9, 7, 0x5f }, { 29, 0x1ffffff9, 7, 0x5d }, { 29, 0x1ffffff9, 7, 0x5b }, { 29, 0x1ffffff9, 7, 0x59 }, { 29, 0x1ffffff9, 7, 0x57 }, { 29, 0x1ffffff9, 7, 0x55 }, { 29, 0x1ffffff9, 7, 0x53 }, { 29, 0x1ffffff9, 7, 0x51 }, { 29, 0x1ffffff9, 7, 0x4f }, { 29, 0x1ffffff9, 7, 0x4d }, { 29, 0x1ffffff9, 7, 0x4b }, { 29, 0x1ffffff9, 7, 0x49 }, { 29, 0x1ffffff9, 7, 0x47 }, { 29, 0x1ffffff9, 7, 0x45 }, { 29, 0x1ffffff9, 7, 0x43 }, { 29, 0x1ffffff9, 7, 0x41 }, { 29, 0x1ffffff9, 7, 0x3f }, { 29, 0x1ffffff9, 7, 0x3d }, { 29, 0x1ffffff9, 7, 0x3b }, { 29, 0x1ffffff9, 7, 0x39 }, { 29, 0x1ffffff9, 7, 0x37 }, { 29, 0x1ffffff9, 7, 0x35 }, { 29, 0x1ffffff9, 7, 0x33 }, { 29, 0x1ffffff9, 7, 0x31 }, { 29, 0x1ffffff9, 7, 0x2f }, { 29, 0x1ffffff9, 7, 0x2d }, { 29, 0x1ffffff9, 7, 0x2b }, { 29, 0x1ffffff9, 7, 0x29 }, { 29, 0x1ffffff9, 7, 0x27 }, { 29, 0x1ffffff9, 7, 0x25 }, { 29, 0x1ffffff9, 7, 0x23 }, { 29, 0x1ffffff9, 7, 0x21 }, { 29, 0x1ffffff9, 7, 0x1f }, { 29, 0x1ffffff9, 7, 0x1d }, { 29, 0x1ffffff9, 7, 0x1b }, { 29, 0x1ffffff9, 7, 0x19 }, { 29, 0x1ffffff9, 7, 0x17 }, { 29, 0x1ffffff9, 7, 0x15 }, { 29, 0x1ffffff9, 7, 0x13 }, { 29, 0x1ffffff9, 7, 0x11 }, { 29, 0x1ffffff9, 7, 0xf }, { 29, 0x1ffffff9, 7, 0xd }, { 29, 0x1ffffff9, 7, 0xb }, { 29, 0x1ffffff9, 7, 0x9 }, { 29, 0x1ffffff9, 7, 0x7 }, { 29, 0x1ffffff9, 7, 0x5 }, { 29, 0x1ffffff9, 7, 0x3 }, { 29, 0x1ffffff9, 7, 0x1 }, { 0, 0, 0, 0 } }, /* * prefixed with 10 zeroes */ { { 12, 0xff1, 0, 0 }, { 15, 0x7feb, 0, 0 }, { 15, 0x7fe9, 0, 0 }, { 19, 0x7ffd7, 0, 0 }, { 19, 0x7ffd5, 0, 0 }, { 19, 0x7ffd3, 0, 0 }, { 19, 0x7ffd1, 0, 0 }, { 23, 0x7fffaf, 0, 0 }, { 23, 0x7fffad, 0, 0 }, { 23, 0x7fffab, 0, 0 }, { 23, 0x7fffa9, 0, 0 }, { 23, 0x7fffa7, 0, 0 }, { 23, 0x7fffa5, 0, 0 }, { 23, 0x7fffa3, 0, 0 }, { 23, 0x7fffa1, 0, 0 }, { 27, 0x7ffff7f, 0, 0 }, { 27, 0x7ffff7d, 0, 0 }, { 27, 0x7ffff7b, 0, 0 }, { 27, 0x7ffff79, 0, 0 }, { 27, 0x7ffff77, 0, 0 }, { 27, 0x7ffff75, 0, 0 }, { 27, 0x7ffff73, 0, 0 }, { 27, 0x7ffff71, 0, 0 }, { 27, 0x7ffff6f, 0, 0 }, { 27, 0x7ffff6d, 0, 0 }, { 27, 0x7ffff6b, 0, 0 }, { 27, 0x7ffff69, 0, 0 }, { 27, 0x7ffff67, 0, 0 }, { 27, 0x7ffff65, 0, 0 }, { 27, 0x7ffff63, 0, 0 }, { 27, 0x7ffff61, 0, 0 }, { 32, 0xfffffe3f, 0, 0 }, { 32, 0xfffffe3d, 0, 0 }, { 32, 0xfffffe3b, 0, 0 }, { 32, 0xfffffe39, 0, 0 }, { 32, 0xfffffe37, 0, 0 }, { 32, 0xfffffe35, 0, 0 }, { 32, 0xfffffe33, 0, 0 }, { 32, 0xfffffe31, 0, 0 }, { 32, 0xfffffe2f, 0, 0 }, { 32, 0xfffffe2d, 0, 0 }, { 32, 0xfffffe2b, 0, 0 }, { 32, 0xfffffe29, 0, 0 }, { 32, 0xfffffe27, 0, 0 }, { 32, 0xfffffe25, 0, 0 }, { 32, 0xfffffe23, 0, 0 }, { 32, 0xfffffe21, 0, 0 }, { 32, 0xfffffe1f, 0, 0 }, { 32, 0xfffffe1d, 0, 0 }, { 32, 0xfffffe1b, 0, 0 }, { 32, 0xfffffe19, 0, 0 }, { 32, 0xfffffe17, 0, 0 }, { 32, 0xfffffe15, 0, 0 }, { 32, 0xfffffe13, 0, 0 }, { 32, 0xfffffe11, 0, 0 }, { 32, 0xfffffe0f, 0, 0 }, { 32, 0xfffffe0d, 0, 0 }, { 32, 0xfffffe0b, 0, 0 }, { 32, 0xfffffe09, 0, 0 }, { 32, 0xfffffe07, 0, 0 }, { 32, 0xfffffe05, 0, 0 }, { 32, 0xfffffe03, 0, 0 }, { 32, 0xfffffe01, 0, 0 }, { 29, 0x1ffffffa, 7, 0x7f }, { 29, 0x1ffffffa, 7, 0x7d }, { 29, 0x1ffffffa, 7, 0x7b }, { 29, 0x1ffffffa, 7, 0x79 }, { 29, 0x1ffffffa, 7, 0x77 }, { 29, 0x1ffffffa, 7, 0x75 }, { 29, 0x1ffffffa, 7, 0x73 }, { 29, 0x1ffffffa, 7, 0x71 }, { 29, 0x1ffffffa, 7, 0x6f }, { 29, 0x1ffffffa, 7, 0x6d }, { 29, 0x1ffffffa, 7, 0x6b }, { 29, 0x1ffffffa, 7, 0x69 }, { 29, 0x1ffffffa, 7, 0x67 }, { 29, 0x1ffffffa, 7, 0x65 }, { 29, 0x1ffffffa, 7, 0x63 }, { 29, 0x1ffffffa, 7, 0x61 }, { 29, 0x1ffffffa, 7, 0x5f }, { 29, 0x1ffffffa, 7, 0x5d }, { 29, 0x1ffffffa, 7, 0x5b }, { 29, 0x1ffffffa, 7, 0x59 }, { 29, 0x1ffffffa, 7, 0x57 }, { 29, 0x1ffffffa, 7, 0x55 }, { 29, 0x1ffffffa, 7, 0x53 }, { 29, 0x1ffffffa, 7, 0x51 }, { 29, 0x1ffffffa, 7, 0x4f }, { 29, 0x1ffffffa, 7, 0x4d }, { 29, 0x1ffffffa, 7, 0x4b }, { 29, 0x1ffffffa, 7, 0x49 }, { 29, 0x1ffffffa, 7, 0x47 }, { 29, 0x1ffffffa, 7, 0x45 }, { 29, 0x1ffffffa, 7, 0x43 }, { 29, 0x1ffffffa, 7, 0x41 }, { 29, 0x1ffffffa, 7, 0x3f }, { 29, 0x1ffffffa, 7, 0x3d }, { 29, 0x1ffffffa, 7, 0x3b }, { 29, 0x1ffffffa, 7, 0x39 }, { 29, 0x1ffffffa, 7, 0x37 }, { 29, 0x1ffffffa, 7, 0x35 }, { 29, 0x1ffffffa, 7, 0x33 }, { 29, 0x1ffffffa, 7, 0x31 }, { 29, 0x1ffffffa, 7, 0x2f }, { 29, 0x1ffffffa, 7, 0x2d }, { 29, 0x1ffffffa, 7, 0x2b }, { 29, 0x1ffffffa, 7, 0x29 }, { 29, 0x1ffffffa, 7, 0x27 }, { 29, 0x1ffffffa, 7, 0x25 }, { 29, 0x1ffffffa, 7, 0x23 }, { 29, 0x1ffffffa, 7, 0x21 }, { 29, 0x1ffffffa, 7, 0x1f }, { 29, 0x1ffffffa, 7, 0x1d }, { 29, 0x1ffffffa, 7, 0x1b }, { 29, 0x1ffffffa, 7, 0x19 }, { 29, 0x1ffffffa, 7, 0x17 }, { 29, 0x1ffffffa, 7, 0x15 }, { 29, 0x1ffffffa, 7, 0x13 }, { 29, 0x1ffffffa, 7, 0x11 }, { 29, 0x1ffffffa, 7, 0xf }, { 29, 0x1ffffffa, 7, 0xd }, { 29, 0x1ffffffa, 7, 0xb }, { 29, 0x1ffffffa, 7, 0x9 }, { 29, 0x1ffffffa, 7, 0x7 }, { 29, 0x1ffffffa, 7, 0x5 }, { 29, 0x1ffffffa, 7, 0x3 }, { 29, 0x1ffffffa, 7, 0x1 }, { 0, 0, 0, 0 } }, /* * prefixed with 11 zeroes */ { { 12, 0xff3, 0, 0 }, { 15, 0x7fef, 0, 0 }, { 15, 0x7fed, 0, 0 }, { 19, 0x7ffdf, 0, 0 }, { 19, 0x7ffdd, 0, 0 }, { 19, 0x7ffdb, 0, 0 }, { 19, 0x7ffd9, 0, 0 }, { 23, 0x7fffbf, 0, 0 }, { 23, 0x7fffbd, 0, 0 }, { 23, 0x7fffbb, 0, 0 }, { 23, 0x7fffb9, 0, 0 }, { 23, 0x7fffb7, 0, 0 }, { 23, 0x7fffb5, 0, 0 }, { 23, 0x7fffb3, 0, 0 }, { 23, 0x7fffb1, 0, 0 }, { 28, 0xfffff1f, 0, 0 }, { 28, 0xfffff1d, 0, 0 }, { 28, 0xfffff1b, 0, 0 }, { 28, 0xfffff19, 0, 0 }, { 28, 0xfffff17, 0, 0 }, { 28, 0xfffff15, 0, 0 }, { 28, 0xfffff13, 0, 0 }, { 28, 0xfffff11, 0, 0 }, { 28, 0xfffff0f, 0, 0 }, { 28, 0xfffff0d, 0, 0 }, { 28, 0xfffff0b, 0, 0 }, { 28, 0xfffff09, 0, 0 }, { 28, 0xfffff07, 0, 0 }, { 28, 0xfffff05, 0, 0 }, { 28, 0xfffff03, 0, 0 }, { 28, 0xfffff01, 0, 0 }, { 32, 0xfffffe7f, 0, 0 }, { 32, 0xfffffe7d, 0, 0 }, { 32, 0xfffffe7b, 0, 0 }, { 32, 0xfffffe79, 0, 0 }, { 32, 0xfffffe77, 0, 0 }, { 32, 0xfffffe75, 0, 0 }, { 32, 0xfffffe73, 0, 0 }, { 32, 0xfffffe71, 0, 0 }, { 32, 0xfffffe6f, 0, 0 }, { 32, 0xfffffe6d, 0, 0 }, { 32, 0xfffffe6b, 0, 0 }, { 32, 0xfffffe69, 0, 0 }, { 32, 0xfffffe67, 0, 0 }, { 32, 0xfffffe65, 0, 0 }, { 32, 0xfffffe63, 0, 0 }, { 32, 0xfffffe61, 0, 0 }, { 32, 0xfffffe5f, 0, 0 }, { 32, 0xfffffe5d, 0, 0 }, { 32, 0xfffffe5b, 0, 0 }, { 32, 0xfffffe59, 0, 0 }, { 32, 0xfffffe57, 0, 0 }, { 32, 0xfffffe55, 0, 0 }, { 32, 0xfffffe53, 0, 0 }, { 32, 0xfffffe51, 0, 0 }, { 32, 0xfffffe4f, 0, 0 }, { 32, 0xfffffe4d, 0, 0 }, { 32, 0xfffffe4b, 0, 0 }, { 32, 0xfffffe49, 0, 0 }, { 32, 0xfffffe47, 0, 0 }, { 32, 0xfffffe45, 0, 0 }, { 32, 0xfffffe43, 0, 0 }, { 32, 0xfffffe41, 0, 0 }, { 29, 0x1ffffffb, 7, 0x7f }, { 29, 0x1ffffffb, 7, 0x7d }, { 29, 0x1ffffffb, 7, 0x7b }, { 29, 0x1ffffffb, 7, 0x79 }, { 29, 0x1ffffffb, 7, 0x77 }, { 29, 0x1ffffffb, 7, 0x75 }, { 29, 0x1ffffffb, 7, 0x73 }, { 29, 0x1ffffffb, 7, 0x71 }, { 29, 0x1ffffffb, 7, 0x6f }, { 29, 0x1ffffffb, 7, 0x6d }, { 29, 0x1ffffffb, 7, 0x6b }, { 29, 0x1ffffffb, 7, 0x69 }, { 29, 0x1ffffffb, 7, 0x67 }, { 29, 0x1ffffffb, 7, 0x65 }, { 29, 0x1ffffffb, 7, 0x63 }, { 29, 0x1ffffffb, 7, 0x61 }, { 29, 0x1ffffffb, 7, 0x5f }, { 29, 0x1ffffffb, 7, 0x5d }, { 29, 0x1ffffffb, 7, 0x5b }, { 29, 0x1ffffffb, 7, 0x59 }, { 29, 0x1ffffffb, 7, 0x57 }, { 29, 0x1ffffffb, 7, 0x55 }, { 29, 0x1ffffffb, 7, 0x53 }, { 29, 0x1ffffffb, 7, 0x51 }, { 29, 0x1ffffffb, 7, 0x4f }, { 29, 0x1ffffffb, 7, 0x4d }, { 29, 0x1ffffffb, 7, 0x4b }, { 29, 0x1ffffffb, 7, 0x49 }, { 29, 0x1ffffffb, 7, 0x47 }, { 29, 0x1ffffffb, 7, 0x45 }, { 29, 0x1ffffffb, 7, 0x43 }, { 29, 0x1ffffffb, 7, 0x41 }, { 29, 0x1ffffffb, 7, 0x3f }, { 29, 0x1ffffffb, 7, 0x3d }, { 29, 0x1ffffffb, 7, 0x3b }, { 29, 0x1ffffffb, 7, 0x39 }, { 29, 0x1ffffffb, 7, 0x37 }, { 29, 0x1ffffffb, 7, 0x35 }, { 29, 0x1ffffffb, 7, 0x33 }, { 29, 0x1ffffffb, 7, 0x31 }, { 29, 0x1ffffffb, 7, 0x2f }, { 29, 0x1ffffffb, 7, 0x2d }, { 29, 0x1ffffffb, 7, 0x2b }, { 29, 0x1ffffffb, 7, 0x29 }, { 29, 0x1ffffffb, 7, 0x27 }, { 29, 0x1ffffffb, 7, 0x25 }, { 29, 0x1ffffffb, 7, 0x23 }, { 29, 0x1ffffffb, 7, 0x21 }, { 29, 0x1ffffffb, 7, 0x1f }, { 29, 0x1ffffffb, 7, 0x1d }, { 29, 0x1ffffffb, 7, 0x1b }, { 29, 0x1ffffffb, 7, 0x19 }, { 29, 0x1ffffffb, 7, 0x17 }, { 29, 0x1ffffffb, 7, 0x15 }, { 29, 0x1ffffffb, 7, 0x13 }, { 29, 0x1ffffffb, 7, 0x11 }, { 29, 0x1ffffffb, 7, 0xf }, { 29, 0x1ffffffb, 7, 0xd }, { 29, 0x1ffffffb, 7, 0xb }, { 29, 0x1ffffffb, 7, 0x9 }, { 29, 0x1ffffffb, 7, 0x7 }, { 29, 0x1ffffffb, 7, 0x5 }, { 29, 0x1ffffffb, 7, 0x3 }, { 29, 0x1ffffffb, 7, 0x1 }, { 0, 0, 0, 0 } }, /* * prefixed with 12 zeroes */ { { 12, 0xff5, 0, 0 }, { 16, 0xffe3, 0, 0 }, { 16, 0xffe1, 0, 0 }, { 20, 0xfffc7, 0, 0 }, { 20, 0xfffc5, 0, 0 }, { 20, 0xfffc3, 0, 0 }, { 20, 0xfffc1, 0, 0 }, { 24, 0xffff8f, 0, 0 }, { 24, 0xffff8d, 0, 0 }, { 24, 0xffff8b, 0, 0 }, { 24, 0xffff89, 0, 0 }, { 24, 0xffff87, 0, 0 }, { 24, 0xffff85, 0, 0 }, { 24, 0xffff83, 0, 0 }, { 24, 0xffff81, 0, 0 }, { 28, 0xfffff3f, 0, 0 }, { 28, 0xfffff3d, 0, 0 }, { 28, 0xfffff3b, 0, 0 }, { 28, 0xfffff39, 0, 0 }, { 28, 0xfffff37, 0, 0 }, { 28, 0xfffff35, 0, 0 }, { 28, 0xfffff33, 0, 0 }, { 28, 0xfffff31, 0, 0 }, { 28, 0xfffff2f, 0, 0 }, { 28, 0xfffff2d, 0, 0 }, { 28, 0xfffff2b, 0, 0 }, { 28, 0xfffff29, 0, 0 }, { 28, 0xfffff27, 0, 0 }, { 28, 0xfffff25, 0, 0 }, { 28, 0xfffff23, 0, 0 }, { 28, 0xfffff21, 0, 0 }, { 32, 0xfffffebf, 0, 0 }, { 32, 0xfffffebd, 0, 0 }, { 32, 0xfffffebb, 0, 0 }, { 32, 0xfffffeb9, 0, 0 }, { 32, 0xfffffeb7, 0, 0 }, { 32, 0xfffffeb5, 0, 0 }, { 32, 0xfffffeb3, 0, 0 }, { 32, 0xfffffeb1, 0, 0 }, { 32, 0xfffffeaf, 0, 0 }, { 32, 0xfffffead, 0, 0 }, { 32, 0xfffffeab, 0, 0 }, { 32, 0xfffffea9, 0, 0 }, { 32, 0xfffffea7, 0, 0 }, { 32, 0xfffffea5, 0, 0 }, { 32, 0xfffffea3, 0, 0 }, { 32, 0xfffffea1, 0, 0 }, { 32, 0xfffffe9f, 0, 0 }, { 32, 0xfffffe9d, 0, 0 }, { 32, 0xfffffe9b, 0, 0 }, { 32, 0xfffffe99, 0, 0 }, { 32, 0xfffffe97, 0, 0 }, { 32, 0xfffffe95, 0, 0 }, { 32, 0xfffffe93, 0, 0 }, { 32, 0xfffffe91, 0, 0 }, { 32, 0xfffffe8f, 0, 0 }, { 32, 0xfffffe8d, 0, 0 }, { 32, 0xfffffe8b, 0, 0 }, { 32, 0xfffffe89, 0, 0 }, { 32, 0xfffffe87, 0, 0 }, { 32, 0xfffffe85, 0, 0 }, { 32, 0xfffffe83, 0, 0 }, { 32, 0xfffffe81, 0, 0 }, { 30, 0x1fff7400, 7, 0x7f }, { 30, 0x1fff7400, 7, 0x7d }, { 30, 0x1fff7400, 7, 0x7b }, { 30, 0x1fff7400, 7, 0x79 }, { 30, 0x1fff7400, 7, 0x77 }, { 30, 0x1fff7400, 7, 0x75 }, { 30, 0x1fff7400, 7, 0x73 }, { 30, 0x1fff7400, 7, 0x71 }, { 30, 0x1fff7400, 7, 0x6f }, { 30, 0x1fff7400, 7, 0x6d }, { 30, 0x1fff7400, 7, 0x6b }, { 30, 0x1fff7400, 7, 0x69 }, { 30, 0x1fff7400, 7, 0x67 }, { 30, 0x1fff7400, 7, 0x65 }, { 30, 0x1fff7400, 7, 0x63 }, { 30, 0x1fff7400, 7, 0x61 }, { 30, 0x1fff7400, 7, 0x5f }, { 30, 0x1fff7400, 7, 0x5d }, { 30, 0x1fff7400, 7, 0x5b }, { 30, 0x1fff7400, 7, 0x59 }, { 30, 0x1fff7400, 7, 0x57 }, { 30, 0x1fff7400, 7, 0x55 }, { 30, 0x1fff7400, 7, 0x53 }, { 30, 0x1fff7400, 7, 0x51 }, { 30, 0x1fff7400, 7, 0x4f }, { 30, 0x1fff7400, 7, 0x4d }, { 30, 0x1fff7400, 7, 0x4b }, { 30, 0x1fff7400, 7, 0x49 }, { 30, 0x1fff7400, 7, 0x47 }, { 30, 0x1fff7400, 7, 0x45 }, { 30, 0x1fff7400, 7, 0x43 }, { 30, 0x1fff7400, 7, 0x41 }, { 30, 0x1fff7400, 7, 0x3f }, { 30, 0x1fff7400, 7, 0x3d }, { 30, 0x1fff7400, 7, 0x3b }, { 30, 0x1fff7400, 7, 0x39 }, { 30, 0x1fff7400, 7, 0x37 }, { 30, 0x1fff7400, 7, 0x35 }, { 30, 0x1fff7400, 7, 0x33 }, { 30, 0x1fff7400, 7, 0x31 }, { 30, 0x1fff7400, 7, 0x2f }, { 30, 0x1fff7400, 7, 0x2d }, { 30, 0x1fff7400, 7, 0x2b }, { 30, 0x1fff7400, 7, 0x29 }, { 30, 0x1fff7400, 7, 0x27 }, { 30, 0x1fff7400, 7, 0x25 }, { 30, 0x1fff7400, 7, 0x23 }, { 30, 0x1fff7400, 7, 0x21 }, { 30, 0x1fff7400, 7, 0x1f }, { 30, 0x1fff7400, 7, 0x1d }, { 30, 0x1fff7400, 7, 0x1b }, { 30, 0x1fff7400, 7, 0x19 }, { 30, 0x1fff7400, 7, 0x17 }, { 30, 0x1fff7400, 7, 0x15 }, { 30, 0x1fff7400, 7, 0x13 }, { 30, 0x1fff7400, 7, 0x11 }, { 30, 0x1fff7400, 7, 0xf }, { 30, 0x1fff7400, 7, 0xd }, { 30, 0x1fff7400, 7, 0xb }, { 30, 0x1fff7400, 7, 0x9 }, { 30, 0x1fff7400, 7, 0x7 }, { 30, 0x1fff7400, 7, 0x5 }, { 30, 0x1fff7400, 7, 0x3 }, { 30, 0x1fff7400, 7, 0x1 }, { 0, 0, 0, 0 } }, /* * prefixed with 13 zeroes */ { { 12, 0xff7, 0, 0 }, { 16, 0xffe7, 0, 0 }, { 16, 0xffe5, 0, 0 }, { 20, 0xfffcf, 0, 0 }, { 20, 0xfffcd, 0, 0 }, { 20, 0xfffcb, 0, 0 }, { 20, 0xfffc9, 0, 0 }, { 24, 0xffff9f, 0, 0 }, { 24, 0xffff9d, 0, 0 }, { 24, 0xffff9b, 0, 0 }, { 24, 0xffff99, 0, 0 }, { 24, 0xffff97, 0, 0 }, { 24, 0xffff95, 0, 0 }, { 24, 0xffff93, 0, 0 }, { 24, 0xffff91, 0, 0 }, { 28, 0xfffff5f, 0, 0 }, { 28, 0xfffff5d, 0, 0 }, { 28, 0xfffff5b, 0, 0 }, { 28, 0xfffff59, 0, 0 }, { 28, 0xfffff57, 0, 0 }, { 28, 0xfffff55, 0, 0 }, { 28, 0xfffff53, 0, 0 }, { 28, 0xfffff51, 0, 0 }, { 28, 0xfffff4f, 0, 0 }, { 28, 0xfffff4d, 0, 0 }, { 28, 0xfffff4b, 0, 0 }, { 28, 0xfffff49, 0, 0 }, { 28, 0xfffff47, 0, 0 }, { 28, 0xfffff45, 0, 0 }, { 28, 0xfffff43, 0, 0 }, { 28, 0xfffff41, 0, 0 }, { 32, 0xfffffeff, 0, 0 }, { 32, 0xfffffefd, 0, 0 }, { 32, 0xfffffefb, 0, 0 }, { 32, 0xfffffef9, 0, 0 }, { 32, 0xfffffef7, 0, 0 }, { 32, 0xfffffef5, 0, 0 }, { 32, 0xfffffef3, 0, 0 }, { 32, 0xfffffef1, 0, 0 }, { 32, 0xfffffeef, 0, 0 }, { 32, 0xfffffeed, 0, 0 }, { 32, 0xfffffeeb, 0, 0 }, { 32, 0xfffffee9, 0, 0 }, { 32, 0xfffffee7, 0, 0 }, { 32, 0xfffffee5, 0, 0 }, { 32, 0xfffffee3, 0, 0 }, { 32, 0xfffffee1, 0, 0 }, { 32, 0xfffffedf, 0, 0 }, { 32, 0xfffffedd, 0, 0 }, { 32, 0xfffffedb, 0, 0 }, { 32, 0xfffffed9, 0, 0 }, { 32, 0xfffffed7, 0, 0 }, { 32, 0xfffffed5, 0, 0 }, { 32, 0xfffffed3, 0, 0 }, { 32, 0xfffffed1, 0, 0 }, { 32, 0xfffffecf, 0, 0 }, { 32, 0xfffffecd, 0, 0 }, { 32, 0xfffffecb, 0, 0 }, { 32, 0xfffffec9, 0, 0 }, { 32, 0xfffffec7, 0, 0 }, { 32, 0xfffffec5, 0, 0 }, { 32, 0xfffffec3, 0, 0 }, { 32, 0xfffffec1, 0, 0 }, { 30, 0x3ffffff9, 7, 0x7f }, { 30, 0x3ffffff9, 7, 0x7d }, { 30, 0x3ffffff9, 7, 0x7b }, { 30, 0x3ffffff9, 7, 0x79 }, { 30, 0x3ffffff9, 7, 0x77 }, { 30, 0x3ffffff9, 7, 0x75 }, { 30, 0x3ffffff9, 7, 0x73 }, { 30, 0x3ffffff9, 7, 0x71 }, { 30, 0x3ffffff9, 7, 0x6f }, { 30, 0x3ffffff9, 7, 0x6d }, { 30, 0x3ffffff9, 7, 0x6b }, { 30, 0x3ffffff9, 7, 0x69 }, { 30, 0x3ffffff9, 7, 0x67 }, { 30, 0x3ffffff9, 7, 0x65 }, { 30, 0x3ffffff9, 7, 0x63 }, { 30, 0x3ffffff9, 7, 0x61 }, { 30, 0x3ffffff9, 7, 0x5f }, { 30, 0x3ffffff9, 7, 0x5d }, { 30, 0x3ffffff9, 7, 0x5b }, { 30, 0x3ffffff9, 7, 0x59 }, { 30, 0x3ffffff9, 7, 0x57 }, { 30, 0x3ffffff9, 7, 0x55 }, { 30, 0x3ffffff9, 7, 0x53 }, { 30, 0x3ffffff9, 7, 0x51 }, { 30, 0x3ffffff9, 7, 0x4f }, { 30, 0x3ffffff9, 7, 0x4d }, { 30, 0x3ffffff9, 7, 0x4b }, { 30, 0x3ffffff9, 7, 0x49 }, { 30, 0x3ffffff9, 7, 0x47 }, { 30, 0x3ffffff9, 7, 0x45 }, { 30, 0x3ffffff9, 7, 0x43 }, { 30, 0x3ffffff9, 7, 0x41 }, { 30, 0x3ffffff9, 7, 0x3f }, { 30, 0x3ffffff9, 7, 0x3d }, { 30, 0x3ffffff9, 7, 0x3b }, { 30, 0x3ffffff9, 7, 0x39 }, { 30, 0x3ffffff9, 7, 0x37 }, { 30, 0x3ffffff9, 7, 0x35 }, { 30, 0x3ffffff9, 7, 0x33 }, { 30, 0x3ffffff9, 7, 0x31 }, { 30, 0x3ffffff9, 7, 0x2f }, { 30, 0x3ffffff9, 7, 0x2d }, { 30, 0x3ffffff9, 7, 0x2b }, { 30, 0x3ffffff9, 7, 0x29 }, { 30, 0x3ffffff9, 7, 0x27 }, { 30, 0x3ffffff9, 7, 0x25 }, { 30, 0x3ffffff9, 7, 0x23 }, { 30, 0x3ffffff9, 7, 0x21 }, { 30, 0x3ffffff9, 7, 0x1f }, { 30, 0x3ffffff9, 7, 0x1d }, { 30, 0x3ffffff9, 7, 0x1b }, { 30, 0x3ffffff9, 7, 0x19 }, { 30, 0x3ffffff9, 7, 0x17 }, { 30, 0x3ffffff9, 7, 0x15 }, { 30, 0x3ffffff9, 7, 0x13 }, { 30, 0x3ffffff9, 7, 0x11 }, { 30, 0x3ffffff9, 7, 0xf }, { 30, 0x3ffffff9, 7, 0xd }, { 30, 0x3ffffff9, 7, 0xb }, { 30, 0x3ffffff9, 7, 0x9 }, { 30, 0x3ffffff9, 7, 0x7 }, { 30, 0x3ffffff9, 7, 0x5 }, { 30, 0x3ffffff9, 7, 0x3 }, { 30, 0x3ffffff9, 7, 0x1 }, { 0, 0, 0, 0 } }, /* * prefixed with 14 zeroes */ { { 13, 0x1ff1, 0, 0 }, { 16, 0xffeb, 0, 0 }, { 16, 0xffe9, 0, 0 }, { 20, 0xfffd7, 0, 0 }, { 20, 0xfffd5, 0, 0 }, { 20, 0xfffd3, 0, 0 }, { 20, 0xfffd1, 0, 0 }, { 24, 0xffffaf, 0, 0 }, { 24, 0xffffad, 0, 0 }, { 24, 0xffffab, 0, 0 }, { 24, 0xffffa9, 0, 0 }, { 24, 0xffffa7, 0, 0 }, { 24, 0xffffa5, 0, 0 }, { 24, 0xffffa3, 0, 0 }, { 24, 0xffffa1, 0, 0 }, { 28, 0xfffff7f, 0, 0 }, { 28, 0xfffff7d, 0, 0 }, { 28, 0xfffff7b, 0, 0 }, { 28, 0xfffff79, 0, 0 }, { 28, 0xfffff77, 0, 0 }, { 28, 0xfffff75, 0, 0 }, { 28, 0xfffff73, 0, 0 }, { 28, 0xfffff71, 0, 0 }, { 28, 0xfffff6f, 0, 0 }, { 28, 0xfffff6d, 0, 0 }, { 28, 0xfffff6b, 0, 0 }, { 28, 0xfffff69, 0, 0 }, { 28, 0xfffff67, 0, 0 }, { 28, 0xfffff65, 0, 0 }, { 28, 0xfffff63, 0, 0 }, { 28, 0xfffff61, 0, 0 }, { 27, 0x7fffff8, 6, 0x3f }, { 27, 0x7fffff8, 6, 0x3d }, { 27, 0x7fffff8, 6, 0x3b }, { 27, 0x7fffff8, 6, 0x39 }, { 27, 0x7fffff8, 6, 0x37 }, { 27, 0x7fffff8, 6, 0x35 }, { 27, 0x7fffff8, 6, 0x33 }, { 27, 0x7fffff8, 6, 0x31 }, { 27, 0x7fffff8, 6, 0x2f }, { 27, 0x7fffff8, 6, 0x2d }, { 27, 0x7fffff8, 6, 0x2b }, { 27, 0x7fffff8, 6, 0x29 }, { 27, 0x7fffff8, 6, 0x27 }, { 27, 0x7fffff8, 6, 0x25 }, { 27, 0x7fffff8, 6, 0x23 }, { 27, 0x7fffff8, 6, 0x21 }, { 27, 0x7fffff8, 6, 0x1f }, { 27, 0x7fffff8, 6, 0x1d }, { 27, 0x7fffff8, 6, 0x1b }, { 27, 0x7fffff8, 6, 0x19 }, { 27, 0x7fffff8, 6, 0x17 }, { 27, 0x7fffff8, 6, 0x15 }, { 27, 0x7fffff8, 6, 0x13 }, { 27, 0x7fffff8, 6, 0x11 }, { 27, 0x7fffff8, 6, 0xf }, { 27, 0x7fffff8, 6, 0xd }, { 27, 0x7fffff8, 6, 0xb }, { 27, 0x7fffff8, 6, 0x9 }, { 27, 0x7fffff8, 6, 0x7 }, { 27, 0x7fffff8, 6, 0x5 }, { 27, 0x7fffff8, 6, 0x3 }, { 27, 0x7fffff8, 6, 0x1 }, { 30, 0x3ffffffa, 7, 0x7f }, { 30, 0x3ffffffa, 7, 0x7d }, { 30, 0x3ffffffa, 7, 0x7b }, { 30, 0x3ffffffa, 7, 0x79 }, { 30, 0x3ffffffa, 7, 0x77 }, { 30, 0x3ffffffa, 7, 0x75 }, { 30, 0x3ffffffa, 7, 0x73 }, { 30, 0x3ffffffa, 7, 0x71 }, { 30, 0x3ffffffa, 7, 0x6f }, { 30, 0x3ffffffa, 7, 0x6d }, { 30, 0x3ffffffa, 7, 0x6b }, { 30, 0x3ffffffa, 7, 0x69 }, { 30, 0x3ffffffa, 7, 0x67 }, { 30, 0x3ffffffa, 7, 0x65 }, { 30, 0x3ffffffa, 7, 0x63 }, { 30, 0x3ffffffa, 7, 0x61 }, { 30, 0x3ffffffa, 7, 0x5f }, { 30, 0x3ffffffa, 7, 0x5d }, { 30, 0x3ffffffa, 7, 0x5b }, { 30, 0x3ffffffa, 7, 0x59 }, { 30, 0x3ffffffa, 7, 0x57 }, { 30, 0x3ffffffa, 7, 0x55 }, { 30, 0x3ffffffa, 7, 0x53 }, { 30, 0x3ffffffa, 7, 0x51 }, { 30, 0x3ffffffa, 7, 0x4f }, { 30, 0x3ffffffa, 7, 0x4d }, { 30, 0x3ffffffa, 7, 0x4b }, { 30, 0x3ffffffa, 7, 0x49 }, { 30, 0x3ffffffa, 7, 0x47 }, { 30, 0x3ffffffa, 7, 0x45 }, { 30, 0x3ffffffa, 7, 0x43 }, { 30, 0x3ffffffa, 7, 0x41 }, { 30, 0x3ffffffa, 7, 0x3f }, { 30, 0x3ffffffa, 7, 0x3d }, { 30, 0x3ffffffa, 7, 0x3b }, { 30, 0x3ffffffa, 7, 0x39 }, { 30, 0x3ffffffa, 7, 0x37 }, { 30, 0x3ffffffa, 7, 0x35 }, { 30, 0x3ffffffa, 7, 0x33 }, { 30, 0x3ffffffa, 7, 0x31 }, { 30, 0x3ffffffa, 7, 0x2f }, { 30, 0x3ffffffa, 7, 0x2d }, { 30, 0x3ffffffa, 7, 0x2b }, { 30, 0x3ffffffa, 7, 0x29 }, { 30, 0x3ffffffa, 7, 0x27 }, { 30, 0x3ffffffa, 7, 0x25 }, { 30, 0x3ffffffa, 7, 0x23 }, { 30, 0x3ffffffa, 7, 0x21 }, { 30, 0x3ffffffa, 7, 0x1f }, { 30, 0x3ffffffa, 7, 0x1d }, { 30, 0x3ffffffa, 7, 0x1b }, { 30, 0x3ffffffa, 7, 0x19 }, { 30, 0x3ffffffa, 7, 0x17 }, { 30, 0x3ffffffa, 7, 0x15 }, { 30, 0x3ffffffa, 7, 0x13 }, { 30, 0x3ffffffa, 7, 0x11 }, { 30, 0x3ffffffa, 7, 0xf }, { 30, 0x3ffffffa, 7, 0xd }, { 30, 0x3ffffffa, 7, 0xb }, { 30, 0x3ffffffa, 7, 0x9 }, { 30, 0x3ffffffa, 7, 0x7 }, { 30, 0x3ffffffa, 7, 0x5 }, { 30, 0x3ffffffa, 7, 0x3 }, { 30, 0x3ffffffa, 7, 0x1 }, { 0, 0, 0, 0 } }, /* * prefixed with 15 zeroes */ { { 13, 0x1ff3, 0, 0 }, { 2, 0x3, 0, 0 }, { 2, 0x1, 0, 0 }, { 3, 0x7, 0, 0 }, { 3, 0x5, 0, 0 }, { 3, 0x3, 0, 0 }, { 3, 0x1, 0, 0 }, { 31, 0x7ffffffb, 4, 0xf }, { 31, 0x7ffffffb, 4, 0xd }, { 31, 0x7ffffffb, 4, 0xb }, { 31, 0x7ffffffb, 4, 0x9 }, { 31, 0x7ffffffb, 4, 0x7 }, { 31, 0x7ffffffb, 4, 0x5 }, { 31, 0x7ffffffb, 4, 0x3 }, { 31, 0x7ffffffb, 4, 0x1 }, { 5, 0x1f, 0, 0 }, { 5, 0x1d, 0, 0 }, { 5, 0x1b, 0, 0 }, { 5, 0x19, 0, 0 }, { 5, 0x17, 0, 0 }, { 5, 0x15, 0, 0 }, { 5, 0x13, 0, 0 }, { 5, 0x11, 0, 0 }, { 5, 0xf, 0, 0 }, { 5, 0xd, 0, 0 }, { 5, 0xb, 0, 0 }, { 5, 0x9, 0, 0 }, { 5, 0x7, 0, 0 }, { 5, 0x5, 0, 0 }, { 5, 0x3, 0, 0 }, { 5, 0x1, 0, 0 }, { 6, 0x3f, 0, 0 }, { 6, 0x3d, 0, 0 }, { 6, 0x3b, 0, 0 }, { 6, 0x39, 0, 0 }, { 6, 0x37, 0, 0 }, { 6, 0x35, 0, 0 }, { 6, 0x33, 0, 0 }, { 6, 0x31, 0, 0 }, { 6, 0x2f, 0, 0 }, { 6, 0x2d, 0, 0 }, { 6, 0x2b, 0, 0 }, { 6, 0x29, 0, 0 }, { 6, 0x27, 0, 0 }, { 6, 0x25, 0, 0 }, { 6, 0x23, 0, 0 }, { 6, 0x21, 0, 0 }, { 6, 0x1f, 0, 0 }, { 6, 0x1d, 0, 0 }, { 6, 0x1b, 0, 0 }, { 6, 0x19, 0, 0 }, { 6, 0x17, 0, 0 }, { 6, 0x15, 0, 0 }, { 6, 0x13, 0, 0 }, { 6, 0x11, 0, 0 }, { 6, 0xf, 0, 0 }, { 6, 0xd, 0, 0 }, { 6, 0xb, 0, 0 }, { 6, 0x9, 0, 0 }, { 6, 0x7, 0, 0 }, { 6, 0x5, 0, 0 }, { 6, 0x3, 0, 0 }, { 6, 0x1, 0, 0 }, { 7, 0x7f, 0, 0 }, { 7, 0x7d, 0, 0 }, { 7, 0x7b, 0, 0 }, { 7, 0x79, 0, 0 }, { 7, 0x77, 0, 0 }, { 7, 0x75, 0, 0 }, { 7, 0x73, 0, 0 }, { 7, 0x71, 0, 0 }, { 7, 0x6f, 0, 0 }, { 7, 0x6d, 0, 0 }, { 7, 0x6b, 0, 0 }, { 7, 0x69, 0, 0 }, { 7, 0x67, 0, 0 }, { 7, 0x65, 0, 0 }, { 7, 0x63, 0, 0 }, { 7, 0x61, 0, 0 }, { 7, 0x5f, 0, 0 }, { 7, 0x5d, 0, 0 }, { 7, 0x5b, 0, 0 }, { 7, 0x59, 0, 0 }, { 7, 0x57, 0, 0 }, { 7, 0x55, 0, 0 }, { 7, 0x53, 0, 0 }, { 7, 0x51, 0, 0 }, { 7, 0x4f, 0, 0 }, { 7, 0x4d, 0, 0 }, { 7, 0x4b, 0, 0 }, { 7, 0x49, 0, 0 }, { 7, 0x47, 0, 0 }, { 7, 0x45, 0, 0 }, { 7, 0x43, 0, 0 }, { 7, 0x41, 0, 0 }, { 7, 0x3f, 0, 0 }, { 7, 0x3d, 0, 0 }, { 7, 0x3b, 0, 0 }, { 7, 0x39, 0, 0 }, { 7, 0x37, 0, 0 }, { 7, 0x35, 0, 0 }, { 7, 0x33, 0, 0 }, { 7, 0x31, 0, 0 }, { 7, 0x2f, 0, 0 }, { 7, 0x2d, 0, 0 }, { 7, 0x2b, 0, 0 }, { 7, 0x29, 0, 0 }, { 7, 0x27, 0, 0 }, { 7, 0x25, 0, 0 }, { 7, 0x23, 0, 0 }, { 7, 0x21, 0, 0 }, { 7, 0x1f, 0, 0 }, { 7, 0x1d, 0, 0 }, { 7, 0x1b, 0, 0 }, { 7, 0x19, 0, 0 }, { 7, 0x17, 0, 0 }, { 7, 0x15, 0, 0 }, { 7, 0x13, 0, 0 }, { 7, 0x11, 0, 0 }, { 7, 0xf, 0, 0 }, { 7, 0xd, 0, 0 }, { 7, 0xb, 0, 0 }, { 7, 0x9, 0, 0 }, { 7, 0x7, 0, 0 }, { 7, 0x5, 0, 0 }, { 7, 0x3, 0, 0 }, { 7, 0x1, 0, 0 }, { 0, 0, 0, 0 } } }; VlcMagic _magic_values[] = { { 0x0, 0, 1 }, { 0x1, 0, 2 }, { 0x4, 0, 3 }, { 0xB, 1, 1 }, { 0xC, 0, 4 }, { 0x1A, 0, 5 }, { 0x1B, 2, 1 }, { 0x38, 3, 1 }, { 0x39, 1, 2 }, { 0x3A, 1, 3 }, { 0x3B, 0, 6 }, { 0x78, 4, 1 }, { 0x79, 5, 1 }, { 0x7A, 6, 1 }, { 0x7B, 2, 2 }, { 0xF8, 1, 4 }, { 0xF9, 7, 1 }, { 0xFA, 8, 1 }, { 0xFB, 3, 2 }, { 0x1F8, 4, 2 }, { 0x1F9, 5, 2 }, { 0x1FA, 2, 3 }, { 0x1FB, 2, 4 }, { 0x3F8, 1, 5 }, { 0x3F9, 1, 6 }, { 0x3FA, 0, 7 }, { 0x3FB, 9, 1 }, { 0x7F8, 10, 1 }, { 0x7F9, 11, 1 }, { 0x7FA, 12, 1 }, { 0x7FB, 13, 1 }, { 0xFF8, 14, 1 }, { 0xFF9, 15, 1 }, { 0xFFA, 6, 2 }, { 0xFFB, 7, 2 }, { 0x1FF8, 8, 2 }, { 0x1FF9, 9, 2 }, { 0x1FFA, 10, 2 }, { 0x1FFB, 11, 2 }, { 0x3FF8, 12, 2 }, { 0x3FF9, 13, 2 }, { 0x3FFA, 14, 2 }, { 0x3FFB, 3, 3 }, { 0x7FF8, 4, 3 }, { 0x7FF9, 5, 3 }, { 0x7FFA, 6, 3 }, { 0x7FFB, 7, 3 }, { 0xFFF8, 8, 3 }, { 0xFFF9, 9, 3 }, { 0xFFFA, 10, 3 }, { 0xFFFB, 11, 3 }, { 0x1FFF8, 12, 3 }, { 0x1FFF9, 13, 3 }, { 0x1FFFA, 14, 3 }, { 0x1FFFB, 3, 4 }, { 0x3FFF8, 4, 4 }, { 0x3FFF9, 5, 4 }, { 0x3FFFA, 6, 4 }, { 0x3FFFB, 7, 4 }, { 0x7FFF8, 8, 4 }, { 0x7FFF9, 9, 4 }, { 0x7FFFA, 10, 4 }, { 0x7FFFB, 11, 4 }, { 0xFFFF8, 12, 4 }, { 0xFFFF9, 13, 4 }, { 0xFFFFA, 14, 4 }, { 0xFFFFB, 2, 5 }, { 0x1FFFF8, 3, 5 }, { 0x1FFFF9, 4, 5 }, { 0x1FFFFA, 5, 5 }, { 0x1FFFFB, 6, 5 }, { 0x3FFFF8, 7, 5 }, { 0x3FFFF9, 8, 5 }, { 0x3FFFFA, 9, 5 }, { 0x3FFFFB, 10, 5 }, { 0x7FFFF8, 11, 5 }, { 0x7FFFF9, 12, 5 }, { 0x7FFFFA, 13, 5 }, { 0x7FFFFB, 14, 5 }, { 0xFFFFF8, 2, 6 }, { 0xFFFFF9, 3, 6 }, { 0xFFFFFA, 4, 6 }, { 0xFFFFFB, 5, 6 }, { 0x1FFFFF8, 6, 6 }, { 0x1FFFFF9, 7, 6 }, { 0x1FFFFFA, 8, 6 }, { 0x1FFFFFB, 9, 6 }, { 0x3FFFFF8, 10, 6 }, { 0x3FFFFF9, 11, 6 }, { 0x3FFFFFA, 12, 6 }, { 0x3FFFFFB, 13, 6 }, { 0x7FFFFF8, 14, 6 }, { 0x7FFFFF9, 1, 7 }, { 0x7FFFFFA, 2, 7 }, { 0x7FFFFFB, 3, 7 }, { 0xFFFFFF8, 4, 7 }, { 0xFFFFFF9, 5, 7 }, { 0xFFFFFFA, 6, 7 }, { 0xFFFFFFB, 7, 7 }, { 0x1FFFFFF8, 8, 7 }, { 0x1FFFFFF9, 9, 7 }, { 0x1FFFFFFA, 10, 7 }, { 0x1FFFFFFB, 11, 7 }, { 0x3FFFFFF8, 12, 7 }, { 0x3FFFFFF9, 13, 7 }, { 0x3FFFFFFA, 14, 7 } }; /* * _find_magic * * Internal helper-function used to locate a given * VlcMagic entry. */ VlcMagic *_find_magic(guint magic) { gint low = 0; gint high = sizeof(_magic_values) / sizeof(VlcMagic) - 1; gint mid; while (low <= high) { mid = (low + high) / 2; if (_magic_values[mid].magic < magic) low = mid + 1; else if (_magic_values[mid].magic > magic) high = mid - 1; else return &_magic_values[mid]; } return NULL; } /* * _initialize_vlcdec_lookup * * Internal helper-function used to initialize * the lookup-table used by the VLC-decoder. */ void _initialize_vlcdec_lookup(gint8 *lookup_tbl) { gint8 util_buf[3072]; gint v1_start, v1_end, v1_dec, util_buf_offset; gint util_buf_offset_inc, buf1_val, samples_offset; gint v1, v2; gint8 *p, *p1, *p2, *p3; util_buf[0] = 0; util_buf[1] = 0; util_buf[2] = 0; util_buf[3] = 1; util_buf[4] = 1; util_buf[5] = 1; util_buf[765] = 1; util_buf[766] = 0; util_buf[767] = 1; lookup_tbl[255] = 255; lookup_tbl[256] = 1; v1_start = -3; v1_dec = 4; util_buf_offset = 11; util_buf_offset_inc = 12; buf1_val = 2; samples_offset = 509; do { v1 = v1_start; v1_end = -(abs(v1_start) + 1) / 2; v2 = 0; p2 = util_buf + util_buf_offset - 3; do { p1 = util_buf + ((v1 & 0xff) * 3); p1[0] = buf1_val; p1[1] = v2; p1[2] = buf1_val; p2[1] = buf1_val; p2[2] = v2 + 1; p2[3] = buf1_val; p3 = lookup_tbl + samples_offset + v2 + 1; p3[0] = v1 & 0xff; p3[1] = -(v1 & 0xff); v1++; v2 += 2; p2 -= 3; } while (v1 <= v1_end); v1_start -= v1_dec; v1_dec *= 2; util_buf_offset += util_buf_offset_inc; util_buf_offset_inc *= 2; buf1_val++; samples_offset += 255; } while (buf1_val <= 7); p = lookup_tbl + 1785 + util_buf[388]; p[0] = 129; } amsn-0.98.9/utils/webcamsn/src/colorspace.c0000644000175000017500000001112010225230720020401 0ustar billiobbilliob/* Copyright (C) 2005 Ole André Vadla Ravnås * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mimic-private.h" #define RED_INDEX_1 0 #define GREEN_INDEX_1 1 #define BLUE_INDEX_1 2 #define RED_INDEX_2 3 #define GREEN_INDEX_2 4 #define BLUE_INDEX_2 5 /* * _rgb_to_yuv * * Internal helper-function used to convert an image * from RGB 24-bpp packed-pixel to YUV420 planar. */ void _rgb_to_yuv(const guchar *input_rgb, guchar *output_y, guchar *output_cb, guchar *output_cr, gint width, gint height) { gint y, x; for (y = 0; y < height; y += 2) { const guchar *src1, *src2; guchar *dst1, *dst2, *dst3, *dst4; gint num_cols; src1 = input_rgb + ((height - 1 - y) * width * 3); src2 = input_rgb + ((height - 2 - y) * width * 3); dst1 = output_y + (y * width); dst2 = output_y + ((y + 1) * width); dst3 = output_cb + ((y / 2) * (width / 2)); dst4 = output_cr + ((y / 2) * (width / 2)); num_cols = width / 2; for (x = 0; x < num_cols; x++) { gint expr1, expr2, expr3, expr4, expr5, v; expr1 = (src1[BLUE_INDEX_1] * 19595) + (src1[GREEN_INDEX_1] * 38470) + (src1[RED_INDEX_1] * 7471); expr2 = (src1[BLUE_INDEX_2] * 19595) + (src1[GREEN_INDEX_2] * 38470) + (src1[RED_INDEX_2] * 7471); expr3 = (src2[BLUE_INDEX_1] * 19595) + (src2[GREEN_INDEX_1] * 38470) + (src2[RED_INDEX_1] * 7471); expr4 = (src2[BLUE_INDEX_2] * 19595) + (src2[GREEN_INDEX_2] * 38470) + (src2[RED_INDEX_2] * 7471); expr5 = expr1 + expr2 + expr3 + expr4; dst1[0] = expr1 >> 16; dst1[1] = expr2 >> 16; dst2[0] = expr3 >> 16; dst2[1] = expr4 >> 16; v = (((src1[BLUE_INDEX_1] + src1[BLUE_INDEX_2] + src2[BLUE_INDEX_1] + src2[BLUE_INDEX_2]) << 16) - expr5 + 131071) >> 16; dst3[0] = _clamp_value(((v * 57475) >> 18) + 128); v = (((src1[RED_INDEX_1] + src1[RED_INDEX_2] + src2[RED_INDEX_1] + src2[RED_INDEX_2]) << 16) - expr5 + 131071) >> 16; dst4[0] = ((v * 32244) >> 18) + 128; src1 += 6; src2 += 6; dst1 += 2; dst2 += 2; dst3++; dst4++; } } } /* * _yuv_to_rgb * * Internal helper-function used to convert an image * from YUV420 planar to RGB 24-bpp packed-pixel. */ void _yuv_to_rgb(const guchar *input_y, const guchar *input_cb, const guchar *input_cr, guchar *output_rgb, guint width, guint height) { const guchar *src_y, *src_cb, *src_cr; guchar *dst_rgb; guint i, j, rgb_stride; src_y = input_y; src_cb = input_cb; src_cr = input_cr; rgb_stride = width * 3; dst_rgb = output_rgb + (rgb_stride * (height - 1)); for (i = 0; i < height; i++) { const guchar *p_y, *p_cb, *p_cr; guchar *p_rgb; p_y = src_y; p_cb = src_cb; p_cr = src_cr; p_rgb = dst_rgb; for (j = 0; j < width; j++) { gint v; v = ((p_y[0] * 65536) + ((p_cr[0] - 128) * 133169)) / 65536; p_rgb[0] = _clamp_value(v); v = ((p_y[0] * 65536) - ((p_cr[0] - 128) * 25821) - ((p_cb[0] - 128) * 38076)) / 65536; p_rgb[1] = _clamp_value(v); v = ((p_y[0] * 65536) + ((p_cb[0] - 128) * 74711)) / 65536; p_rgb[2] = _clamp_value(v); p_y++; if ((j + 1) % 2 == 0) { p_cb++; p_cr++; } p_rgb += 3; } src_y += width; if ((i + 1) % 2 == 0) { src_cb += (width + 1) / 2; src_cr += (width + 1) / 2; } dst_rgb -= rgb_stride; } } amsn-0.98.9/utils/webcamsn/src/libmimic.dsp0000755000175000017500000000725410734050401020421 0ustar billiobbilliob# Microsoft Developer Studio Project File - Name="libmimic" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Static Library" 0x0104 CFG=libmimic - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "libmimic.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "libmimic.mak" CFG="libmimic - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "libmimic - Win32 Release" (based on "Win32 (x86) Static Library") !MESSAGE "libmimic - Win32 Debug" (based on "Win32 (x86) Static Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "libmimic - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c # ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c # ADD BASE RSC /l 0x40c /d "NDEBUG" # ADD RSC /l 0x40c /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LIB32=link.exe -lib # ADD BASE LIB32 /nologo # ADD LIB32 /nologo !ELSEIF "$(CFG)" == "libmimic - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c # ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c # ADD BASE RSC /l 0x40c /d "_DEBUG" # ADD RSC /l 0x40c /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LIB32=link.exe -lib # ADD BASE LIB32 /nologo # ADD LIB32 /nologo !ENDIF # Begin Target # Name "libmimic - Win32 Release" # Name "libmimic - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=.\bitstring.c # End Source File # Begin Source File SOURCE=.\colorspace.c # End Source File # Begin Source File SOURCE=.\deblock.c # End Source File # Begin Source File SOURCE=.\decode.c # End Source File # Begin Source File SOURCE=.\encode.c # End Source File # Begin Source File SOURCE=.\fdct_quant.c # End Source File # Begin Source File SOURCE=.\idct_dequant.c # End Source File # Begin Source File SOURCE=.\mimic.c # End Source File # Begin Source File SOURCE=.\vlc_common.c # End Source File # Begin Source File SOURCE=.\vlc_decode.c # End Source File # Begin Source File SOURCE=.\vlc_encode.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=.\constants.h # End Source File # Begin Source File SOURCE=.\glib_replacement.h # End Source File # Begin Source File SOURCE=".\mimic-private.h" # End Source File # Begin Source File SOURCE=.\mimic.h # End Source File # End Group # End Target # End Project amsn-0.98.9/utils/webcamsn/src/fdct_quant.c0000644000175000017500000001142410225230720020406 0ustar billiobbilliob/* Copyright (C) 2005 Ole André Vadla Ravnås * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mimic-private.h" extern guchar _col_zag[64]; void _fdct_quant_block(MimCtx *ctx, gint *block, const guchar *src, gint stride, gboolean is_chrom, gint num_coeffs) { gint sum1, sum2, sum3, sum4; gint diff1, diff2, diff3, diff4; gint ex1, ex2, ex3, ex4, ex5; gint i, j; const guchar *p1; gint *iptr; /* * Forward DCT, first pass (horizontal). */ p1 = src; iptr = block; for (i = 0; i < 8; i++) { sum1 = p1[0] + p1[7]; sum2 = p1[1] + p1[6]; sum3 = p1[2] + p1[5]; sum4 = p1[3] + p1[4]; diff1 = p1[0] - p1[7]; diff2 = p1[1] - p1[6]; diff3 = p1[2] - p1[5]; diff4 = p1[3] - p1[4]; ex1 = ((diff1 + diff4) * 851) - (diff1 * 282); ex2 = ((diff2 + diff3) * 1004) - (diff2 * 804); ex3 = ((diff2 + diff3) * 1004) - (diff3 * 1204); ex4 = ((diff1 + diff4) * 851) - (diff4 * 1420); iptr[0] = sum1 + sum2 + sum3 + sum4; iptr[2] = (((sum1 - sum4) * 1337) + ((sum2 - sum3) * 554)) >> 10; iptr[4] = sum1 - sum2 - sum3 + sum4; iptr[1] = (ex1 + ex2 + ex3 + ex4) >> 10; iptr[3] = ((ex4 - ex2) * 181) >> 17; iptr[5] = ((ex1 - ex3) * 181) >> 17; p1 += stride; iptr += 8; } p1 = src; iptr = block; /* * Forward DCT, first pass (vertical). * * This is only known to be correct for i == 0, though it seems to be ... */ for (i = 0; i < 6; i++) { sum1 = iptr[ 0 + i] + iptr[56 + i]; sum2 = iptr[ 8 + i] + iptr[48 + i]; sum3 = iptr[16 + i] + iptr[40 + i]; sum4 = iptr[24 + i] + iptr[32 + i]; diff1 = iptr[ 0 + i] - iptr[56 + i]; diff2 = iptr[ 8 + i] - iptr[48 + i]; diff3 = iptr[16 + i] - iptr[40 + i]; diff4 = iptr[24 + i] - iptr[32 + i]; ex1 = ((diff1 + diff4) * 851) - (diff1 * 282); ex2 = ((diff2 + diff3) * 1004) - (diff2 * 804); ex3 = ((diff2 + diff3) * 1004) - (diff3 * 1204); ex4 = ((diff1 + diff4) * 851) - (diff4 * 1420); ex5 = (sum1 + sum2 - sum3 - sum4) * 554; for (j = 0; j < 7 - i; j++) { switch (j) { case 0: iptr[ 0 + i] = (16 + sum1 + sum2 + sum3 + sum4) >> 5; break; case 1: iptr[ 8 + i] = (16384 + ex1 + ex2 + ex3 + ex4) >> 15; break; case 2: iptr[16 + i] = (16384 + ((sum1 - sum4) * 783) + ex5) >> 15; break; case 3: iptr[24 + i] = (8192 + (((ex4 - ex2) >> 8) * 181)) >> 14; break; case 4: iptr[32 + i] = (16 + sum1 - sum2 - sum3 + sum4) >> 5; break; case 5: iptr[40 + i] = (8192 + (((ex1 - ex3) >> 8) * 181)) >> 14; break; case 6: iptr[48 + i] = (16384 - ((sum2 - sum3) * 1891) + ex5) >> 15; break; } } } /* * Quantize. */ block[0] /= 2; block[8] /= 4; block[1] /= 4; block[6] = 0; if (num_coeffs > 3) { gdouble s = (10000 - ctx->quality) * 10.0 * (gfloat) 9.9999997e-5; if (s > 10.0) s = 10.0; else if (is_chrom != 0 && s < 1.0) s = 1.0; else if (s < 2.0) s = 2.0; s = 1.0 / s; for (i = 3; i < num_coeffs; i++) { gdouble coeff, r; coeff = block[_col_zag[i]] * s; r = coeff - (gint) coeff; if (r >= 0.6) block[_col_zag[i]] = (gint) (coeff + 1.0); else if (r <= -0.6) block[_col_zag[i]] = (gint) (coeff - 1.0); else block[_col_zag[i]] = (gint) coeff; if (block[_col_zag[i]] > 120) block[_col_zag[i]] = 120; else if (block[_col_zag[i]] < -120) block[_col_zag[i]] = -120; } } if (block[8] > 120) block[8] = 120; else if (block[8] < -120) block[8] = -120; if (block[1] > 120) block[1] = 120; else if (block[1] < -120) block[1] = -120; for (i = num_coeffs; i < 64; i++) block[_col_zag[i]] = 0; } amsn-0.98.9/utils/webcamsn/src/vlc_decode.c0000644000175000017500000000675610225230720020361 0ustar billiobbilliob/* Copyright (C) 2005 Ole Andr Vadla Ravns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "mimic-private.h" extern guchar _col_zag[64]; /* * _vlc_decode_block * * De-serialize (reconstruct) a variable length coded 8x8 block. */ gboolean _vlc_decode_block(MimCtx *ctx, gint *block, gint num_coeffs) { guint pos; memset(block, 0, 64 * sizeof(gint)); /* The DC-value is read in as is. */ block[0] = _read_bits(ctx, 8); for (pos = 1; pos < num_coeffs; pos++) { guint prev_data_index, prev_cur_chunk_len, prev_chunk; guint value, num_bits; gboolean prev_read_odd, found_magic; /* Save context. */ prev_data_index = ctx->data_index; prev_cur_chunk_len = ctx->cur_chunk_len; prev_chunk = ctx->cur_chunk; prev_read_odd = ctx->read_odd; /* Grab 16 bits. */ value = _read_bits(ctx, 16) << 16; /* Restore context. */ ctx->data_index = prev_data_index; ctx->cur_chunk_len = prev_cur_chunk_len; ctx->cur_chunk = prev_chunk; ctx->read_odd = prev_read_odd; /* Analyze and determine number of bits to read initially. */ num_bits = 3; if ((value >> 30) == 0 || (value >> 30) == 1) { num_bits = 2; } else if ((value & 0xE0000000) != 0x80000000) { guint nibble = value >> 28; if (nibble == 11 || nibble == 12) { num_bits = 4; } else if (nibble == 10) { _read_bits(ctx, 4); return TRUE; } else { if (((value << 2) & 0x8000000) == 0) num_bits = 2; num_bits += 2; } } /* Read that number of bits. */ value = _read_bits(ctx, num_bits); /* * Look up the current value against the magic ones, * and continue extending it bit by bit from the input * stream until the magic value is found or we have * read 32 bits (in which case we give up). */ found_magic = FALSE; while (!found_magic) { VlcMagic *magic; if (num_bits > 32) return FALSE; magic = _find_magic(value); if (magic != NULL) { pos += magic->pos_add; num_bits = magic->num_bits; found_magic = TRUE; } else { value <<= 1; value |= _read_bits(ctx, 1); num_bits++; } } /* Read the number of bits given by magic value entry. */ value = _read_bits(ctx, num_bits); /* Gotcha! :-) */ block[_col_zag[pos]] = ctx->vlcdec_lookup[(num_bits * 255) + value]; } return TRUE; } amsn-0.98.9/utils/webcamsn/src/decode.c0000644000175000017500000002150310225230720017500 0ustar billiobbilliob/* Copyright (C) 2005 Ole Andr Vadla Ravns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "mimic-private.h" static gboolean decode(MimCtx *ctx, gboolean is_pframe); /** * Decode a MIMIC-encoded frame into RGB data. * * @param ctx the mimic context * @param input_buffer buffer containing the MIMIC-encoded frame to decode * @param output_buffer buffer that will receive the decoded frame in RGB 24-bpp packed pixel top-down format * (use #mimic_get_property to determine the required buffer size, as well as frame width and height) * @returns #TRUE on success */ gboolean mimic_decode_frame(MimCtx *ctx, const guchar *input_buffer, guchar *output_buffer) { gboolean result, is_pframe; guchar *input_y, *input_cr, *input_cb; gint width, height; /* * Some sanity checks. */ if (ctx == NULL || input_buffer == NULL || output_buffer == NULL) { return FALSE; } if (!ctx->decoder_initialized) return FALSE; /* * Get frame dimensions. */ width = GUINT16_FROM_LE(*((guint16 *) (input_buffer + 4))); height = GUINT16_FROM_LE(*((guint16 *) (input_buffer + 6))); /* * Resolution changing is not supported. */ if (width != ctx->frame_width || height != ctx->frame_height) { return FALSE; } /* * Increment frame counter. */ ctx->frame_num++; /* * Initialize state. */ ctx->quality = GUINT16_FROM_LE(*((guint16 *) (input_buffer + 2))); is_pframe = GUINT32_FROM_LE(*((guint32 *) (input_buffer + 12))); ctx->num_coeffs = input_buffer[16]; ctx->data_buffer = (gchar *) (input_buffer + 20); ctx->data_index = 0; ctx->cur_chunk_len = 16; ctx->read_odd = FALSE; /* * Decode frame. */ if (!(is_pframe && ctx->prev_frame_buf == NULL)) result = decode(ctx, is_pframe); else result = FALSE; /* * Perform YUV 420 to RGB conversion. */ input_y = ctx->cur_frame_buf; input_cr = ctx->cur_frame_buf + ctx->y_size; input_cb = ctx->cur_frame_buf + ctx->y_size + ctx->crcb_size; _yuv_to_rgb(input_y, input_cb, input_cr, output_buffer, ctx->frame_width, ctx->frame_height); return result; } /* * decode_main * * Main decoding loop. */ static gboolean decode(MimCtx *ctx, gboolean is_pframe) { gint y, x, i, j, chrom_ch, *bptr, base_offset, offset; gint dct_block[64]; guchar *src, *dst, *p; guint32 bit; /* * Clear Cr and Cb planes. */ p = ctx->cur_frame_buf + ctx->y_size; memset(p, 128, 2 * ctx->crcb_size); /* * Decode Y plane. */ for (y = 0; y < ctx->num_vblocks_y; y++) { base_offset = ctx->y_stride * 8 * y; src = ctx->prev_frame_buf + base_offset; dst = ctx->cur_frame_buf + base_offset; for (x = 0; x < ctx->num_hblocks_y; x++) { /* Check for a change condition in the current block. */ if (is_pframe) bit = _read_bits(ctx, 1); else bit = 0; if (bit == 0) { /* Yes: Is the new content the same as it was in one of * the 15 last frames preceding the previous? */ if (is_pframe) bit = _read_bits(ctx, 1); if (bit == 0) { /* No: decode it. */ if (_vlc_decode_block(ctx, dct_block, ctx->num_coeffs) == FALSE) { /* Corruped frame, return. */ return FALSE; } _idct_dequant_block(ctx, dct_block, 0); bptr = dct_block; for (i = 0; i < 8; i++) { offset = ctx->y_stride * i; for (j = 0; j < 8; j++) { guint v; if (bptr[j] <= 255) v = (bptr[j] >= 0) ? bptr[j] : 0; else v = 255; *(dst + offset + j) = v; } bptr += 8; } } else { guint32 backref; /* Yes: read the backreference (4 bits) and copy. */ backref = _read_bits(ctx, 4); p = ctx->buf_ptrs[(ctx->ptr_index + backref) % 16]; p += base_offset + (x * 8); for (i = 0; i < 8; i++) { offset = ctx->y_stride * i; memcpy(dst + offset, p + offset, 8); } } } else { /* No change no worries: just copy from the previous frame. */ for (i = 0; i < 8; i++) { offset = ctx->y_stride * i; memcpy(dst + offset, src + offset, 8); } } src += 8; dst += 8; } } /* * Decode Cr and Cb planes. */ for (chrom_ch = 0; chrom_ch < 2; chrom_ch++) { base_offset = ctx->y_size + (ctx->crcb_size * chrom_ch); for (y = 0; y < ctx->num_vblocks_cbcr; y++) { guint num_rows = 8; /* The last row of blocks in chrominance for 160x120 resolution * is half the normal height and must be accounted for. */ if (y + 1 == ctx->num_vblocks_cbcr && ctx->frame_height % 16 != 0) num_rows = 4; offset = base_offset + (ctx->crcb_stride * 8 * y); src = ctx->prev_frame_buf + offset; dst = ctx->cur_frame_buf + offset; for (x = 0; x < ctx->num_hblocks_cbcr; x++) { /* Check for a change condition in the current block. */ if (is_pframe) bit = _read_bits(ctx, 1); else bit = 1; if (bit == 1) { /* Yes: decode it. */ if (_vlc_decode_block(ctx, dct_block, ctx->num_coeffs) == FALSE) { /* Corrupted frame: clear Cr and Cb planes and return. */ p = ctx->cur_frame_buf + ctx->y_size; memset(p, 128, ctx->crcb_size * 2); return FALSE; } _idct_dequant_block(ctx, dct_block, 1); for (i = 0; i < num_rows; i++) { p = dst + (ctx->crcb_stride * i); for (j = 0; j < 8; j++) p[j] = dct_block[(i * 8) + j]; } } else { /* No change no worries: just copy from the previous frame. */ for (i = 0; i < num_rows; i++) { offset = ctx->crcb_stride * i; memcpy(dst + offset, src + offset, 8); } } src += 8; dst += 8; } } } /* * Make a copy of the current frame and store in * the circular pointer list of 16 entries. */ ctx->prev_frame_buf = ctx->buf_ptrs[ctx->ptr_index]; memcpy(ctx->prev_frame_buf, ctx->cur_frame_buf, ctx->y_size + (ctx->crcb_size * 2)); if (--ctx->ptr_index < 0) ctx->ptr_index = 15; /* * Perform deblocking on all planes. */ _deblock(ctx->cur_frame_buf, ctx->y_stride, ctx->y_row_count); _deblock(ctx->cur_frame_buf + ctx->y_size, ctx->crcb_stride, ctx->crcb_row_count); _deblock(ctx->cur_frame_buf + ctx->y_size + ctx->crcb_size, ctx->crcb_stride, ctx->crcb_row_count); return TRUE; } amsn-0.98.9/utils/webcamsn/src/constants.h0000644000175000017500000015031110250007176020303 0ustar billiobbilliobint shifts_right[] = { 25, 20, 15, 10, 27, 23, 18, 12, 28, 21, 16, 9, 26, 22, 17, 11 }; int shifts_left[] = { 7, 12, 17, 22, 5, 9, 14, 20, 4, 11, 16, 23, 6, 10, 15, 21 }; int choose_data_idx[] = { 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 }; int const_mult[] = { -1, -1, +1, -1, -1, +1, -1, -1, +1, -1, -1, -1, +1, -1, -1, +1, -1, -1, +1, -1, -1, +1, -1, -1, +1, -1, -1, +1, -1, -1, +1, -1, -1, -1, +1, -1, -1, +1, -1, -1, +1, -1, -1, +1, -1, -1, +1, -1, -1, +1, -1, -1, +1, -1, -1, -1, +1, -1, -1, +1, -1, -1, +1, -1, }; int const_values[] = { 0x28955B88, 0x173848AA, 0x242070DB, 0x3E423112, 0x0A83F051, 0x4787C62A, 0x57CFB9ED, 0x2B96AFF, 0x698098D8, 0x74BB0851, 0x0A44F, 0x76A32842, 0x6B901122, 0x2678E6D, 0x5986BC72, 0x49B40821, 0x9E1DA9E, 0x3FBF4CC0, 0x265E5A51, 0x16493856, 0x29D0EFA3, 0x2441453, 0x275E197F, 0x182C0438, 0x21E1CDE6, 0x3CC8F82A, 0x0B2AF279, 0x455A14ED, 0x561C16FB, 0x3105C08, 0x676F02D9, 0x72D5B376, 0x5C6BE, 0x788E097F, 0x6D9D6122, 0x21AC7F4, 0x5B4115BC, 0x4BDECFA9, 0x944B4A0, 0x41404390, 0x289B7EC6, 0x155ED806, 0x2B10CF7B, 0x4881D05, 0x262B2FC7, 0x1924661B, 0x1FA27CF8, 0x3B53A99B, 0x0BD6DDBC, 0x432AFF97, 0x546BDC59, 0x36C5FC7, 0x655B59C3, 0x70F3336E, 0x100B83, 0x7A7BA22F, 0x6FA87E4F, 0x1D31920, 0x5CFEBCEC, 0x4E0811A1, 0x8AC817E, 0x42C50DCB, 0x2AD7D2BB, 0x14792C6F }; static int append_size = 16; static int key_append[] = { 0x7CF1DC2C, 0x57A3C467, 0x16DE0737, 0x5AF79D21, 0x1E020846, 0x0A8C89907, 0x216BE734, 0x1FF75D58, 0x9B9197A, 0x4C0F074F, 0x760BF742, 0x416CCB1F, 0x36BB041F, 0x0B532FC6E, 0x2D778922, 0x0F8548D07, 0x978C7807, 0x6292C537, 0x9F364930, 0x0C28BF77C, 0x0A7BD6244, 0x6772C34F, 0x65C47E56, 0x8D9CE01F, 0x22D06933, 0x0F5E40729, 0x80EF8448, 0x7761C03C, 0x1E95114F, 0x2767BBE, 0x10B491B7, 0x25B4F277, 0x4474CAC0, 0x6CA5F2C8, 0x56261D13, 0x1C9098F6, 0x5A989670, 0x0B084C431, 0x16A75876, 0x6351B06A, 0x0FC93CB00, 0x8CB24F39, 0x0A4BD7B0A, 0x324FD01F, 0x41E54B28, 0x0D134052D, 0x2AA45D27, 0x0D871C42F, 0x33C7CA64, 0x0C9DAA657, 0x9AFDBB2C, 0x0DB842D29, 0x314D6A27, 0x0C23A03, 0x68210E49, 0x531DD45A, 0x0F5A6422C, 0x0E8109311, 0x0CA7E9417, 0x0ADD7A45A, 0x691BC101, 0x65708949, 0x0E2F9E335, 0x41C9B359, 0x16408632, 0x7113C132, 0x3879AE77, 0x70D81C23, 0x21988564, 0x4E20076E, 0x0D329CD0D, 0x1D2C5165, 0x0DAD25627, 0x78E74818, 0x507B2105, 0x1BB8A24F, 0x491C4E45, 0x7A1F7F2C, 0x0F329677F, 0x7DE3182A, 0x44FA2504, 0x8E27232C, 0x58684653, 0x7547902B, 0x8EE95D2F, 0x0C089541C, 0x0C8646406, 0x8390A05B, 0x0A89AE72D, 0x92E3F81D, 0x30684536, 0x11B6A82F, 0x0F7538267, 0x1262296C, 0x527F5C09, 0x0D94081A, 0x8375EA1E, 0x8AF80A01, 0x7E6C253D, 0x0A40D7003, 0x0D818126F, 0x5196F24A, 0x0C239C168, 0x0B2EB6816, 0x4DBD36D, 0x1E2AD595, 0x2FF01C9A, 0x46355255, 0x713F1209, 0x67294722, 0x739FC0E0, 0x1D6F30D9, 0x4FF59511, 0x0E8E5E825, 0x4516184A, 0x0DDDEF340, 0x0A86F3D42, 0x0D7B7C50, 0x606F941C, 0x500A2570, 0x9F5E756E, 0x90D7D952, 0x61C0CD1F, 0x96B2F755, 0x0A339033F, 0x0B33F2A29, 0x0A4460070, 0x26AFED5D, 0x3E38352A, 0x22B3252D, 0x0CBBC5D61, 0x16514719, 0x73491878, 0x8DF61E4A, 0x0C93CB02F, 0x3DC7535B, 0x9FAB0138, 0x96E0BB15, 0x5061DD03, 0x2B806352, 0x4065FD94, 0x1C53F61D, 0x0E8BFF29, 0x720EE35A, 0x77617F2, 0x748CA63A, 0x5A3A3B0F, 0x8D73FEF, 0x4FE07F0B, 0x0E3F14C6A, 0x0C03ECB2E, 0x0EE3EF579, 0x3F5E8FC5, 0x2695CBCB, 0x1062C762, 0x3C76F926, 0x0D43EC377, 0x2938ED3F, 0x3DB2175A, 0x1277F821, 0x7E11198, 0x51E7CE90, 0x6E87ABC4, 0x60F42887, 0x95659405, 0x0F204F06A, 0x0FBFB7E40, 0x3411963D, 0x88E5AB00, 0x4B5D5C44, 0x6091F90F, 0x0E093DA7B, 0x2B3CDC1A, 0x5CE0E400, 0x86379F08, 0x0F3004517, 0x9D45E83B, 0x0ABA5756, 0x6335EB55, 0x0EC256847, 0x0EDABA440, 0x2374B604, 0x0DB645D41, 0x6175CB7D, 0x44734F53, 0x60564A11, 0x7878F579, 0x19B2124B, 0x4B64A19A, 0x7126B6A7, 0x4E7283BB, 0x587C840, 0x0BE99820F, 0x54F14A28, 0x92AE7523, 0x54FF1615, 0x355901F4, 0x77DCAA71, 0x65812158, 0x588BF36, 0x0D9075128, 0x0E8A1A662, 0x0AF6FC10F, 0x5442D43, 0x44828B63, 0x35A76018, 0x0F844725A, 0x0E2C7731F, 0x3F61B86E, 0x5C7A5D30, 0x0CEEDDB66, 0x2D0D5D2F, 0x7FEE1335, 0x0A9523928, 0x8E82282D, 0x0C4616308, 0x9A98339, 0x7FB1D27, 0x0DD137653, 0x9237BB0A, 0x3CE4F397, 0x2F917E1F, 0x11340243, 0x6A8D5D9E, 0x533CDE8C, 0x233EDF91, 0x482C1D41, 0x19B8FF0E, 0x870A7050, 0x58CF7172, 0x7200EE0F, 0x6012C178, 0x40711855, 0x2170AF1F, 0x6556EE3B, 0x85F3A338, 0x57171038, 0x5E9B6016, 0x67BB1758, 0x9678C826, 0x0BA15BE46, 0x35A9F33E, 0x0C3852556, 0x3904D27B, 0x0DFFB2C67, 0x52084E03, 0x0FD653504, 0x0E8A4B020, 0x59036C2A, 0x0DA79AB57, 0x7BDC6B2B, 0x16299725, 0x0E3B62C18, 0x0E18D7174, 0x91E84430, 0x40E5F800, 0x0DAEDEC60, 0x61A70950, 0x0E309007D, 0x61F85C31, 0x0B9767B42, 0x560AEE0C, 0x0C20A1E2A, 0x0F9E79317, 0x0D2429AC, 0x1A8B7DC9, 0x23C53AAF, 0x54F6BB51, 0x85FC6C7C, 0x0E5964F28, 0x650A760B, 0x3F122B43, 0x1C2A10BF, 0x745FD9F3, 0x635FDCED, 0x25BFDAF4, 0x7A98E964, 0x767C3243, 0x0E2E0206F, 0x0D39B550F, 0x217C7136, 0x202AAD48, 0x2B137203, 0x272EC36A, 0x3F4BFE0E, 0x7BAD3165, 0x74920334, 0x1939EB6F, 0x0DC543B35, 0x579C0331, 0x7B314821, 0x95CBB677, 0x0ADA6F13D, 0x3D3C664B, 0x8EB34A0F, 0x25218F6A, 0x649D7231, 0x0D8F825F, 0x0F3B23C4F, 0x0EA99DF2D, 0x0F225D207, 0x58BDB25A, 0x29AC0A71, 0x0D66156F, 0x32B9FBC9, 0x27974E36, 0x6CD9C3AE, 0x29F77886, 0x193F3A73, 0x0EA82A62C, 0x0CF818D30, 0x6A35180E, 0x47403347, 0x0B8467A65, 0x9EE22241, 0x868B3156, 0x33F4AB4A, 0x12752675, 0x0A0C41C46, 0x0F49E77F, 0x69112A26, 0x1BF66467, 0x0A4149E77, 0x17B81B64, 0x5832CB32, 0x33C8E806, 0x3CD9AA4E, 0x0BCCF3D64, 0x40576B66, 0x2F8CE71D, 0x0A6691D12, 0x327D3D6E, 0x88499A78, 0x0D0152803, 0x40E3525D, 0x997E834, 0x72D82F33, 0x4785D81A, 0x47D2056, 0x8B176A26, 0x31087F47, 0x0D3FEAD06, 0x0F54C8234, 0x7948B20E, 0x8C45286C, 0x932FA575, 0x0FFD3E364, 0x0BF39D436, 0x0A5A4CB6A, 0x9F98002B, 0x0CF82BB36, 0x0FB6F510, 0x0BA8E6512, 0x7397592E, 0x266E1175, 0x12C13045, 0x0A65F4235, 0x6247BC43, 0x0CF906E29, 0x0E6B6AD1B, 0x1CA3FF31, 0x7FEB2E53, 0x7F398F82, 0x134EF25D, 0x4510B43E, 0x59173E67, 0x22B4260F, 0x0B8E8E371, 0x0A09C1602, 0x27314765, 0x43004E18, 0x0D2A49549, 0x0FA2FF56B, 0x394DD04C, 0x4BED4758, 0x86751D58, 0x0CC7C7542, 0x4AC12B3D, 0x46AFF10E, 0x7221412D, 0x0EA592C68, 0x1532AD45, 0x81D7363E, 0x0A4E8917A, 0x347EEFC2, 0x3B056C76, 0x3A5030C6, 0x3BD5B048, 0x98D0477, 0x863A3169, 0x15E0F644, 0x9A60A858, 0x0FB34BD24, 0x2E14E24E, 0x0B47DE632, 0x41457163, 0x872B2036, 0x0D6310D42, 0x0F92D5555, 0x28C83638, 0x0FD625427, 0x3C2EA36D, 0x0FA6CCC01, 0x0F8924913, 0x757B733A, 0x455A145A, 0x7E08676B, 0x42F8E87C, 0x8F1B4017, 0x0C4B7587A, 0x0B4192A2A, 0x79756C7F, 0x0D9E90540, 0x35F16068, 0x1E5EFE79, 0x62B30C34, 0x0DC36A91B, 0x0D507C139, 0x91DC555D, 0x0E5C3AD12, 0x5B42F222, 0x0A6BC4C22, 0x7F24566B, 0x5677AF47, 0x0D5D02E71, 0x33A23C1E, 0x97BC202B, 0x5CFC4E27, 0x0AD44960, 0x90EA7500, 0x84C4855F, 0x7379E07, 0x0CD18196E, 0x7E315261, 0x0FFC9E71A, 0x42948C28, 0x0C38B663B, 0x7ED24E06, 0x848C7525, 0x53A7A652, 0x428AA700, 0x38A69F4F, 0x0CC1C1352, 0x1C74AD40, 0x6D970038, 0x0EA7A114C, 0x7E27BA74, 0x49CEA953, 0x0BF82D205, 0x0F041052, 0x2E925766, 0x1AC5C428, 0x0B5C05C74, 0x0AEB6AD51, 0x713C7470, 0x8A918B65, 0x0E158EA6F, 0x8F9941B, 0x0E78DDA0C, 0x0EB2C3450, 0x99E30A1C, 0x6B52606C, 0x0F363D257, 0x66FC230A, 0x0EA83B24D, 0x0F22DBA72, 0x0A890B032, 0x0AD0F1909, 0x70000979, 0x2D1D2658, 0x0B7BF5B, 0x0B38AB079, 0x65C3C527, 0x0CDD3D22D, 0x0CFFE5D3A, 0x0D35AC65F, 0x0B74EE479, 0x4D26182F, 0x1C297033, 0x77D1B67F, 0x5C2A2801, 0x4BBBC719, 0x91967B28, 0x11EB8475, 0x0F971756B, 0x2D3EF18, 0x9C7C105B, 0x0DACA5F5B, 0x0BCC8434, 0x830AEB67, 0x0C6F7932B, 0x0A4AF8F50, 0x0EE5C4B54, 0x0B95B6603, 0x0AACB35A, 0x0D8E0FD21, 0x0AB892076, 0x0B23C640D, 0x86F0162B, 0x1C8A296F, 0x0DF598A65, 0x86A7D606, 0x0CF14DA68, 0x451D500D, 0x537BA934, 0x9E133823, 0x1878166D, 0x0BCA8D2E, 0x0EB395052, 0x34A18620, 0x829B442E, 0x47647853, 0x7F5C4E3A, 0x1332C056, 0x584FFD48, 0x78CEC325, 0x1605B06F, 0x0F4CB0D24, 0x53992301, 0x21D13424, 0x77D6F80B, 0x1991B72C, 0x0C580C474, 0x66334460, 0x0D2EC1D30, 0x0CF2C784F, 0x3E144202, 0x7D763E26, 0x8169DC5C, 0x0C404592D, 0x99006815, 0x61C36642, 0x4BAC2F34, 0x6815427E, 0x0A6E0B64F, 0x9E27D968, 0x6297A21, 0x0BE58CD3C, 0x0A9F16617, 0x0F162CA73, 0x0F2F9535D, 0x2B8DAB45, 0x38C74247, 0x7256A217, 0x3FBF6B1C, 0x91164010, 0x0EA24663D, 0x55C41B0C, 0x85E24D34, 0x3DBE893E, 0x76955030, 0x0FDB84640, 0x564F416B, 0x3B161525, 0x63EC8A20, 0x283C5F1B, 0x0A438D74, 0x0A100CD22, 0x0A6B29D41, 0x8BAC6951, 0x66052650, 0x3FB30557, 0x0EC6FD013, 0x0B1B15504, 0x0A8C84755, 0x92508763, 0x4FD92E6D, 0x0AEF1C176, 0x50A95420, 0x0F9CA9504, 0x0A0548C6A, 0x43A3A87D, 0x2458414A, 0x0D81BCF31, 0x0B5F94A15, 0x6317AD66, 0x28C1C503, 0x7A9F959D, 0x731C7C51, 0x162A3DBF, 0x0DDDC3A11, 0x2E711923, 0x0ECCDA336, 0x332C7C7C, 0x69872E48, 0x4FBA2E57, 0x5C68DB17, 0x73CABB3C, 0x0F0BAFB79, 0x21B7959, 0x0FF76250E, 0x56C0214A, 0x41CE7E30, 0x0EBE6F521, 0x772774E, 0x0E996C605, 0x7E377D05, 0x574BA63B, 0x9888887C, 0x0CEE0D125, 0x50163C40, 0x38DD1467, 0x11847A23, 0x746E7D0A, 0x1CCDE544, 0x36F81567, 0x28B6E831, 0x3672427D, 0x669C760B, 0x9061F363, 0x69405051, 0x4379B11C, 0x0BFD20C07, 0x550EF407, 0x76A52D19, 0x285A3B4F, 0x0A4C8225F, 0x0D20D0931, 0x9C24F70B, 0x94831E59, 0x0D428820A, 0x9B9B1C1A, 0x0EB434023, 0x16F7003B, 0x8682123C, 0x0F2B5B771, 0x0FF8DC740, 0x4BA8F41, 0x49015E2D, 0x9716503D, 0x0D39A6167, 0x99179A6D, 0x0CFF36424, 0x0E41EDC0A, 0x0E861778, 0x0E0EC483D, 0x0AB9CA143, 0x0E60B4269, 0x5A183C18, 0x1139184F, 0x766D354D, 0x0C3588C69, 0x54B2C96B, 0x35404254, 0x18678071, 0x0CA57F704, 0x5E9A7D23, 0x0BC2FA350, 0x9D650036, 0x0FABE742F, 0x50B3C129, 0x718E8240, 0x955A9149, 0x3BF7014D, 0x8785837B, 0x1BDDA305, 0x2EADB93E, 0x87134B3C, 0x20973347, 0x77AE176C, 0x1E2A9B79, 0x0F331952E, 0x11C6B159, 0x0EE1D001E, 0x0D7507139, 0x1F4CC951, 0x0CE0A495B, 0x82ED127D, 0x5580B3B, 0x28238573, 0x93262B4C, 0x7BC54008, 0x0EB7B115D, 0x0E7D8F437, 0x0B105835C, 0x3E3914E, 0x0B230EC3C, 0x0FA00000, 0x0BF12351F, 0x4F96EC72, 0x95F752F, 0x0FC6F648, 0x0C0246F33, 0x9EB90679, 0x4BBDF815, 0x48AAF22E, 0x0B996AA7E, 0x796AB254, 0x0CFBD3D6B, 0x0D92DDE45, 0x0F018CA40, 0x0EDE7D864, 0x0CC5F7374, 0x1DF7B1A, 0x0DB05D902, 0x0A4B0E42D, 0x0AA6C8E, 0x5557C67F, 0x7426E5D7, 0x6AFE2A4D, 0x0D133A751, 0x0BAC42277, 0x0A148912F, 0x0BCAFB82E, 0x0A19D172F, 0x524E140C, 0x0BF924A7D, 0x53CE036C, 0x61EE140C, 0x7EA57F1C, 0x0A264F05E, 0x6A4D8A3B, 0x8E6B7665, 0x63895F12, 0x8079134, 0x0D9286F7B, 0x0AB335241, 0x0C19D3B33, 0x52932150, 0x7AF18F2C, 0x9BCB1979, 0x42ACEB10, 0x67D96811, 0x672B8D6D, 0x448B672B, 0x43DF4114, 0x0BDC711B, 0x64B6AC17, 0x0ECEF6372, 0x327A6946, 0x8A39FD3E, 0x0BE230B44, 0x0EC3E8C3D, 0x2B828E6E, 0x7AD3C372, 0x8DDCA36C, 0x7DD0A27A, 0x3A660E70, 0x0E1AAA758, 0x0DEBEB706, 0x0B80B8E0C, 0x830F9837, 0x480C4242, 0x46770472, 0x0E698F749, 0x5013D376, 0x1FA0736D, 0x91CC490B, 0x11B10E2A, 0x7133953D, 0x0BBED937, 0x0AC7C2823, 0x0B4DF804E, 0x73974249, 0x14A8B510, 0x0F86AE879, 0x0B676845D, 0x1F84272C, 0x5C219511, 0x0A266E84F, 0x558F3B68, 0x2A1F517E, 0x5DD4478, 0x1DF2B6A5, 0x11DD203F, 0x0DB5DB706, 0x0CB19C11C, 0x8EADC339, 0x15C4C576, 0x0ACC46875, 0x6C6C7B40, 0x0CDCF5303, 0x2FD4002D, 0x0B478BD02, 0x14475875, 0x166DF876, 0x48C9079, 0x33E7CB62, 0x0A7394202, 0x163D9F23, 0x0A51A6120, 0x0B3F71B3A, 0x0C2B9C746, 0x59FAE16E, 0x4B81B6D7, 0x2225D215, 0x710855B9, 0x0C04D7C7, 0x0F6E5A403, 0x0AD865F7A, 0x7E6CCB30, 0x47E43576, 0x94E1F14A, 0x0DFF6BE44, 0x85215326, 0x0A5BE120A, 0x0BA54764B, 0x503B1443, 0x346CD643, 0x0CF183C42, 0x0FCFF7C38, 0x0A0D85104, 0x9CE88F45, 0x2BD47D65, 0x33B77714, 0x4A99DE4E, 0x7362F998, 0x183BB70, 0x0E416B41D, 0x0E97AB85E, 0x6F1A3F24, 0x8931153E, 0x9C72D418, 0x32D4066B, 0x0E22BF72C, 0x0C201331C, 0x8368442, 0x3391C115, 0x9E07167D, 0x0FE1B2946, 0x10D2F8DD, 0x19B12FD, 0x7D71AAF6, 0x579940E8, 0x0FB6AA072, 0x0CB21B262, 0x1AB82565, 0x0B5BF163E, 0x1B5DC625, 0x4E24FC28, 0x84D85200, 0x175D435E, 0x0EEFC4D2D, 0x21C1E245, 0x4231C143, 0x434E5D34, 0x0D1F0CA00, 0x84723720, 0x9D2BFD34, 0x0B5077F1E, 0x6DEDEF7E, 0x0C463C59, 0x3E39945C, 0x960C417, 0x3E1A4344, 0x20658B09, 0x0CB61F733, 0x4750C706, 0x53F64C1F, 0x69690D31, 0x456CF04C, 0x340E6E2F, 0x85DDEE5E, 0x8B6C4F09, 0x0A807810A, 0x81488F51, 0x568E016C, 0x0C2BFA66F, 0x3608A60F, 0x71EBC711, 0x10E4A218, 0x0BBE0F80F, 0x88480B70, 0x0FFE0F045, 0x0DCA1DB55, 0x0CB79CC33, 0x422F4E7A, 0x0AD92A656, 0x4FEC0354, 0x0DF5A4B2F, 0x639A2575, 0x0BCD9F352, 0x0ECA08708, 0x0A1D3B951, 0x0C539B86A, 0x2ABBCA4C, 0x0C238455B, 0x909BAF1E, 0x710B9253, 0x152F927A, 0x0F904BD4F, 0x0B7778220, 0x493D002A, 0x7EE2AB2E, 0x42E4D129, 0x0F2448134, 0x0FF2A3B00, 0x9972D315, 0x0B4042824, 0x3633E10F, 0x0A5E9B27, 0x0C5E8CA3C, 0x0F113DA1F, 0x93A6A617, 0x0C4C9BB02, 0x0CDB5B575, 0x5E20734B, 0x6F9097D, 0x7A485C4C, 0x0AD0C771F, 0x0E653552C, 0x0DDE28141, 0x69E66A72, 0x0D2F4DC34, 0x7FB63B13, 0x2E20235D, 0x0FCAFA701, 0x41EF806E, 0x0BEBBD27B, 0x6EBB3955, 0x561E1369, 0x0B7C08F4B, 0x2533BC75, 0x0A05B1313, 0x35A33B7A, 0x67178E1F, 0x92A09447, 0x35CE767A, 0x8A6135, 0x46A5BC6B, 0x6B01580A, 0x0BE8FC5C, 0x0B8E8728, 0x5C15322A, 0x9E8EA374, 0x0CF57432B, 0x29CBE71F, 0x0FCAE1640, 0x0D6504D28, 0x0A313446C, 0x0A9BB8D5F, 0x0BCA4A254, 0x81F6C52D, 0x12A2F851, 0x8E997F09, 0x0AD0141, 0x40C21B2F, 0x8A49270B, 0x419C822F, 0x0FE7DEE2A, 0x0F8046160, 0x97BA9518, 0x0B53E7E76, 0x1D381D56, 0x3716A92B, 0x0EAE1B970, 0x854FAB75, 0x0C9B63D73, 0x1FB0306B, 0x85D90C2B, 0x105CFA5E, 0x8AB18875, 0x90C10908, 0x1BEA8107, 0x0E6C6BA1F, 0x2E50AD7C, 0x0EB41C532, 0x0F92A23F, 0x2AFFC33C, 0x0C192125B, 0x0B3A5E62B, 0x0D3BA511C, 0x7D37B52F, 0x349CAC59, 0x0E55C4A6E, 0x0BD13439, 0x3449AE1A, 0x251F661D, 0x951A5C44, 0x75E5304A, 0x239D5448, 0x8E1FBD24, 0x0CA0C662, 0x0D8DBD23E, 0x0AB57DA7A, 0x44B66F0E, 0x0C3BD8C2F, 0x30A78570, 0x0D6DAD01, 0x0E26DBD1A, 0x0B680921B, 0x1DC9A760, 0x6D1F4610, 0x46429C23, 0x39B32968, 0x53E60030, 0x75924920, 0x24F5EE1A, 0x6378A36F, 0x9F910D5D, 0x0E5870176, 0x161E8A1B, 0x734C5F79, 0x62BFB625, 0x4ABA3675, 0x58A9A967, 0x6D90EB5E, 0x7E03E50F, 0x7EC80F05, 0x2AB4723, 0x0F3E8155A, 0x0A165644D, 0x90CA0448, 0x0FF88DC3C, 0x7A41370C, 0x3C22DF42, 0x433F4C4B, 0x3DFFC33B, 0x345AEA2F, 0x7A766A3C, 0x55CDBE6B, 0x4D13CFB5, 0x6E75A12D, 0x8C8CC766, 0x698C9372, 0x0A728CB15, 0x0E072C816, 0x0DE1EDD12, 0x0CB1DBA30, 0x43EB6B06, 0x7DB0EA6F, 0x0B0A5BB26, 0x5909F621, 0x0F0FC4969, 0x1265724C, 0x0A3C32C17, 0x49A6F350, 0x7FF55D2B, 0x21C71127, 0x0C76E0356, 0x82A0A54E, 0x14B02701, 0x68D46723, 0x126BAA16, 0x1339043E, 0x0E2159F2F, 0x668FA6FB, 0x2C5694B1, 0x2D596884, 0x717198FF, 0x0A8244A56, 0x3F82E441, 0x0DDA0E55B, 0x169AEB03, 0x0CB0EAC28, 0x462D794E, 0x0BEC2B619, 0x0AB81743F, 0x244C5661, 0x89E0704A, 0x0EE6CE045, 0x0A2FC4051, 0x4D0662F1, 0x1E06DA4B, 0x3D9D7964, 0x35F715A9, 0x0EA39037F, 0x0DB9F7E0B, 0x0CCE0FC68, 0x0B011526, 0x0A20E8261, 0x4E81A237, 0x1FB13C27, 0x0BE3E904, 0x60EC4C4E, 0x33EA4065, 0x0EDF88834, 0x0AF79D627, 0x8A62916E, 0x0D0EEC1F, 0x6AD0C434, 0x3287DB44, 0x4C90D061, 0x4771AA10, 0x4821C748, 0x179F7C0A, 0x8E9E235F, 0x6E47D62, 0x0C320F149, 0x0B2EA7940, 0x90C4EE2C, 0x0B18DD10F, 0x54E7BA11, 0x0CA4A1B1E, 0x6A0C23A0, 0x58241F43, 0x6C9B9FE1, 0x4A7E504A, 0x0C280C457, 0x0E216B744, 0x0EF3EC01C, 0x658F4639, 0x3098597C, 0x0EF0FC43, 0x7072303E, 0x9184A64A, 0x41DA3D29, 0x5D6BB972, 0x40FE7C72, 0x0CB3CCF17, 0x6A79A512, 0x0AACE4127, 0x0FDC3AA5C, 0x0B6097674, 0x58AAA16A, 0x5FA419DF, 0x62DD1531, 0x7EDD9EA4, 0x4CC9EF07, 0x91C9E348, 0x32C98957, 0x0DC8DDE34, 0x4257B558, 0x86B04469, 0x0A6D8F952, 0x3B5B5D50, 0x6D918A35, 0x0BD0EB42E, 0x1F990847, 0x30124F0D, 0x9F256B73, 0x0ED8C863, 0x95A19546, 0x0D0BDC46F, 0x1CC8C527, 0x514C604, 0x61426B3A, 0x5EA20351, 0x627F7F77, 0x0A140E82C, 0x29DFD268, 0x0CDF8240A, 0x4B0F2A54, 0x27A37D45, 0x83029B7E, 0x3C4F160C, 0x6D88EF6A, 0x51AB8D7D, 0x0BC2D2623, 0x0B951DF72, 0x0E2747146, 0x0EEF6AF7A, 0x96DFBD27, 0x25CC261F, 0x74A7F463, 0x3CB8B77A, 0x6027846F, 0x0E2387F19, 0x0F9C66B29, 0x7FC08C36, 0x124BCE26, 0x99ECD61C, 0x8D98551A, 0x0A7EC636D, 0x69AA9B0C, 0x0AA601B42, 0x0AC002A72, 0x0CAEC0647, 0x8031F13, 0x0E80A969, 0x6B2DEF73, 0x31E2F17B, 0x0DB78CE73, 0x0B63C1948, 0x58856F41, 0x5F7B6972, 0x0F28B2F54, 0x0C50D5F2C, 0x0B026F76F, 0x0AEB95577, 0x7F5F3E1F, 0x939B6836, 0x9CB00572, 0x153FFC46, 0x0B8678F55, 0x1158FA55, 0x51F7B341, 0x188F1345, 0x0F390796F, 0x4BBE1F6B, 0x984FA07B, 0x5DC4716, 0x0E4AAF607, 0x25E8F515, 0x0ACC8AB03, 0x4D559214, 0x0CF481158, 0x58C9D575, 0x1742995B, 0x0D74B306B, 0x66497F5F, 0x826F884F, 0x92E2267, 0x42C24D53, 0x38ACA117, 0x61B39128, 0x6D67365D, 0x49C6BBD7, 0x3C3AB4C, 0x1A77F083, 0x0D9F12663, 0x0A6202F74, 0x0E4FF166C, 0x75A22C55, 0x0BB5F2B3B, 0x9C67A641, 0x86FA262B, 0x0C57DF7C, 0x0B5F6B906, 0x798BA01A, 0x5715FF67, 0x4D465A02, 0x7E67E830, 0x3BC0F56F, 0x722E5018, 0x2A309434, 0x88158804, 0x42776170, 0x82F9692A, 0x9F572160, 0x19C3915B, 0x0E942E909, 0x21C7A92F, 0x22F1B342, 0x2B05375D, 0x59734B47, 0x84A4456B, 0x0CC42EE22, 0x84AB1C33, 0x0AB653640, 0x1DA79C58, 0x5D9D4316, 0x4C07480, 0x360A3D4D, 0x4211363F, 0x38DC5AFB, 0x9E0E5A06, 0x593A9716, 0x183D706C, 0x5305140D, 0x0D2C53731, 0x70526F54, 0x0A04B6E0F, 0x512D2062, 0x0AB126544, 0x137ABE27, 0x7B5DB416, 0x3428ED48, 0x55F11F18, 0x0FE561E41, 0x0D37F0E29, 0x6EB4B173, 0x0E799074B, 0x0F546B858, 0x91A56536, 0x129F3E28, 0x4EBA0320, 0x154AAB21, 0x0DEE12C4B, 0x0D2652053, 0x0C0AFE161, 0x0FB88C923, 0x2F036469, 0x11364716, 0x0FD2F7D68, 0x243D454, 0x1D1CD805, 0x9C3ED76E, 0x5B7D6B6B, 0x35594872, 0x0EF43EB7B, 0x2D43A31C, 0x0A5ABB746, 0x908F590B, 0x7E70C37E, 0x51BE1C0B, 0x5AA2767A, 0x2B4FAE3, 0x7F474047, 0x7E520363, 0x0F8249656, 0x5866187D, 0x66AFE93E, 0x0DFBE9D21, 0x4DADD055, 0x0F7544F75, 0x0F15DDC49, 0x9C67D475, 0x0C9FFA16, 0x0CF3F0915, 0x6ECDF448, 0x0CC4EDC78, 0x35548F9E, 0x1F620E29, 0x3F53C974, 0x791C3A28, 0x0A0132D07, 0x0FAA0FB14, 0x64372710, 0x0FB909872, 0x30FA4307, 0x537B120C, 0x28D43B0F, 0x0D5A5FB4D, 0x0E30A6C17, 0x0A744FF0D, 0x26641859, 0x8614844A, 0x6A6A19B8, 0x56AEB4B9, 0x56743C8F, 0x1BBAD20E, 0x4B13A2A, 0x0E5BEA554, 0x78F6AA1B, 0x515E0B00, 0x0DC13F549, 0x69548765, 0x0EDC5DF75, 0x0E9B2EF60, 0x3894907A, 0x5C93D43E, 0x0B501CC59, 0x25D6333, 0x0FA632D71, 0x9386EF68, 0x0CA55B354, 0x9A775A78, 0x8D27EB7D, 0x2E8DDA64, 0x9508F36A, 0x0BD212F05, 0x8208ED70, 0x0BDDC2E7A, 0x93C72A53, 0x65135908, 0x64212E08, 0x0B92B432C, 0x0EC27DD52, 0x534A52B, 0x65766559, 0x6A379968, 0x9E6BB225, 0x6927A003, 0x4FF63E3D, 0x16625D41, 0x0BA85AB03, 0x2C0A3407, 0x7FB6E426, 0x0A84B8B79, 0x15BD2368, 0x0B74A7521, 0x4DF5F38, 0x0CABEEF41, 0x0BAA7D854, 0x0FE428D29, 0x5D45DF2A, 0x84FD8B29, 0x98BAE721, 0x0EB6CCA28, 0x0B38A660E, 0x2DC3DA0C, 0x0A88EF92D, 0x3593537F, 0x0EA9F0907, 0x3B562401, 0x9AA6AC07, 0x4FC1370F, 0x0F581672D, 0x86CE895A, 0x54F5DC3A, 0x5AF8CC06, 0x0F1052343, 0x0F3608F60, 0x0C31F6D0A, 0x40FC6100, 0x9C3EC21, 0x7DA5180E, 0x6C069607, 0x8979D148, 0x25F1A307, 0x81C3B96F, 0x40C4466A, 0x29D00340, 0x4C82A931, 0x0FA6B1F3F, 0x27139169, 0x0A9C7885C, 0x7F69AB68, 0x0BFCD780B, 0x94345305, 0x32F41177, 0x0EC905318, 0x3DC34C33, 0x67876576, 0x0D7305D1F, 0x78197134, 0x12E127E, 0x26F2942E, 0x6D9BD861, 0x88FC9B58, 0x7AE77169, 0x0C793A568, 0x7902BF1B, 0x6D48014A, 0x8AB31273, 0x0B9FE201C, 0x770BEE6B, 0x49ECE0AC, 0x2165C0AB, 0x21692DF3, 0x7840F990, 0x0A7C87013, 0x4049061F, 0x571AD348, 0x0F34A1A45, 0x549D4C1D, 0x6AE05CA5, 0x29F0C7C1, 0x628EECC4, 0x3EFBDC3D, 0x3147F626, 0x0EC12E33D, 0x2A8C3056, 0x6E0A435A, 0x539A4834, 0x1BD8D75, 0x0E723B40E, 0x54C85A32, 0x27AF2224, 0x54BF8C70, 0x0DCC4F60A, 0x0A296940D, 0x1C533259, 0x55C7B526, 0x0FDF9557, 0x0A606454C, 0x0FC6D642, 0x86EA8343, 0x0AE5F704D, 0x35CB8D66, 0x866F4378, 0x0DCA93F56, 0x0DC93FE79, 0x0C7B84917, 0x33C4121F, 0x0D0DE183F, 0x26E6F75, 0x0B1F17651, 0x6DF1BB60, 0x0BC8C403C, 0x0EFEC530F, 0x9E38B207, 0x0A89F237A, 0x1A798465, 0x0D43F561, 0x7C347AD1, 0x0DB6D67E, 0x4771EA82, 0x0B782F18, 0x43E5347F, 0x48263661, 0x2CC7BD6B, 0x0E57BC90C, 0x6479683A, 0x818E7312, 0x0F45A5F64, 0x0B80AD06, 0x90544A55, 0x7B45E327, 0x0B9DF1D54, 0x0C51FD83B, 0x1B52620, 0x95895D2A, 0x0A2B3D635, 0x0C86D7037, 0x0C84D7049, 0x7292EF74, 0x0CADBDF2C, 0x7A3FE71A, 0x0DF83AB55, 0x86682069, 0x692C3B2A, 0x7DBC5D5D, 0x2E084463, 0x83A5BF0F, 0x8AFF523F, 0x2942B011, 0x9FDBD16A, 0x7E66FC2F, 0x79447772, 0x0E2C0066A, 0x3C87F474, 0x74C30225, 0x15FD0271, 0x123F7D7F, 0x269AA870, 0x0BB972F5B, 0x36864852, 0x0B7EEF245, 0x36DD1203, 0x0F0656626, 0x7C0ECB01, 0x38923923, 0x85EFC350, 0x1EC2A137, 0x0AA5A, 0x4E3D341A, 0x9054912C, 0x0CBDB8907, 0x0C87C1B35, 0x6FD83C02, 0x5144AA70, 0x31A9565F, 0x0ED949A5F, 0x804CEE53, 0x2F66190E, 0x6E42ADFC, 0x6143807A, 0x400891C4, 0x0F6FAE94E, 0x22D31558, 0x36EBEE43, 0x0BD871C60, 0x0C7DE4A36, 0x0FD27BF3A, 0x0E88DB72B, 0x0EE78F326, 0x0B8BFEE15, 0x1F14007E, 0x0A567E66C, 0x0EF9C0119, 0x0F7A6624, 0x2176B16E, 0x272F3B3C, 0x94692A75, 0x40385326, 0x272FE516, 0x0E2A65E0F, 0x0D08CE452, 0x0F20A6F1E, 0x0AA237A44, 0x40652155, 0x444F190F, 0x0DCCCD023, 0x2DFABB34, 0x0C49B0763, 0x911BE712, 0x0A48EA953, 0x6D2AA648, 0x0E545CF6C, 0x9A899322, 0x90FDBB20, 0x1B31BE30, 0x5711B002, 0x57DC0657, 0x18597D6B, 0x409F672E, 0x4555FA7D, 0x0D0186C01, 0x5FB3672C, 0x0EABCE06A, 0x0BFB56D1A, 0x6E2DCE50, 0x0C339259, 0x0E6E4A856, 0x297F845, 0x4C6BE57F, 0x0E148E6D, 0x0E53D5755, 0x1CF8C952, 0x1FFD0B, 0x8F61D119, 0x5C5DEB27, 0x446E161B, 0x6B2EA23D, 0x8957A75C, 0x80A1E7E, 0x0FC498950, 0x2EE65030, 0x7634C446, 0x0E18F583D, 0x0C86FE452, 0x6328067, 0x0FCC0166E, 0x20819455, 0x5D0E873E, 0x141A9459, 0x6020FC03, 0x0A363813C, 0x0E532005B, 0x0BFD36330, 0x8D206227, 0x0A4E86D75, 0x2D013201, 0x9953F400, 0x8BCD164C, 0x2F982A47, 0x0E5BED900, 0x99E1A439, 0x14D6811C, 0x2B7A353, 0x9900A245, 0x0A4375336, 0x5E148F7B, 0x0DE6EB860, 0x0F66F573, 0x0E86B3658, 0x0E678D65E, 0x0CB07E44, 0x16528708, 0x5CAD9A25, 0x0ED3FD701, 0x0DEC16B5B, 0x62DF1A0D, 0x0EA00EE6F, 0x0FE420031, 0x0C0EDA14B, 0x0FE1A8249, 0x5E63FC34, 0x63512308, 0x0E34D8224, 0x1D376065, 0x0F071852F, 0x8836F019, 0x4A389266, 0x8AC57930, 0x13040766, 0x7AD0BC2D, 0x6F845331, 0x0ACE5AB1F, 0x8EA63E4A, 0x713BF704, 0x45E64D65, 0x32DE9100, 0x0D04F8600, 0x23550646, 0x42448774, 0x0B8BBBC58, 0x0ACEDC24, 0x4EF40539, 0x0CE0D4461, 0x667B774A, 0x3B34DD3A, 0x4461B7FC, 0x33ECD6D8, 0x3262A55C, 0x0B0E1E4A, 0x89483423, 0x24504D74, 0x976AC22, 0x0EC99572B, 0x79ECF18, 0x27AD0C08, 0x0DC0BDD5A, 0x8FD4BF32, 0x71E59E6E, 0x66D1560B, 0x0A2D8C618, 0x0EBB55B1C, 0x0D655AA3C, 0x4EBE7238, 0x7A5C9A66, 0x4791A141, 0x94A4C01D, 0x0AC3A2C67, 0x17E12742, 0x0B7F9C663, 0x0EE7EB35B, 0x0CF9CE41A, 0x0C1C7A308, 0x3C73B914, 0x9DAA287C, 0x28431B53, 0x78A7964F, 0x4A7AD838, 0x2881F1EC, 0x19FB97A4, 0x5CBA44B3, 0x5BFF119C, 0x0C12CAF6E, 0x0FE023549, 0x66803979, 0x0C9CA7E07, 0x25B04151, 0x428C1654, 0x589F3E3A, 0x9795E03F, 0x0A95D6D5F, 0x0FB770553, 0x824B3C5C, 0x7FB3171C, 0x4936780B, 0x0FCA7D642, 0x0C644B95D, 0x0DDDA3829, 0x0A9E2022A, 0x0DE25E11F, 0x95D4FF0C, 0x9761B605, 0x0ADC2C53A, 0x569CA315, 0x0D4D46F1A, 0x4B6DEE36, 0x7EDFBE68, 0x4C7C066A, 0x95E7C66F, 0x6F7D6C13, 0x0E9586864, 0x8A744F16, 0x0E9634E61, 0x0AB851753, 0x8877845F, 0x4FE4875A, 0x7450965A, 0x0AE27C630, 0x92709E2E, 0x0CCEFD414, 0x45BDA670, 0x3BCE0B0E, 0x0C767DA67, 0x0C708E34C, 0x0BA81232A, 0x119E5273, 0x0C4B0B90F, 0x80C6DC07, 0x0EE788B1C, 0x6D93BC39, 0x5EECBD27, 0x834D8B29, 0x4F5723F, 0x0CAF8362, 0x0DAE92E3F, 0x0D8C9E259, 0x571C7219, 0x58C9ED27, 0x2446E943, 0x0EC033909, 0x0C8465A3B, 0x0E9F5128, 0x1BC4395A, 0x35D115B4, 0x3AEE6A18, 0x0A5881A8, 0x18F3077, 0x2D75FF55, 0x0AC17D32F, 0x93FFCE25, 0x0F964D46A, 0x0F1D47920, 0x0CECDDA33, 0x0C1CCAE52, 0x0B9DD5C6D, 0x884FFE5D, 0x0D26A0146, 0x7D8E167D, 0x816DB65, 0x0C0E38C62, 0x0EA21D336, 0x6702990D, 0x4431180C, 0x0EE164676, 0x73B11C70, 0x1E1B474B, 0x0C7E02850, 0x0CACD8E09, 0x76E43473, 0x0EB261214, 0x0B6D1C712, 0x3E2B8F2E, 0x0F9C5633C, 0x2C4A5032, 0x0F0D5374B, 0x0B2EACC37, 0x2A3A5D31, 0x0F1646842, 0x5F3C3742, 0x305EB03B, 0x6F051933, 0x4A83B8CF, 0x0C826AA01, 0x5232121C, 0x9A914F4B, 0x8104076F, 0x0DA81107A, 0x6CFC5011, 0x0FE921D6C, 0x0E297EB5F, 0x2CE0DD73, 0x0E8B4F022, 0x499A846D, 0x7011F67F, 0x0D7CB3619, 0x0BC4BA15D, 0x8E2C3D4B, 0x9EAC5F69, 0x86193067, 0x511723E, 0x89D3717D, 0x3CEBF779, 0x433C016D, 0x8399D539, 0x6835482C, 0x33123938, 0x3584A271, 0x936FA55D, 0x2477A17A, 0x15E46E7F, 0x6AC1D53E, 0x0A8DBD862, 0x0EEA80F78, 0x32E87F40, 0x0FA0DEB7E, 0x883A5F43, 0x0B4EC862F, 0x0D48FFB78, 0x0F436B054, 0x0B27FA41B, 0x0B727E758, 0x20178E48, 0x9B34953E, 0x0C26B46, 0x91288448, 0x7200CC57, 0x0BD0D0D24, 0x1F55C113, 0x10AD2B41, 0x43273D0B, 0x24663352, 0x99809D3E, 0x80123505, 0x68A2343F, 0x1C1A7378, 0x0E8477D31, 0x9BB46D77, 0x529E156A, 0x7BB7220F, 0x0C02B0F72, 0x67828469, 0x0E578F84D, 0x6807E854, 0x552B9461, 0x1861780E, 0x6315D353, 0x0DD65F324, 0x0CC4DFF3D, 0x37A5CE4C, 0x0D19CA379, 0x7ECDA359, 0x0EECCB525, 0x0F1B33142, 0x19023918, 0x0EF8E216C, 0x82DCB50A, 0x8B020570, 0x0AC9C2E10, 0x0A231771E, 0x9BAF3031, 0x0EFC36B1B, 0x0C697AA70, 0x3530CE6F, 0x6FD6A020, 0x2E3ADF2F, 0x514A4168, 0x581E1E52, 0x0CAEE4C27, 0x0A3E85652, 0x0D3D54061, 0x8A1A5C19, 0x0A6BDB3B, 0x0B94E392F, 0x0F221446E, 0x5F966F1D, 0x0D1AFB13D, 0x55371742, 0x3CFC6242, 0x9DFDB07B, 0x8DDCE50E, 0x0D99063C, 0x1BCB5455, 0x7BA99B34, 0x0FF4C387E, 0x35CD8D6D, 0x6A38BD20, 0x8129EE08, 0x0C0CF925D, 0x16D5EB30, 0x235B6527, 0x5C7FC30E, 0x699574C, 0x0EAF20F18, 0x91AF917E, 0x756FF86C, 0x182DEF47, 0x0E2F9D266, 0x0CD8D163F, 0x0E21B3C6F, 0x86E22939, 0x0A1635720, 0x6C369808, 0x6A23B22D, 0x78FF3024, 0x37A7237A, 0x44CE01B1, 0x2B62420D, 0x0B48FF338, 0x2CE0D754, 0x0C85FF308, 0x416CD947, 0x3A79DE10, 0x0E32A485E, 0x0BD15757C, 0x39C6160F, 0x18F8D54B, 0x274E321D, 0x0BAEF0418, 0x0D9C76829, 0x3E231E4E, 0x0DE4A6A3F, 0x35472C38, 0x44BC751A, 0x0C83D7A57, 0x0C6F6BD36, 0x0B92B6E07, 0x0E06A691F, 0x0A8F0901D, 0x87B98446, 0x0C386A50E, 0x2ED3BA56, 0x281DDC66, 0x2FBD3D17, 0x0BF20C04B, 0x82CF6C36, 0x8E151A0E, 0x0AF04355E, 0x0AD31AF43, 0x43A50D47, 0x0DBE40C33, 0x7591A24C, 0x8411E70E, 0x155EEB43, 0x58BCEA2A, 0x41275C0B, 0x4E240253, 0x71B4C076, 0x69758E28, 0x914076B, 0x4A7C2920, 0x0A798AC76, 0x0E75E712A, 0x7FC35558, 0x0EB542211, 0x0AF9CEB01, 0x45BA130F, 0x0A4809018, 0x8F075521, 0x0EDAAA42C, 0x2B3A155F, 0x528EFA2F, 0x1C7E5F03, 0x5357F145, 0x824B3847, 0x0DB9E1F4F, 0x0D5265E7C, 0x6D60D29F, 0x6F5891FE, 0x3900600, 0x1567C1CA, 0x65886160, 0x0F7E9AF0C, 0x0D817472B, 0x7BE64C24, 0x50A69A37, 0x193FA336, 0x0C90A4F77, 0x0C15A5B2E, 0x82B4315F, 0x0D21E5662, 0x0BD7844E, 0x294DDE55, 0x0B97DC70C, 0x8A9ADA26, 0x14A20067, 0x681AB30E, 0x0CF54EE35, 0x0B922917F, 0x0F8210830, 0x0BCFF9262, 0x6F8D9E3B, 0x7E9F3187, 0x25E4675C, 0x351F8D33, 0x0CCFB3A27, 0x0B31C1235, 0x0DDBF520, 0x0DD5C8D7C, 0x3DC06662, 0x90330361, 0x3063ED18, 0x0A348C842, 0x871DB36D, 0x87B3444, 0x1E2F1567, 0x0D7C34D25, 0x22BAD77A, 0x0E739645E, 0x981EA953, 0x0A46E095A, 0x0BA58BA40, 0x0A3F52D22, 0x0CEBBE72F, 0x73D6814D, 0x2D900849, 0x0E25DE816, 0x0DCF0345C, 0x0FCE4F67E, 0x9B807916, 0x0D4123D0C, 0x0B9E48961, 0x80DD1F75, 0x1EC33F6C, 0x91627C47, 0x0B891B719, 0x0EBBE7A13, 0x457F8E7C, 0x0C56CAD3A, 0x0C81B0810, 0x823FF55E, 0x4E5B4CC8, 0x124C4517, 0x2F338D38, 0x152D88DE, 0x1FA296D, 0x43B7D208, 0x0B481B12E, 0x23B40168, 0x2BF13667, 0x4DA05A02, 0x0C7220B42, 0x0E549F127, 0x0F0958824, 0x95DEF271, 0x58207375, 0x1E26916D, 0x783CDB08, 0x3411A851, 0x1A0B886C, 0x13BD541F, 0x824E55D, 0x0D3EF114E, 0x939A7414, 0x27E7244A, 0x65528E15, 0x4B2C2C2E, 0x12A69F5D, 0x0AAD11C12, 0x1199D968, 0x0DAC1A76D, 0x2C111271, 0x66398A04, 0x0D2409D16, 0x5299CF12, 0x43F7ED0D, 0x0D33AC703, 0x9550A21B, 0x0F8789F3C, 0x0F6EEC86B, 0x0C041D902, 0x4519FA3E, 0x0BE11D42D, 0x0A58BCA2A, 0x35AF8263, 0x53F0C61F, 0x0FEAB3D20, 0x53D51351, 0x0CB2CA228, 0x32BDE571, 0x6EE09B3D, 0x0DFE9F647, 0x3BE1CA4F, 0x41D0AD0B, 0x72846B5C, 0x62C8EF19, 0x0A6223C21, 0x0BEB0970A, 0x746E8F77, 0x50F45833, 0x0CF497173, 0x4E303765, 0x7D056B24, 0x3583FB77, 0x2071D47B, 0x0CF9E3A37, 0x797AE905, 0x0F4AB9B7F, 0x64EFDC52, 0x71F38842, 0x0EA9A646B, 0x2531B655, 0x0B60C8301, 0x0A8AC3819, 0x0CABC8000, 0x0EBBB0565, 0x0FC9CFF38, 0x0C868BE20, 0x3F911936, 0x0C7C9A161, 0x0FB25A412, 0x0AD71B573, 0x0A6B39829, 0x36076F62, 0x0EE41637F, 0x19380406, 0x98CF5E7C, 0x95649F20, 0x0D7E89B10, 0x0C3EEE73, 0x0E558F853, 0x0A6320D04, 0x5A6E2559, 0x625E6378, 0x0DBB5087C, 0x7ADFF954, 0x31FD9D2F, 0x5430F201, 0x6E8B9554, 0x96EC7A02, 0x0C5237B44, 0x5926FA3F, 0x0BB1D3158, 0x7B30FE45, 0x1D33259, 0x85DAB158, 0x67EC032B, 0x0FD6F3212, 0x4E437079, 0x0A67D1D61, 0x0C539D473, 0x4969140C, 0x53EFD254, 0x6BED6C1D, 0x7F70836E, 0x41313654, 0x84257123, 0x52DD97D0, 0x4014F6DB, 0x6C2326AF, 0x4DDD47A3, 0x0BCEECD48, 0x1411A38, 0x7DECF537, 0x1E4D3141, 0x0DDF62234, 0x0F7CBEF0C, 0x504ACF70, 0x31271536, 0x66578561, 0x0E6364A73, 0x0F74A907A, 0x0BF7D7F21, 0x47CE63F, 0x9676368, 0x6F1E4833, 0x7F5DF003, 0x0D967926B, 0x0BEC0E40C, 0x74729D1D, 0x7FE5AF4C, 0x83FAB800, 0x0BDDBB129, 0x0D2D48221, 0x0EEE7251E, 0x3C4C3518, 0x1406B975, 0x730D9741, 0x538C1703, 0x0EA9B8E6A, 0x0CE1BA475, 0x760AE861, 0x0A68A5C33, 0x0D05CBE2D, 0x0F3F6DD19, 0x0C5D78D74, 0x0AD53E161, 0x0EBC2CD26, 0x15225D65, 0x0DE7AF617, 0x511A5308, 0x0FB58A758, 0x0D5C58612, 0x1098D229, 0x9CAD2224, 0x48411553, 0x0D0E88424, 0x0C2DC4F48, 0x21A9A73E, 0x8EA96931, 0x374FED65, 0x0A18E570B, 0x11A42232, 0x0F42A9F0F, 0x7363DA2C, 0x8C4850, 0x3177D427, 0x87699322, 0x7399DF11, 0x8403EC2A, 0x7205220D, 0x4DDF4283, 0x52A2C7B6, 0x2BC34B4D, 0x72B8C500, 0x0EE04B226, 0x0DD670C35, 0x0BE652317, 0x0D9C77F4D, 0x0F289691A, 0x9DE0192F, 0x2AE2D255, 0x0EDE21073, 0x72A6A041, 0x3A7AA57F, 0x89903317, 0x0BAE7B514, 0x0B632A24, 0x4C6D835F, 0x0DC905D53, 0x990C9455, 0x83BC7045, 0x7D1FB55E, 0x0ABB0B607, 0x77E70F55, 0x0F0828F0B, 0x0AB3CFF57, 0x0A85EE47C, 0x78EC222E, 0x1ED6DE69, 0x2D62D027, 0x0EAF1443B, 0x5F8B6271, 0x2870A434, 0x282C37B, 0x719DA426, 0x1675565B, 0x0E0E9CF30, 0x2F03C83D, 0x0F03CD628, 0x0D273394B, 0x0CCE3E16C, 0x1A1FA97E, 0x0C0564A3E, 0x3F8A822E, 0x55994E7E, 0x49E77D55, 0x0F9713843, 0x60FC7822, 0x95540135, 0x0D5029616, 0x0F9080D78, 0x1811727A, 0x52224B75, 0x0A4B9C37F, 0x90F8814F, 0x43A5DA00, 0x4FF6C257, 0x3857664C, 0x0BB91FD2E, 0x6DCCA141, 0x31084709, 0x6F5244D6, 0x7FE57A0E, 0x66FDFD56, 0x4DBAF33F, 0x6E9F2DF9, 0x62423705, 0x190A1571, 0x6DF87017, 0x94DB072D, 0x5A630F62, 0x3ADC5204, 0x0AEFAB02B, 0x1ABA5920, 0x7966D532, 0x394FF29, 0x40260F59, 0x7D00DF34, 0x714FD4F0, 0x744368D3, 0x48DBA30C, 0x5D998544, 0x11074B25, 0x9AFDEE01, 0x1534944, 0x0A1FFCC74, 0x0DDA2C902, 0x51490C1C, 0x0DA563341, 0x9834C731, 0x0BE15AE5D, 0x3F106A35, 0x3DB8091C, 0x8B6DB210, 0x0CD39455E, 0x0E5BD0F02, 0x0C9625B6A, 0x71D87662, 0x6CADE518, 0x375BCC01, 0x5B47E0F, 0x0C610F57A, 0x71371F06, 0x0B3AE2F3B, 0x0E0CA4E1B, 0x0EA9DF438, 0x0B7422F65, 0x446C2611, 0x5C76022F, 0x1AD3A731, 0x3D62FF3B, 0x0A451A63B, 0x776C2D76, 0x4E694A61, 0x3F4F953D, 0x79BF763A, 0x0F0681756, 0x1CF25E40, 0x0CA088356, 0x0CABF4A17, 0x0B5262672, 0x881E3134, 0x9D0B44C, 0x0F2DE2F0E, 0x5CE8E64A, 0x75C6DA10, 0x53858358, 0x36F298DE, 0x47E2700D, 0x444A2529, 0x144A0B31, 0x4C96EF1C, 0x0A5B1A24, 0x85812A37, 0x451F58, 0x0EB25693F, 0x6F1F1F70, 0x0B7874E3D, 0x2F928F50, 0x0CC95211F, 0x0D15AF66E, 0x6CF48E0C, 0x70E7C75A, 0x49C72365, 0x0F409E49, 0x60C4561C, 0x501B573F, 0x15F46F93, 0x0CC28BC58, 0x8C8F1D76, 0x74863B5B, 0x814FE24A, 0x14AE4E2A, 0x7E56F027, 0x732E1259, 0x283A326F, 0x5460EA52, 0x4BCB5169, 0x629711E, 0x9C425B60, 0x8F157712, 0x1A737C4F, 0x0E8D84A7D, 0x99709136, 0x0A0F4A606, 0x0E81D6A55, 0x8496FA75, 0x0F14C676, 0x9FA5B812, 0x0B3288A46, 0x0DBA9E715, 0x7100AF01, 0x4E5852DA, 0x24D4B216, 0x37D84D1, 0x1E50B1EE, 0x0FBC70C09, 0x7C4E6D06, 0x8441E304, 0x0C7F0C861, 0x8DE8A7C, 0x0F9C71E60, 0x4840AB2C, 0x1C8CD926, 0x771E0F08, 0x0BC6EBD05, 0x45C60B16, 0x0CB7EF95A, 0x73A0F6F, 0x4BEF7C34, 0x67C1543B, 0x964F8601, 0x6562F903, 0x509A9F38, 0x2FC01738, 0x557A00A, 0x38B8090E, 0x0B456122E, 0x156B6601, 0x0D85DC220, 0x677F9C74, 0x0F0144E17, 0x495E7122, 0x879CB547, 0x1A2637EA, 0x1709E823, 0x77A791D1, 0x2913569, 0x46EF551, 0x324953A5, 0x5998AA27, 0x735463D7, 0x0DE20AA6D, 0x489F7E1F, 0x0A3DE1533, 0x553FB975, 0x40E3C25, 0x0E8A42149, 0x21BEB250, 0x0B484B14, 0x48EDF0B7, 0x6E6AC7AE, 0x3929693F, 0x4FEECCA2, 0x0D819A744, 0x0D057E94D, 0x9E4D380C, 0x11D2B052, 0x84AEFB7B, 0x0B3B89E0D, 0x0E92F7373, 0x0EC2D9870, 0x0A4CDEC24, 0x328EE415, 0x73CA4D38, 0x0E073EA2C, 0x35B4281F, 0x0D4E1F540, 0x18E2F43D, 0x0B428DA2E, 0x0B93A814E, 0x1841C830, 0x3B7B163B, 0x985B2B3C, 0x2CEC6283, 0x5B069FED, 0x51F59901, 0x13BC9618, 0x0C7FE4D37, 0x0E599702, 0x6F36CE09, 0x0FA92EC34, 0x0E06A185, 0x790915C7, 0x55C3319F, 0x3FDB85A6, 0x0E025896D, 0x32D7BC42, 0x80C4F625, 0x65D48469, 0x0E58F5B50, 0x69F46919, 0x51021D5A, 0x895D4875, 0x9B824E2F, 0x0C4CC6A12, 0x6AD13222, 0x0D036774E, 0x98AE6053, 0x82B32760, 0x845F517D, 0x51E9E121, 0x9AF4EF10, 0x0BFDA6738, 0x0E9440D5E, 0x0FAD43661, 0x9E349426, 0x0D7DFF10F, 0x5EC3B956, 0x6533E25D, 0x0E5388912, 0x0CDF98760, 0x5FC6CE12, 0x7C112821, 0x369A6C02, 0x73D70821, 0x5EC02CD0, 0x5203378E, 0x2527100C, 0x6CC8641A, 0x23C23557, 0x0AB76B5C, 0x0D6BCCE33, 0x74C45231, 0x9414B451, 0x713F1D63, 0x3891BD43, 0x0FEE5E673, 0x42769431, 0x0D03F1E17, 0x80990E54, 0x0C6D5E52E, 0x21290039, 0x1B8EFE64, 0x86B04D67, 0x0B6E0D17, 0x15633546, 0x24E5E10D, 0x0E24DFF26, 0x7426EF1C, 0x8918C46B, 0x0C7868839, 0x4120777D, 0x0E8DE927E, 0x4498B05A, 0x1FE89E7D, 0x0DB2EE647, 0x309C1E4F, 0x0DDD54F6B, 0x56F653, 0x9C648369, 0x988542, 0x0B0D6230, 0x7221521D, 0x745CD873, 0x9F211602, 0x0E4606F00, 0x0ACED9537, 0x9D07FD75, 0x26D70332, 0x7C2DB44E, 0x1DA10B4A, 0x0ECACE960, 0x9D56B407, 0x382F0A2F, 0x725D3748, 0x0A8C4C11E, 0x4E923F75, 0x96421956, 0x8A12C145, 0x0C2B82E12, 0x1F5BDD41, 0x5299497F, 0x3D9A50F, 0x83A7040, 0x9631FA59, 0x22C1440D, 0x0E3685608, 0x0C6CD1829, 0x0FF969478, 0x0E4BE4C5C, 0x62329C12, 0x0FF2E1A3B, 0x0EFCBAE0C, 0x0D553EE2F, 0x738BF22E, 0x8EEDC40E, 0x0B9B45D30, 0x1F798866, 0x2BF5C104, 0x0DF8B6162, 0x9BA63C35, 0x4896CD4E, 0x0CB384B43, 0x4E037000, 0x166B8E14, 0x4E580FF3, 0x6F8B1DBE, 0x0CF571773, 0x0D4D89B61, 0x6CD47321, 0x91104605, 0x0F4337923, 0x0BE6DBD20, 0x94E9EB14, 0x0FC6DE963, 0x549FB77A, 0x0B7AA3022, 0x0DFD63F6C, 0x1A6DD023, 0x0B641C51A, 0x0C3958C48, 0x7C9F6C36, 0x0B670DF55, 0x0B2613B55, 0x51F35A66, 0x29FCD104, 0x404F0064, 0x0AA8B816, 0x49755A6B, 0x6B44C268, 0x0E9331A79, 0x0E41B9720, 0x0B4DA8F37, 0x0B56C653C, 0x1D19885D, 0x35A06735, 0x0F302E847, 0x0FFDA3A39, 0x4F87E28, 0x0C7DB8329, 0x6BAFAE5A, 0x9508C52D, 0x0BB0FFD4C, 0x291D6C7B, 0x29F2B042, 0x0B77DE630, 0x7DBC2376, 0x0E09CE164, 0x9754261D, 0x9729F419, 0x97DEA67F, 0x5AEAB265, 0x13C96050, 0x4D4F8655, 0x0D4CEE3A, 0x65BCBB36, 0x764B585A, 0x4D9BEE1E, 0x6F64744D, 0x0BFC0B245, 0x0B9DFB007, 0x59988E46, 0x0A4DC4966, 0x6DBA403F, 0x0E05F402, 0x0C1F5D143, 0x0A25AA874, 0x108DC4A, 0x0C0D00C7D, 0x0A652271D, 0x0C8E35F74, 0x2B80BB57, 0x3B5BEC4A, 0x84F35C41, 0x549D2753, 0x644D9D0D, 0x3B714372, 0x0D1594B49, 0x45EA7E72, 0x0D2C5690F, 0x68833F63, 0x0DCC82572, 0x2DB01C75, 0x7C4CA033, 0x2918AC47, 0x3AFC0A30, 0x0E1085C6A, 0x9F630422, 0x8797F94E, 0x506DD037, 0x5F24B767, 0x4077AA56, 0x0A9055F7E, 0x301014E, 0x0AD31EB15, 0x0B70A5301, 0x0C4F6D211, 0x4F8C930A, 0x0B8122F4C, 0x85C7DF0E, 0x0F5DEBA27, 0x81F68E40, 0x0B0479B66, 0x303AA772, 0x5EAEB01, 0x5E5C239, 0x95874400, 0x405B2F74, 0x0D63E0E03, 0x0DA71C372, 0x13219903, 0x3FC24D66, 0x0B63AE964, 0x40D1B578, 0x0BB0EEE19, 0x0DF52952C, 0x7ACDC028, 0x9C174A04, 0x7EB6994E, 0x165BA77, 0x0EC841A3C, 0x0DDDA5036, 0x42DC644E, 0x968A793A, 0x0E0DB5104, 0x0EF0D5064, 0x4D95CC3B, 0x0A5D22416, 0x3F9AE36E, 0x6A8FB07, 0x2A9A0425, 0x34799E16, 0x879E8A48, 0x0DAE19F0B, 0x65B34509, 0x8C88764A, 0x0DFC66245, 0x0FA3A8A09, 0x0CCE3A53E, 0x0B6057148, 0x0D4AC4D7C, 0x0DF043F42, 0x0F5C7BE2E, 0x8AE73661, 0x1FD6F43A, 0x0B0D6AC48, 0x693ACC0D, 0x99A3B563, 0x4CEEF64C, 0x0E7F0655C, 0x9B08705B, 0x38731109, 0x0C5CBB612, 0x0DDE4D429, 0x0CEFD8A43, 0x0A5A70817, 0x0CCF2240E, 0x1C93577F, 0x4A7A2D2D, 0x21DC3AB0, 0x73B5D4CE, 0x16360A86, 0x210D61B0, 0x0A9D9DD4F, 0x4FF6D15D, 0x0A5B9EC1C, 0x3562541A, 0x2EBD3423, 0x9FF47626, 0x146FA58, 0x0E4C2A56B, 0x73A1C422, 0x0E14A391B, 0x0D98A641A, 0x0FD88FB03, 0x212E56, 0x89611163, 0x66C3C711, 0x9AC4E339, 0x0B47061F, 0x72F5B3B6, 0x36C01945, 0x5C988DAE, 0x1280E400, 0x12B2283F, 0x0DCC0A47C, 0x0B827ED17, 0x0DEA44D4D, 0x0F853FC7B, 0x2A21A45, 0x0EA31564A, 0x1A8F4F03, 0x77B64C17, 0x2A38FD5D, 0x0C3682D53, 0x0C6AC1E75, 0x0CFF1E97A, 0x0F8CA816D, 0x0F4695318, 0x6EE66021, 0x0FA107C46, 0x0D92CF903, 0x0E1872544, 0x0DB5BB561, 0x0B2B75D1E, 0x0DE102148, 0x0DB7CE337, 0x3C196F01, 0x44D4E859, 0x7541C771, 0x11697731, 0x91881648, 0x0AA0E1B07, 0x1F2C916A, 0x0A408FB48, 0x0BCC04346, 0x0FCEC3567, 0x5C30E860, 0x9B659113, 0x0F4403263, 0x5ED20226, 0x8597E75D, 0x0FD08166, 0x0D5884F3D, 0x0AFCFE43B, 0x0D238AF39, 0x9B356E32, 0x7EC1CE36, 0x0CB033127, 0x909FC14A, 0x0ECA72F58, 0x0C514AD6D, 0x69CCBA4E, 0x0CD2F551C, 0x0A070624F, 0x1B84186D, 0x0AB407664, 0x7BED4507, 0x579D876E, 0x0EF145F3E, 0x0F12E0D79, 0x6906FF1F, 0x809D7506, 0x9B3D2800, 0x8832900A, 0x24A6704F, 0x58FE6B46, 0x841FC671, 0x80D65830, 0x0F363FD59, 0x7960F854, 0x0DFA85B56, 0x78FBE437, 0x88307A3B, 0x0B431AB13, 0x27CBC973, 0x5A692975, 0x50671946, 0x0A58C982A, 0x256D5A1C, 0x0E006DB10, 0x9134C802, 0x0EA81070A, 0x2E6AFF49, 0x4045FF1C, 0x6A54F329, 0x0D8B3D1D, 0x9A59303, 0x6E0AF60, 0x0BCF4353B, 0x0F8B9F241, 0x0F70EBD59, 0x25FB345B, 0x78576848, 0x924CE559, 0x7462D0E4, 0x21EDF5EF, 0x522D87FD, 0x2484D56A, 0x1DD43148, 0x0DDAE4E7A, 0x0ABAD832C, 0x0FC7C8D1E, 0x55AA3332, 0x33DEFD67, 0x0B1AE3832, 0x7C75FD25, 0x8D47275D, 0x1165278, 0x21029650, 0x0B3B48179, 0x0E11C2D09, 0x0B2365E53, 0x9D368903, 0x2AF0C268, 0x109B7B72, 0x2829F35C, 0x8E477135, 0x19400F76, 0x2E09A33D, 0x4A3CA770, 0x11FA0138, 0x25186017, 0x6F37DC4B, 0x8A516A00, 0x0B7644571, 0x1D65A131, 0x274F4318, 0x0A2AF9611, 0x4FB22C09, 0x44237560, 0x7F5EE50B, 0x0FA5FB035, 0x41A0027F, 0x0D508193E, 0x1508B9FD, 0x26F43182, 0x752E5700, 0x1E33D9D3, 0x0F3648D29, 0x7380AC34, 0x6D3A5774, 0x0D481BA32, 0x25B70A08, 0x0B71E077, 0x0FE717D1B, 0x3652867A, 0x339AD354, 0x8CB9EE50, 0x4F929570, 0x61A37612, 0x0D7F59541, 0x618C9728, 0x86BBD629, 0x462D720D, 0x0EBDD0129, 0x3D201C1B, 0x6392133F, 0x122D4541, 0x4761C14C, 0x6409BCFF, 0x6DD3D930, 0x11DE11A4, 0x0ACA4F07D, 0x97F0BC20, 0x3437B176, 0x0D9E29E1B, 0x893FF851, 0x85B5C75A, 0x94687416, 0x7CA4857B, 0x0F835740F, 0x1A3CB0A, 0x5026402E, 0x1EED7E17, 0x0C14AC02, 0x4E98BD49, 0x543F0512, 0x3FAE7F57, 0x1CBAEE15, 0x51F335D4, 0x57E8755E, 0x40AF0085, 0x45E322B, 0x260DCD13, 0x0F874B469, 0x0EF3B3454, 0x642DE92E, 0x5C07C828, 0x1697915, 0x43FD9B5B, 0x0E4C0871, 0x58B93337, 0x0A22B3414, 0x0BBF0F86E, 0x0EFA9F057, 0x0D662E50A, 0x94D3970A, 0x79E9E829, 0x5C18AD65, 0x283C0C21, 0x0F58D6E25, 0x544E2175, 0x2ADFD72B, 0x46B4AE53, 0x723BA00C, 0x36F3832E, 0x944C6C1D, 0x0C67AA51E, 0x76A10306, 0x6F9E1838, 0x6A4C4021, 0x16F3F96F, 0x21E65A14, 0x6EAA724C, 0x3D00C703, 0x1A5B0F7E, 0x5EE6A620, 0x0A12DB032, 0x7662D726, 0x5F4F2036, 0x0E42A4C0E, 0x84AEDF17, 0x0B708546D, 0x87568022, 0x3F9FD806, 0x0A7B24445, 0x5DB9652D, 0x0D4727011, 0x209C2D6F, 0x0B9D11213, 0x0FCAE7C32, 0x152A9C14, 0x0E203408, 0x268E545E, 0x5BDE4A68, 0x805BD414, 0x5D81D80C, 0x0F02AB705, 0x47D67933, 0x0D322DC12, 0x5FC9CF3D, 0x0B122BA54, 0x0E915D602, 0x81AF2A52, 0x1FCD2C21, 0x26169D06, 0x9B0A3A50, 0x7DB3D341, 0x0C7434D39, 0x116D1177, 0x0DD02F477, 0x0AC6E9947, 0x951BF10E, 0x940B4865, 0x33C5196A, 0x0D5BAC915, 0x3BBE8C2A, 0x907E7F17, 0x0A92D3A27, 0x5B5ABA19, 0x4A50922A, 0x0A5DCB659, 0x7184562E, 0x5870C632, 0x0CC6A0B38, 0x0CC62A116, 0x0D8CB9A47, 0x29ECE344, 0x0BC8D581C, 0x1FA2147B, 0x3D79F15F, 0x30E45B8A, 0x5058B41F, 0x6C821EE1, 0x16DE34B5, 0x7897DC6, 0x3CF9DEEE, 0x2CFB00A7, 0x6D45CF32, 0x0D37E801A, 0x497E9E73, 0x4A48C32A, 0x7FED1962, 0x0DE998F02, 0x0DF530B10, 0x0B2B2334C, 0x0B3545918, 0x1A12983A, 0x4331B363, 0x5C82933F, 0x766C5254, 0x8D81450E, 0x25F4A19, 0x0E7F0A802, 0x0E5F10B41, 0x0CEC95551, 0x0B3534A19, 0x0BDBDA608, 0x0F7B53916, 0x70E1A235, 0x0DD5FBB03, 0x0F3C4F96D, 0x8C38CB0F, 0x0AD248A53, 0x0D8E98F48, 0x293F1E3C, 0x9DB68544, 0x0E424C329, 0x6150AB38, 0x0BFC5477, 0x0B8A34344, 0x0AACE492C, 0x55441822, 0x37915D26, 0x8868D92E, 0x34982332, 0x0EA439172, 0x3CBD3247, 0x4FAABB6C, 0x2D754456, 0x983FC606, 0x0C5160E41, 0x0BAF68964, 0x9A9E1020, 0x0AC07B743, 0x9FE89525, 0x68686671, 0x5F5B015D, 0x5CA63C2E, 0x5F1EA007, 0x2B7A2127, 0x6DA60039, 0x337B43C0, 0x642E9FDE, 0x0E72A8205, 0x2BCD293E, 0x84B48D5E, 0x84E1074A, 0x0FF2EC67, 0x0E5043917, 0x8FDD5C41, 0x0C795302C, 0x8FD38243, 0x0E5217563, 0x0FF268E52, 0x183C5C72, 0x19BA9815, 0x0E96A1F45, 0x54F98E39, 0x68645402, 0x16E0631B, 0x0EC385540, 0x2D7B6243, 0x0D0D6ED7F, 0x2ACC778, 0x4E9394E6, 0x2F042BB4, 0x208CF258, 0x39DE1A64, 0x0CB65C053, 0x4F5E6C59, 0x81BBF76, 0x56CB805, 0x0A141064F, 0x64902E19, 0x0EC963A0B, 0x0C969766, 0x480F2FD3, 0x5F3BE605, 0x3657B648, 0x0CE49F50E, 0x569F16, 0x0A3964D21, 0x5D1D7852, 0x0E577147A, 0x0A2BDDB73, 0x7559D444, 0x0FE31AD0F, 0x5CBC2DCE, 0x48A6AF5F, 0x321C6C2B, 0x0AA62556, 0x0B68BB83E, 0x94116455, 0x71DF4C54, 0x3D631E1F, 0x6E947D5C, 0x0E09ED079, 0x2CA3EA70, 0x0A7729840, 0x0AC04914D, 0x7B01574A, 0x0AF8D5737, 0x0B1704953, 0x1D435D19, 0x131E8650, 0x9D07845E, 0x0E9518D26, 0x0FC624248, 0x0D80C633, 0x0C552AA1B, 0x0CAAC3757, 0x0DD6654A, 0x69E9F73C, 0x27CAAF29, 0x0F24D7A44, 0x0BA7D330, 0x9D23846E, 0x0F17F2754, 0x97CFCE69, 0x6676E76C, 0x58162966, 0x38D82D3E, 0x1C02A02B, 0x0EC278D3B, 0x0AAB77A12, 0x5965BE4A, 0x5ABC0A18, 0x8A564B0C, 0x8608A93B, 0x12FA358, 0x365BDC59, 0x51D20D6C, 0x2DF696FC, 0x5B2F3C49, 0x73CAB4FC, 0x0C4DA8060, 0x84D3A90B, 0x89FEA45, 0x0C03DC328, 0x9253703F, 0x0CDF19461, 0x8AEAFA7F, 0x9F29D609, 0x36DB8C1E, 0x0B2B4AA29, 0x9277504E, 0x4282604F, 0x4FD82E18, 0x83F77722, 0x0D9512F39, 0x0B54E1605, 0x0DB0DA108, 0x112A5D77, 0x0D250B630, 0x0C7352E44, 0x0BBE1D709, 0x2BB6747B, 0x22F2385C, 0x46382316, 0x0B1BE1D37, 0x2321DC34, 0x7C93FF6F, 0x0B3C81D3D, 0x0D4DDD644, 0x645F251D, 0x0D1157B5C, 0x99B85725, 0x0E832CF28, 0x0D9B46522, 0x59F61A4E, 0x7A863F68, 0x0A7A6FA03, 0x0E4E0154E, 0x1AB01572, 0x0DD818722, 0x9695C077, 0x0AC276640, 0x1F04E871, 0x0E56DEF0F, 0x2F1FDE62, 0x0F855172B, 0x9ABC0515, 0x0A2D7F6B, 0x0A807422, 0x6C0DBC45, 0x0D162AD2F, 0x0C5614C2C, 0x98C33041, 0x0F354E60B, 0x0B9A6F42, 0x49824E78, 0x1776C240, 0x882D6F32, 0x0FC4A6C35, 0x0EB539905, 0x0EC8C944F, 0x0CE60E711, 0x840CF12A, 0x0D4BF6378, 0x0A7154D34, 0x0DE020C79, 0x4F46A360, 0x4EBC4738, 0x5D9A87D9, 0x25D0B3F, 0x5A744C74, 0x5BE5A855, 0x151E1F13, 0x4B42B74C, 0x3DE7D14E, 0x443DFD75, 0x4498CE77, 0x0D7A3D763, 0x4E6A7C61, 0x4E18431A, 0x44B19329, 0x1FCD2911, 0x137A8F46, 0x0DC74C46A, 0x1322101D, 0x1F14FF08, 0x25F71263, 0x2A98D25D, 0x0A7416E3B, 0x22427F18, 0x15EC6B63, 0x93CE020B, 0x51C5C3AB, 0x3836A421, 0x627C0AF6, 0x15A906EB, 0x78FB6807, 0x0B6D40964, 0x0E674FB16, 0x3ADF8A4E, 0x507B6A26, 0x4DFACA91, 0x30941D2, 0x5CB36513, 0x5DF5813E, 0x0CF3F3F5C, 0x7826DF3F, 0x0A18D5036, 0x0A6E31640, 0x0C6905B21, 0x0EFA59350, 0x0EA94AA69, 0x0E65D8532, 0x3202317, 0x0C6096F54, 0x0F97F954F, 0x22342220, 0x0EC008237, 0x2318682D, 0x0C975905B, 0x0E430150, 0x3804D410, 0x5C449366, 0x0FEE5677A, 0x0D2FC301F, 0x0C3D2F969, 0x959E1B59, 0x4AF89926, 0x7AA7034E, 0x7B131770, 0x84D72475, 0x9972C604, 0x8DC6E161, 0x16309202, 0x0CE5BA84E, 0x0EBBB6320, 0x0E56FD15E, 0x4682870E, 0x8C49B456, 0x8C53E81E, 0x0D13E32F, 0x7CEF4727, 0x76E89208, 0x0F3706862, 0x7F0F6B3E, 0x3DF2015D, 0x0ECF0FD31, 0x0A1438D5E, 0x29F38314, 0x0F09665F, 0x6AB91D3A, 0x37368564, 0x470D3A70, 0x0C6FDB020, 0x351CED5E, 0x1A0A6B0F, 0x89D0AA0A, 0x0CABA0838, 0x64020536, 0x378AE58, 0x46CE1F28, 0x0E9D9292B, 0x9DEA745D, 0x0D394010A, 0x0FF09BC2D, 0x6B461D2C, 0x0BE50652A, 0x0E5798D0C, 0x0B1C8A43A, 0x4B9A1901, 0x71CD752B, 0x0BEDB876A, 0x0C7896128, 0x0E7B50834, 0x0B14CF04C, 0x4699CC66, 0x24A80A11, 0x9D3DEE7E, 0x0E7DC5945, 0x4D9B8E25, 0x0AC46545E, 0x5196777F, 0x84D1130A, 0x0F4538E4E, 0x17942820, 0x0B9ED0069, 0x0E5EF95D, 0x0A064D32A, 0x84A80921, 0x7260FE13, 0x0A4DC8103, 0x0CA762949, 0x5B3A283F, 0x41C7F660, 0x9D0B2B53, 0x5B44E46C, 0x0AC0D140D, 0x5C5C907D, 0x40BE7179, 0x5DD6B847, 0x0A7F6A97E, 0x0B18BE724, 0x1CB24032, 0x6E800B27, 0x9841F058, 0x0CDFE307F, 0x0B419D80D, 0x0BDE9FA69, 0x6B3C1F7E, 0x9BF63153, 0x0A85890F, 0x1783735C, 0x0EC8CA952, 0x8F569D19, 0x0BD7012B, 0x321D272, 0x48449E02, 0x1935FB08, 0x0A385A51D, 0x0CCECA723, 0x8C95F91C, 0x47622721, 0x9663D16C, 0x0E7CF215C, 0x88291E02, 0x346FFC3F, 0x42140649, 0x3437320F, 0x90CB8C3D, 0x82D27742, 0x920DEB56, 0x37C2363C, 0x335E5F67, 0x0AEBF2B09, 0x0A5424263, 0x0CC9F4F40, 0x7BBE5C08, 0x595C1A71, 0x89894A2A, 0x0E6FA7B06, 0x0F4524C44, 0x930ED439, 0x0FE7DEF62, 0x0E0DFF516, 0x22657153, 0x955F10D, 0x0E300C809, 0x6BA90F56, 0x33492E48, 0x38EDC807, 0x1AF75F76, 0x16A603F9, 0x0CEE89448, 0x0CEF98866, 0x96EF0710, 0x5612B34A, 0x2698526, 0x0D9030E59, 0x8B49E559, 0x92341264, 0x5BD6851B, 0x1D57D030, 0x0C9F64820, 0x8F34E502, 0x0CB16FC39, 0x6E398B03, 0x5BD43443, 0x46D55842, 0x0C795A574, 0x0E45D7F6D, 0x2DD0D448, 0x0BBE8F138, 0x776C5327, 0x2B4EC42B, 0x9BC8E74F, 0x9AD1C47A, 0x9C2DED7, 0x47EBC365, 0x186BC083, 0x2CD44485, 0x4501D01, 0x3C118C4A, 0x64D8804, 0x0D238B249, 0x1403F224, 0x7AB1BFA2, 0x79B5A21A, 0x294DC7C1, 0x76409E6D, 0x0B4944A6E, 0x9EA8AC3B, 0x0D1162409, 0x0D1EB1A1F, 0x679FF55B, 0x604B090C, 0x9C021759, 0x0D5D8805F, 0x0BB1F3E4F, 0x0E2D76F1B, 0x9C6E2654, 0x6F1653D3, 0x58E808E, 0x72C54CA4, 0x421E6816, 0x3AF60810, 0x0F21F005D, 0x0B1BBD55E, 0x6F99BE49, 0x70E9AF36, 0x0B636AA2F, 0x0C6C6601A, 0x7539CD37, 0x0F247367A, 0x0CD13E91E, 0x47727F01, 0x0FD524B2B, 0x6A507933, 0x70BDE415, 0x9C7E502, 0x0E0901721, 0x24522F04, 0x0A86F923E, 0x0B1A73B2A, 0x0F53D4A23, 0x0F0F881A, 0x12F34436, 0x9140617C, 0x0E5E7087A, 0x0CD128305, 0x7418D117, 0x81562F4E, 0x6D904042, 0x83C0157C, 0x0D9AD475B, 0x847A5126, 0x0BEB61E0C, 0x0CBCD4738, 0x35362705, 0x2D50DD55, 0x3CB7F76E, 0x0EB6CD134, 0x0F3163E70, 0x0B1F0C426, 0x0DDB4072F, 0x0C02A270F, 0x0F8624428, 0x0DA07535A, 0x2A7BA042, 0x6920293E, 0x0E4CE385D, 0x0A0CB863, 0x8D725842, 0x8C3ECB1B, 0x0BCB3F30D, 0x83B0A265, 0x9B4D5336, 0x0CEA63844, 0x14F10362, 0x80355C30, 0x9BB9BB49, 0x8809D579, 0x28C8B7E, 0x84AFC0B, 0x0CCAEA75, 0x0DB39D359, 0x8CC44D32, 0x0CA800902, 0x0A6071B12, 0x0C1FA7437, 0x0F7D0E657, 0x0E2BE1201, 0x0AC67466C, 0x0EAE72448, 0x93AFD727, 0x8A1C4E1B, 0x0AB124C57, 0x8C121C50, 0x6424A175, 0x0D58DEC19, 0x0F532450E, 0x48F3D952, 0x0E099A47D, 0x82A59D50, 0x0D431A56E, 0x9C4D980B, 0x5564036, 0x707FF824, 0x6AF4D04F, 0x1A474418, 0x0F0B45455, 0x5AE8C19, 0x0A2501912, 0x0F240E053, 0x0EF88825, 0x0AE1A0408, 0x0CD7AB32D, 0x9ABCD657, 0x789B0D0A, 0x7482CE3F, 0x5CB74B0F, 0x6F6CF461, 0x5641E140, 0x81F927B, 0x5A54192A, 0x0EAF0B868, 0x923BE016, 0x5676501, 0x7603D538, 0x0F75F810C, 0x0DAF4511B, 0x6B361A47, 0x3F535B5F, 0x0BA8EF618, 0x0EDDBB717, 0x1485004E, 0x56DC8E24, 0x0F331F84D, 0x8404F972, 0x0C0D05F74, 0x0D793C66, 0x74B94D48, 0x0C67EEC0D, 0x0AFC95578, 0x67FA2D1C, 0x0D4767533, 0x5EE45900, 0x3475E149, 0x6E334C0B, 0x0D67F670A, 0x0A8F7AF09, 0x0CAEA971A, 0x46EC5B6C, 0x0FF38914A, 0x0D3092A16, 0x0A0407516, 0x0E9294A33, 0x65450A2D, 0x0A5A7DA17, 0x5F2D1F6C, 0x5CA58B39, 0x7F9C2C33, 0x0CA633933, 0x9CF8E618, 0x3A2B234C, 0x0B73FF14A, 0x0B07DE766, 0x9007B270, 0x0AA71E918, 0x651F1C1E, 0x26BAD541, 0x3BB54E34, 0x1808FEB5, 0x1757FE72, 0x67B47B77, 0x0F365C3E, 0x0EBCD7326, 0x0C598D577, 0x44AB3D08, 0x5901C031, 0x9B183D02, 0x0ECA2ED11, 0x24EC574C, 0x0E104996E, 0x0EBDB7E5C, 0x0F7F58162, 0x81450E05, 0x0D405C90F, 0x5C3B8C0F, 0x26EDE81C, 0x3333E87B, 0x0B9E01749, 0x0A6891550, 0x379DF767, 0x25F74426, 0x56BCA7E, 0x506B7E85, 0x557E648, 0x70BCEA0C, 0x5F48FC12, 0x39D9C622, 0x0C194FC71, 0x17332212, 0x0E114F544, 0x0D8EBFA64, 0x7EE79D09, 0x0F14A5103, 0x0C3B96E0B, 0x43807301, 0x35F68E0B, 0x1DBB2E3D, 0x0DE98B003, 0x21997C1D, 0x41A78609, 0x0C09D4972, 0x0D75FB79, 0x389D086C, 0x41E35777, 0x0E17AC409, 0x94D8947B, 0x68D04014, 0x15AEAC05, 0x4DB9AC44, 0x0E5A5664, 0x1245CE34, 0x0A292AB26, 0x0EE0E8F00, 0x0C71BE12E, 0x0A7E9916F, 0x661BB411, 0x22141736, 0x759DCAB4, 0x0C96738C, 0x3E97FF53, 0x0C2D74D57, 0x0F84B7164, 0x0BC7E9D5D, 0x0B3229F5A, 0x0BC05E06F, 0x0FFFE105F, 0x0E8182E66, 0x0D9C00E2D, 0x0DD97C162, 0x9B2AA03, 0x1A689536, 0x9D350B55, 0x1627A67D, 0x52059E22, 0x0DF18634C, 0x45B29845, 0x33707F31, 0x7D2A391A, 0x121830EF, 0x404E787, 0x1C6E6D0, 0x5102FAD8, 0x6BFF20FE, 0x43528945, 0x0E7B0C670, 0x7E131D79, 0x0A11D0353, 0x3DD5639C, 0x506219F3, 0x72461551, 0x4C3DA71E, 0x20AEC362, 0x0BAC9EA36, 0x82B4164, 0x0D3D0623D, 0x76CFCA26, 0x72A5243, 0x0BBE99023, 0x4F90D953, 0x0E4C11326, 0x0C59B3B27, 0x69F86E0A, 0x82F71E7B, 0x0DBC2E124, 0x0BBFD0C2D, 0x61108247, 0x0D3644C2C, 0x0A1DB3F4B, 0x0A8F92528, 0x0E0B46339, 0x0D5721F2E, 0x0FD3C206D, 0x4A497B, 0x0AC9CAA37, 0x408FA932, 0x0E7FA0F6C, 0x2AB0C730, 0x0E1ACAC05, 0x0F50FB41E, 0x88863D3C, 0x0A32A2658, 0x41BC5725, 0x0A934011F, 0x5DF4100F, 0x49E79809, 0x7C05645C, 0x0D3C3DB35, 0x5011EB4C, 0x38EFF47F, 0x2254B509, 0x34D3FE72, 0x0FD8A3027, 0x8B4C2414, 0x0B6CA1D6E, 0x0D84D124C, 0x5D1461FF, 0x663F3D06, 0x372DED1B, 0x0E875F28, 0x0BFD4C55D, 0x8C67C231, 0x0BD98903A, 0x0BC11E64A, 0x8CB10B2D, 0x69353B72, 0x0FCA08F7D, 0x73AC1B19, 0x93E50223, 0x0DE4D3C03, 0x68BCCF37, 0x1B6C405F, 0x8178625B, 0x0A978275D, 0x0C4A0417E, 0x0DE6C736A, 0x0F25FC066, 0x41A6A55A, 0x0B1304F20, 0x4271AB33, 0x79959A5A, 0x0D384042A, 0x7744AA26, 0x7620CB01, 0x5E4F198, 0x63938F5C, 0x1551A865, 0x98C9E55, 0x45EA674A, 0x0FA203C46, 0x8B41CB0B, 0x4BF2D28, 0x8788FE77, 0x48DA5B46, 0x0C1D01373, 0x133A0A25, 0x0B10F9738, 0x0BD71A370, 0x87E6253E, 0x44F5995B, 0x9BBFDF73, 0x0EFA2F575, 0x6061DA3A, 0x1C38424F, 0x991B1D53, 0x24021C39, 0x0FAA4B539, 0x8B7BDD39, 0x21FDE62, 0x15694DC9, 0x7690AA57, 0x8ABEAA2, 0x7E5A0904, 0x45313314, 0x545E2770, 0x0DC2B3242, 0x7240FB28, 0x0A3CC043E, 0x80478C41, 0x0B72A6373, 0x9DED4004, 0x0C89574D, 0x0BCE9901B, 0x24763F7C, 0x5463B313, 0x7DBAA40E, 0x38B04921, 0x6734A4C, 0x3A2C487F, 0x0BF966F5F, 0x4A68E427, 0x0D6EB2773, 0x0AE396555, 0x0AAC9BE62, 0x0F2236A42, 0x47558228, 0x0CFCBDA1B, 0x0EDC81F7C, 0x0D3D05F62, 0x34749C2F, 0x989E2456, 0x0A1BDE84F, 0x13B2F81D, 0x17F92D5A, 0x0E6EE1B64, 0x6710200E, 0x0F324601C, 0x582F170D, 0x0ADD244C, 0x746CEC5D, 0x105A7A00, 0x0A8CA6550, 0x80F5432B, 0x0CC430B1C, 0x0CC40A54C, 0x0D458F73E, 0x49FEAF2A, 0x4F1EE6D, 0x0DACB410B, 0x832AF829, 0x0C3875E4D, 0x25342633, 0x5916201D, 0x72C1C322, 0x0CFFDE415, 0x4C3A8A5F, 0x0B916464B, 0x9EC9BF31, 0x3903AA5B, 0x8CE7A52D, 0x0D33D5C61, 0x0D1A1CE31, 0x2DA58E7D, 0x0E6EF547F, 0x0E89AFC0B, 0x1394AA61, 0x4D00750D, 0x0DCBF5C28, 0x6CC3C16E, 0x58DD9959, 0x502C4906, 0x7C1D3C6F, 0x0A8FF29, 0x0D0218D31, 0x4861470B, 0x0CCE8A476, 0x0A47A8470, 0x915FF735, 0x0D1D99364, 0x7F46C67B, 0x148AEF5F, 0x9461F231, 0x0A47AEC2E, 0x6EA00F7D, 0x623B654, 0x7378D144, 0x0BADA995C, 0x0C039FC1F, 0x12429176, 0x0F3DD4338, 0x4C21A24D, 0x0E57FED57, 0x0C47F126A, 0x7AC6304B, 0x0CB6F4257, 0x0AD1A0F76, 0x8D5ADB2C, 0x1870B764, 0x89DA6B1E, 0x0F91D9D1B, 0x704D513E, 0x0D906B524, 0x753BD90A, 0x70F55068, 0x0A9284256, 0x0BD9C2016, 0x3DDEF55E, 0x4DA3C646, 0x4EFC174C, 0x0EB88943, 0x3F3E0774, 0x3FC4E8FE, 0x3535FFF7, 0x67EFA479, 0x0D1261729, 0x0A93C324A, 0x0E4DC4A36, 0x8B01B105, 0x69762E6A, 0x0F61EDC2C, 0x7EDFF43D, 0x0B597D037, 0x1E7FC078, 0x55DDE79B, 0x3ECE9111, 0x1CC0FFF3, 0x0EF79161E, 0x0BDB8DC2F, 0x0BE7EC340, 0x7854823C, 0x0B6D6794B, 0x2FCC147F, 0x515B3761, 0x2C125356, 0x9FC16567, 0x0FA837937, 0x0E9AE736C, 0x0DC9F5B46, 0x4827407E, 0x38AB8B38, 0x0EA57E509, 0x1411CD40, 0x9B319364, 0x8D71617F, 0x85754632, 0x6C58AA0D }; amsn-0.98.9/utils/webcamsn/src/kidhash.h0000644000175000017500000000015210253461533017703 0ustar billiobbilliob#ifndef KIDHASH_H #define KIDHASH_H int MakeKidHash(char *a, int *a_size, int kid, char * sid); #endif amsn-0.98.9/utils/webcamsn/src/Rules.mk0000644000175000017500000000147310750446030017546 0ustar billiobbilliobOBJS-webcamsn := $(webcamsn_dir)/src/webcamsn.o $(webcamsn_dir)/src/kidhash.o $(webcamsn_dir)/src/libmimic.a TARGETS-webcamsn := $(webcamsn_dir)/src/webcamsn.$(SHLIB_EXTENSION) OBJS-mimic := $(webcamsn_dir)/src/bitstring.o $(webcamsn_dir)/src/deblock.o $(webcamsn_dir)/src/encode.o \ $(webcamsn_dir)/src/idct_dequant.o $(webcamsn_dir)/src/mimic.o \ $(webcamsn_dir)/src/vlc_decode.o $(webcamsn_dir)/src/colorspace.o $(webcamsn_dir)/src/decode.o \ $(webcamsn_dir)/src/fdct_quant.o $(webcamsn_dir)/src/vlc_common.o $(webcamsn_dir)/src/vlc_encode.o TARGETS-mimic := $(webcamsn_dir)/src/libmimic.a $(TARGETS-mimic): $(OBJS-mimic) @$(echo_ar_lib) @$(ar_lib) $(TARGETS-webcamsn): $(OBJS-webcamsn) all:: $(TARGETS-webcamsn) clean:: clean-webcamsn clean-webcamsn:: rm -f $(TARGETS-webcamsn) $(OBJS-webcamsn) amsn-0.98.9/utils/webcamsn/src/mimic-private.h0000644000175000017500000000571110647521273021051 0ustar billiobbilliob/* Copyright (C) 2005 Ole André Vadla Ravnås * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef MIMIC_PRIVATE_H #define MIMIC_PRIVATE_H #include "mimic.h" #define MIMIC_ENCODER_DEFAULT_QUALITY 0 struct _MimCtx { gboolean encoder_initialized; gboolean decoder_initialized; gint frame_width; gint frame_height; gint quality; gint num_coeffs; gint y_stride; gint y_row_count; gint y_size; gint crcb_stride; gint crcb_row_count; gint crcb_size; gint num_vblocks_y; gint num_hblocks_y; gint num_vblocks_cbcr; gint num_hblocks_cbcr; guchar *cur_frame_buf; guchar *prev_frame_buf; gint8 vlcdec_lookup[2296]; gchar *data_buffer; guint data_index; guint32 cur_chunk; gint cur_chunk_len; guint32 *chunk_ptr; gboolean read_odd; gint frame_num; gint ptr_index; guchar *buf_ptrs[16]; }; typedef struct { guchar length1; guint32 part1; guchar length2; guint32 part2; } VlcSymbol; typedef struct { guint32 magic; guchar pos_add; guchar num_bits; } VlcMagic; void _mimic_init(MimCtx *ctx, gint width, gint height); guchar _clamp_value(gint value); guint32 _read_bits(MimCtx *ctx, gint num_bits); void _write_bits(MimCtx *ctx, guint32 bits, gint length); void _vlc_encode_block(MimCtx *ctx, const gint *block, gint num_coeffs); gboolean _vlc_decode_block(MimCtx *ctx, gint *block, gint num_coeffs); void _fdct_quant_block(MimCtx *ctx, gint *block, const guchar *src, gint stride, gboolean is_chrom, gint num_coeffs); void _idct_dequant_block(MimCtx *ctx, gint *block, gboolean is_chrom); VlcMagic *_find_magic(guint magic); void _initialize_vlcdec_lookup(gint8 *lookup_tbl); void _rgb_to_yuv(const guchar *input_rgb, guchar *output_y, guchar *output_cb, guchar *output_cr, gint width, gint height); void _yuv_to_rgb(const guchar *input_y, const guchar *input_cb, const guchar *input_cr, guchar *output_rgb, guint width, guint height); void _deblock(guchar *blocks, guint stride, guint row_count); #endif // MIMIC_PRIVATE_H amsn-0.98.9/utils/webcamsn/src/kidhash.c0000644000175000017500000001416410516043025017700 0ustar billiobbilliob#include #include #include "kidhash.h" #include "constants.h" #include "glib_replacement.h" const double append_multiplicator = 4.614703357219696e-7; const char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./"; const int init_variable = 0x0FE0637B1; int init_table[31]; int init_table_size = 31; int *init_table_ptr = NULL; int *init_table_end = NULL; int *init_table_idx2 = NULL; int *init_table_idx1 = NULL; int init_table_idx_diff = 3; const int fixed_value_3 = 3; int key[26]; void crazy_algorithm(int *table,int *temp_data) { unsigned int i, temp = 0; // Initialize the 4 temp variables int P = table[1], PP = table[2], PPP = table[3], PPPP = table[0]; // four loops made into one for (i = 0; i < 16*4; i++) { temp = PPPP + const_mult[i] * const_values[i]; // Common to all loops if(i/16 == 0) temp += GUINT32_FROM_LE(temp_data[i]) + (PPP ^ (P & (PP ^ PPP))); // add this for first loop i =[0..15] else if(i/16 == 1) temp += GUINT32_FROM_LE(temp_data[((i-16)*5 + 1)%16]) + (PP ^ (PPP & (P ^ PP))); // add for second i = [16..31] else if(i/16 == 2) temp += GUINT32_FROM_LE(temp_data[((i-32)*3 + 5)%16]) + (P ^ (PP ^ PPP)); // add for second i = [31..47] else if(i/16 == 3) temp += GUINT32_FROM_LE(temp_data[choose_data_idx[i-48]]) + (PP ^ ((PPP ^ 0xFFFFFFFF) | P)); // add for the last loop PPPP = PPP; PPP = PP; PP = P; P += (temp >> shifts_right[(i%4) + 4*(i/16)]) | (temp << shifts_left[(i%4) + 4*(i/16)]); // look for the shifts in the table } // store in the output variables table[0] += PPPP; table[1] += P; table[2] += PP; table[3] += PPP; return; } int alter_table() { int ret; if (fixed_value_3 != 0 ) { *init_table_idx2 = *init_table_idx1 + *init_table_idx2; ret = *init_table_idx2 >> 1 & 0x7fffffff; if (init_table_idx2 + 1 < init_table_end) { if(init_table_idx1 + 1 >= init_table_end) init_table_idx1 = init_table_ptr; else init_table_idx1++; init_table_idx2++; } else { init_table_idx2 = init_table_ptr; init_table_idx1++; } } else { init_table_ptr[0] = init_table_ptr[0] % 0x1f31d * 0x41a7 - init_table_ptr[0] / 0x1f31d * 0xb14; if ( init_table_ptr[0] <= 0) init_table_ptr[0] += 0x7fffffff; init_table_ptr[0] &= 0x7fffffff; ret = init_table_ptr[0]; } return ret; } void init(int value) { int i = 0; *init_table_ptr = value; if(fixed_value_3) { for (i = 1; i < init_table_size; i++) { init_table_ptr[i] = init_table_ptr[i-1] % 0x1f31d * 0x41a7 - init_table_ptr[i-1] / 0x1f31d * 0xb14; if ( init_table_ptr[i] <= 0) init_table_ptr[i] += 0x7fffffff; } init_table_idx1 = init_table_ptr; init_table_idx2 = init_table_ptr + init_table_idx_diff; for(i = init_table_size * 10; i > 0; i--) alter_table(); } return; } void set_result (int *table, char * temp_data, int * result) { char * temp_data_ptr = temp_data; int idx; idx = (table[4] / 8) & 63; temp_data_ptr = temp_data + idx; *temp_data_ptr = 0x80; temp_data_ptr++; idx = 55 - idx; if ( idx < 0) { memset(temp_data_ptr, 0, idx + 8); crazy_algorithm(table, (int *)temp_data); memset(temp_data, 0, 56); } else memset(temp_data_ptr, 0, idx); temp_data_ptr += idx; // The last 2 dwords are size / 8 and a bool for if size > 64 *((int *)temp_data_ptr) = GUINT32_TO_LE(table[4]); temp_data_ptr+=4; *((int *)temp_data_ptr) = GUINT32_TO_LE(table[5]); crazy_algorithm(table, (int *)temp_data); result[0] = table[0]; result[1] = table[1]; result[2] = table[2]; result[3] = table[3]; result[4] = 0; } void Hash(char * a, int key_size) { int result[5], table[] = {0x67452301, 0x0EFCDAB89, 0x98BADCFE, 0x10325476, 8*key_size, key_size >> 29}; char temp_data[64]; int *key_ptr = key; char *a_ptr = a; int i, temp; if(key_size >= 64) { for(i = key_size / 64; i > 0 ; i--) { memcpy(temp_data, key_ptr, 64); crazy_algorithm(table, (int *)temp_data); key_ptr += 16; } key_size &= 63; } memcpy(temp_data, key_ptr, key_size); set_result(table, temp_data, result); result[0] = GUINT32_TO_LE(result[0]); result[1] = GUINT32_TO_LE(result[1]); result[2] = GUINT32_TO_LE(result[2]); result[3] = GUINT32_TO_LE(result[3]); result[4] = GUINT32_TO_LE(result[4]); for (i = 0 ; i < 18; i += 3) { temp = (0x000000ff &((char *) result)[i]) << 16 | (0x000000ff & ((char *) result)[i+1]) << 8 | (0x000000ff & ((char *) result)[i+2]); a_ptr[0] = alphabet[temp >> 6 >> 6 >> 6 & 0x3F]; a_ptr[1] = alphabet[temp >> 6 >> 6 & 0x3F]; a_ptr[2] = alphabet[temp >> 6 & 0x3F]; a_ptr[3] = alphabet[temp & 0x3F]; a_ptr+=4; } *(a_ptr - 2) = 0; } int MakeKidHash(char *a, int *a_size, int kid, char * sid) { int i; char * sid_ptr = sid; char *key_ptr = (char *) key; char *append_char; char *append_ptr; if(kid < 0 || kid > 100) return 0; if (*a_size < 25) return 0; memset(key, 0, 26 * sizeof(int)); init_table_ptr = init_table; init_table_idx1 = init_table_ptr; init_table_idx2 = init_table_ptr + init_table_idx_diff; init_table_end = init_table_ptr + init_table_size; for (i = 0 ; i < 100; i++) { if(*sid_ptr == 0) break; *key_ptr = *sid_ptr; key_ptr++; sid_ptr++; } if (sid_ptr - sid + append_size > 100) return 0; init(init_variable); while(kid > 0) { alter_table(); kid--; } append_char = (char *) (key_append + (long) (alter_table() * append_multiplicator) * 4); append_ptr = append_char; for (i = 0 ; i < append_size; i++) { #ifdef __BIG_ENDIAN__ *key_ptr = append_char[3 - ((append_ptr - append_char)%4) + 4*((append_ptr - append_char)/4)]; #else *key_ptr = *append_ptr; #endif key_ptr++; append_ptr++; } Hash(a, (int) (sid_ptr - sid) + append_size); return 1; } int test () { char sid[] = "sid=aD4ENXNY3Q"; char sid2[] = "sid=KCSwrDFrVg"; char a[30]; int kid = 64; int kid2 = 98; int a_size = 30; printf("\n"); if (MakeKidHash(a, &a_size, kid2, sid2)) { printf("Computed hash is : %s\n", a); printf("Should be : hHQbVkZ/eApiRzPiTg6jyw\n\n\n"); } if(MakeKidHash(a, &a_size, kid, sid)) { printf("Computed hash is : %s\n", a); printf("Should be : HlyPs6/kiWhr0JxmMO1A4Q\n"); } printf("\n\n"); return 0; } amsn-0.98.9/utils/webcamsn/src/Webcamsn.dsw0000644000175000017500000000140710455541227020404 0ustar billiobbilliobMicrosoft Developer Studio Workspace File, Format Version 6.00 # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! ############################################################################### Project: "Webcamsn"=.\Webcamsn.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ Begin Project Dependency Project_Dep_Name libmimic End Project Dependency }}} ############################################################################### Project: "libmimic"=.\libmimic.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Global: Package=<5> {{{ }}} Package=<3> {{{ }}} ############################################################################### amsn-0.98.9/utils/webcamsn/src/bitstring.c0000644000175000017500000000516210225230720020265 0ustar billiobbilliob/* Copyright (C) 2005 Ole André Vadla Ravnås * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mimic-private.h" /* * _read_bits * * Internal helper-function used to read num_bits * from stream. */ guint32 _read_bits(MimCtx *ctx, gint num_bits) { guint32 bits; if (ctx->cur_chunk_len >= 16) { guchar *input_buf = (guchar *) ctx->data_buffer + ctx->data_index; if (!ctx->read_odd) { ctx->read_odd = TRUE; ctx->cur_chunk = (input_buf[3] << 24) | (input_buf[2] << 16) | (input_buf[1] << 8) | input_buf[0]; } else { ctx->read_odd = FALSE; ctx->cur_chunk = (input_buf[1] << 24) | (input_buf[0] << 16) | (input_buf[7] << 8) | input_buf[6]; ctx->data_index += 4; } ctx->cur_chunk_len -= 16; } bits = (ctx->cur_chunk << ctx->cur_chunk_len) >> (32 - num_bits); ctx->cur_chunk_len += num_bits; return bits; } /* * _write_bits * * Internal helper-function used to write "length" * bits of "bits" to stream. */ void _write_bits(MimCtx *ctx, guint32 bits, gint length) { /* Left-align the bit string within its 32-bit container. */ bits <<= (32 - length); /* Append the bit string (one or more of the trailing bits might not fit, but that's ok). */ ctx->cur_chunk |= bits >> ctx->cur_chunk_len; ctx->cur_chunk_len += length; /* Is it full? */ if (ctx->cur_chunk_len >= 32) { /* Add the full 32-bit chunk to the stream and update counter. */ ctx->chunk_ptr[0] = GUINT32_TO_LE(ctx->cur_chunk); ctx->chunk_ptr++; ctx->cur_chunk_len -= 32; /* Add any trailing bits that didn't fit. */ ctx->cur_chunk = bits << (length - ctx->cur_chunk_len); } } amsn-0.98.9/utils/webcamsn/src/idct_dequant.c0000644000175000017500000000732510225230720020727 0ustar billiobbilliob/* Copyright (C) 2005 Ole Andr Vadla Ravns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mimic-private.h" void _idct_dequant_block(MimCtx *ctx, gint *block, gboolean is_chrom) { gdouble f; gint i, *p; /* * De-quantize. */ f = (10000 - ctx->quality) * 10.0 * (gfloat) 9.9999997e-5; if (f > 10.0) f = 10.0; if (!is_chrom) { if (f < 2.0) f = 2.0; } else { if (f < 1.0) f = 1.0; } block[0] <<= 1; block[1] <<= 2; block[8] <<= 2; for (i = 2; i < 64; i++) { if (i == 8) continue; block[i] *= f; } /* * Inverse DCT, first pass (horizontal). */ p = block; for (i = 0; i < 8; i++) { gint v1, v2, v3, v4, v5, v6, v7, v8; gint va, vb; va = (p[0] << 11) + (p[4] << 11); vb = ((p[2] << 2) * 392) + (((p[2] << 2) + (p[6] << 2)) * 277); v1 = va + vb + 512; v2 = va - vb + 512; va = (p[0] << 11) - (p[4] << 11); vb = (((p[2] << 2) + (p[6] << 2)) * 277) - ((p[6] << 2) * 946); v3 = va + vb + 512; v4 = va - vb + 512; va = (p[1] << 9) + (p[3] * 724) + (p[7] << 9); vb = (p[1] << 9) + (p[5] * 724) - (p[7] << 9); v5 = (((va + vb) * 213) - (vb * 71)) >> 6; v6 = (((va + vb) * 213) - (va * 355)) >> 6; va = (p[1] << 9) - (p[3] * 724) + (p[7] << 9); vb = (p[1] << 9) - (p[5] * 724) - (p[7] << 9); v7 = (((va + vb) * 251) - (va * 201)) >> 6; v8 = (((va + vb) * 251) - (vb * 301)) >> 6; p[0] = (v1 + v5) >> 10; p[1] = (v3 + v7) >> 10; p[2] = (v4 + v8) >> 10; p[3] = (v2 + v6) >> 10; p[4] = (v2 - v6) >> 10; p[5] = (v4 - v8) >> 10; p[6] = (v3 - v7) >> 10; p[7] = (v1 - v5) >> 10; p += 8; } /* * Inverse dct, second pass (vertical). */ p = block; for (i = 0; i < 8; i++) { gint v1, v2, v3, v4, v5, v6, v7, v8; gint va, vb; va = (p[0] << 9) + (p[32] << 9); vb = ((p[16] + p[48]) * 277) + (p[16] * 392); v1 = va + vb + 1024; v2 = va - vb + 1024; va = (p[0] << 9) - (p[32] << 9); vb = ((p[16] + p[48]) * 277) - (p[48] * 946); v3 = va + vb + 1024; v4 = va - vb + 1024; va = ((p[8] << 7) + (p[24] * 181) + (p[56] << 7)) >> 6; vb = ((p[8] << 7) + (p[40] * 181) - (p[56] << 7)) >> 6; v5 = ((va + vb) * 213) - (vb * 71); v6 = ((va + vb) * 213) - (va * 355); va = ((p[8] << 7) - (p[24] * 181) + (p[56] << 7)) >> 6; vb = ((p[8] << 7) - (p[40] * 181) - (p[56] << 7)) >> 6; v7 = ((va + vb) * 251) - (va * 201); v8 = ((va + vb) * 251) - (vb * 301); p[0] = (v1 + v5) >> 11; p[8] = (v3 + v7) >> 11; p[16] = (v4 + v8) >> 11; p[24] = (v2 + v6) >> 11; p[32] = (v2 - v6) >> 11; p[40] = (v4 - v8) >> 11; p[48] = (v3 - v7) >> 11; p[56] = (v1 - v5) >> 11; p++; } } amsn-0.98.9/utils/webcamsn/src/webcamsn.h0000644000175000017500000000644711231467240020102 0ustar billiobbilliob/* File : webcamsn.h Description : Header file for the webcamsn extension for tk. A wrapper for libmimdec Author : Youness El Alaoui ( KaKaRoTo - kakaroto@user.sourceforge.net) */ #ifndef _WEBCAMSN #define _WEBCAMSN // Include files, must include windows.h before tk.h and tcl.h before tk.h or else compiling errors #include #include "mimic.h" #ifdef WIN32 #include #endif #include "string.h" #include #include // Defined as described in tcl.tk compiling extension help #ifndef STATIC_BUILD #if defined(_MSC_VER) # define EXPORT(a,b) __declspec(dllexport) a b # define DllEntryPoint DllMain #else # if defined(__BORLANDC__) # define EXPORT(a,b) a _export b # else # define EXPORT(a,b) a b # endif #endif #endif #define DLL_BUILD #define BUILD_WEBCAMSN #ifdef BUILD_WEBCAMSN # undef TCL_STORAGE_CLASS # define TCL_STORAGE_CLASS DLLEXPORT #endif #ifdef __cplusplus extern "C" #endif typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned int DWORD; typedef struct mimic_header { WORD header_size; WORD width; WORD height; WORD reserved1; DWORD payload_size; DWORD fourcc; DWORD reserved2; DWORD reserved3; } MimicHeader; enum codec_types {ENCODER, DECODER_UNINITIALIZED, DECODER_INITIALIZED}; struct CodecInfo { MimCtx * codec; enum codec_types type; char name[30]; unsigned int frames; }; typedef struct CodecInfo CodecInfo; #define MAX_INTERFRAMES 15 EXTERN BYTE * RGBA2RGB(Tk_PhotoImageBlock data); // External functions EXTERN int Webcamsn_Init _ANSI_ARGS_((Tcl_Interp *interp)); EXTERN int Webcamsn_SafeInit _ANSI_ARGS_((Tcl_Interp *interp)); EXTERN int Webcamsn_NewDecoder _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Webcamsn_NewEncoder _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Webcamsn_Decode _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Webcamsn_Encode _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Webcamsn_SetQuality _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Webcamsn_GetWidth _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Webcamsn_GetHeight _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Webcamsn_GetQuality _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Webcamsn_Close _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Webcamsn_Count _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Webcamsn_Frames _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); # undef TCL_STORAGE_CLASS # define TCL_STORAGE_CLASS DLLIMPORT #endif /* _TKCXIMAGE */ amsn-0.98.9/utils/webcamsn/src/deblock.c0000644000175000017500000002505010225230720017661 0ustar billiobbilliob/* Copyright (C) 2005 Ole Andr Vadla Ravns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "mimic-private.h" static void deblock_horizontal(guchar *blocks, guint stride, guint row_count); static void deblock_vertical(guchar *blocks, guint stride, guint row_count); static gboolean deblock_h_consider_entire(guchar *blocks, guint stride); static void deblock_h_do_entire(guchar *blocks, guint stride); static void deblock_h_do_boundaries(guchar *blocks, guint stride); static gboolean deblock_v_consider_entire(guchar *blocks, guint stride); static void deblock_v_do_entire(guchar *blocks, guint stride); static void deblock_v_do_boundaries(guchar *blocks, guint stride); /* * _deblock * * Internal helper-function used for de-blocking. */ void _deblock(guchar *blocks, guint stride, guint row_count) { deblock_horizontal(blocks, stride, row_count); deblock_vertical(blocks, stride, row_count); } static void deblock_horizontal(guchar *blocks, guint stride, guint row_count) { guchar *p1; gint i, j, n1, n2; if (stride <= 8 || row_count == 0) return; p1 = blocks + 4; n1 = ((row_count - 1) >> 2) + 1; n2 = ((stride - 9) >> 3) + 1; for (i = 0; i < n1; i++) { guchar *p; p = p1; for (j = 0; j < n2; j++) { if (deblock_h_consider_entire(p - 1, stride) == TRUE) { gint v1, v2, v; v1 = p[0]; v2 = p[7]; v = v1 - v2; if (v <= 0) v = v2 - v1; if (v < 20) deblock_h_do_entire(p - 1, stride); } else { deblock_h_do_boundaries(p - 1, stride); } p += 8; } p1 += stride * 4; } } static void deblock_vertical(guchar *blocks, guint stride, guint row_count) { gint i, j, k, n1, n2; guchar *p1, *p2; if (stride == 0 || row_count <= 8) return; p1 = blocks + (stride * 3); p2 = blocks + (stride * 4); n1 = ((row_count - 9) >> 3) + 1; n2 = ((stride - 1) >> 3) + 1; for (i = 0; i < n1; i++) { guchar *p3, *p4; p3 = p1; p4 = p2; for (j = 0; j < n2; j++) { if (deblock_v_consider_entire(p3, stride) == TRUE) { guchar *p5; gboolean do_entire; p5 = p3 + (stride * 8); do_entire = TRUE; for (k = 0; k < 8; k++) { gint v1, v2, v; v1 = p4[k]; v2 = p5[k]; v = v1 - v2; if (v <= 0) v = v2 - v1; if (v > 20) { do_entire = FALSE; break; } } if (do_entire) deblock_v_do_entire(p3, stride); } else { deblock_v_do_boundaries(p3, stride); } p3 += 8; p4 += 8; } p1 += stride * 8; p2 += stride * 8; } } static gboolean deblock_h_consider_entire(guchar *blocks, guint stride) { guchar *p; gint i, j, count; count = 0; p = blocks; for (i = 0; i < 4; i++) { for (j = 1; j <= 7; j++) { gint v1, v2, v; v1 = p[j]; v2 = p[j+1]; v = v1 - v2; if (v <= 0) v = v2 - v1; if (v <= 1) count--; } p += stride; } return (count <= -20); } static void deblock_h_do_entire(guchar *blocks, guint stride) { guchar buf[8], *p; gint i; p = blocks; for (i = 0; i < 4; i++) { gint v, low, high; v = p[0] - p[1]; if (v <= 0) v = p[1] - p[0]; if (v < 10) low = p[0]; else low = p[1]; v = p[8] - p[9]; if (v <= 0) v = p[9] - p[8]; if (v >= 10) high = p[8]; else high = p[9]; v = (low * 3) + p[1] + p[2] + p[3] + p[4] + 4; buf[0] = (((p[1] + v) << 1) - p[4] + p[5]) >> 4; v += p[5] - low; buf[1] = (((p[2] + v) << 1) - p[5] + p[6]) >> 4; v += p[6] - low; buf[2] = (((p[3] + v) << 1) - p[6] + p[7]) >> 4; v += p[7] - low; buf[3] = (((p[4] + v) << 1) - p[1] - p[7] + p[8] + low) >> 4; v += p[8] - p[1]; buf[4] = (((p[5] + v) << 1) + p[1] - p[2] - p[8] + high) >> 4; v += high - p[2]; buf[5] = (((p[6] + v) << 1) + p[2] - p[3]) >> 4; v += high - p[3]; buf[6] = (((p[7] + v) << 1) + p[3] - p[4]) >> 4; v += high; buf[7] = (((p[8] + v) << 1) - p[4] - p[5]) >> 4; memcpy(p + 1, buf, 8); p += stride; } } static void deblock_h_do_boundaries(guchar *blocks, guint stride) { guchar *p; gint i; p = blocks; for (i = 0; i < 4; i++) { gint v, v1, v2, v3; v = p[4] - p[5]; if ((v / 2) != 0) { v1 = ((p[3] - p[6]) * 2) - (v * 5); if (abs(v1) < 80) { v2 = ((p[3] - p[2]) * 5) + ((p[1] - p[4]) * 2); v3 = (p[5] * 2) + (p[7] * 5) - (p[8] * 7); v = abs(v1) - MIN(abs(v2), abs(v3)); if (v > 0) { v = ((v * 5) + 32) >> 6; if (v > 0) { v2 = (p[4] - p[5]) / 2; v3 = (((v1 < 0) * 2) - 1) * v; if (v2 > 0) v = MIN(v2, ((v3 < 0) - 1) & v3); else v = MAX(v2, ((v3 > 0) - 1) & v3); p[4] -= v; p[5] += v; } } } } p += stride; } } static gboolean deblock_v_consider_entire(guchar *blocks, guint stride) { gint count, i, j; guchar *p1, *p2; count = 0; p1 = blocks + stride; p2 = blocks + (stride * 2); for (i = 0; i < 7; i++) { for (j = 0; j < 8; j++) { gint v1, v2, v; v1 = p1[j]; v2 = p2[j]; v = v1 - v2; if (v <= 0) v = v2 - v1; if (v <= 1) count++; } p1 += stride; p2 += stride; } return (count > 40); } static void deblock_v_do_entire(guchar *blocks, guint stride) { gint offset0, offset1, offset2, offset3; gint offset4, offset5, offset6, offset7; gint offset8, i; guchar *p, buf[8]; offset0 = stride - (stride * 6); offset1 = (stride * 2) - (stride * 6); offset2 = (stride * 3) - (stride * 6); offset3 = (stride * 4) - (stride * 6); offset4 = (stride * 5) - (stride * 6); offset5 = 0; offset6 = (stride * 7) - (stride * 6); offset7 = (stride * 8) - (stride * 6); offset8 = (stride * 9) - (stride * 6); p = blocks + (stride * 6); for (i = 0; i < 8; i++) { gint v, low, high; v = blocks[i] - p[offset0]; if (v <= 0) v = p[offset0] - blocks[i]; if (v < 10) low = blocks[i]; else low = p[offset0]; v = p[offset7] - p[offset8]; if (v <= 0) v = p[offset8] - p[offset7]; if (v < 10) high = p[offset8]; else high = p[offset7]; v = p[offset0] + (low * 3) + p[offset1] + p[offset2] + p[offset3] + 4; buf[0] = (((p[offset0] + v) << 1) - p[offset3] + p[offset4]) >> 4; v += p[offset4] - low; buf[1] = (((p[offset1] + v) << 1) - p[offset4] + p[0]) >> 4; v += p[0] - low; buf[2] = (((p[offset2] + v) << 1) - p[0] + p[offset6]) >> 4; v += p[offset6] - low; buf[3] = (((p[offset3] + v) << 1) - p[offset0] - p[offset6] + p[offset7] + low) >> 4; v += p[offset7] - p[offset0]; buf[4] = (((p[offset4] + v) << 1) - p[offset7] - p[offset1] + p[offset0] + high) >> 4; v += high - p[offset1]; buf[5] = (((p[0] + v) << 1) - p[offset2] + p[offset1]) >> 4; v += high - p[offset2]; buf[6] = (((p[offset6] + v) << 1) - p[offset3] + p[offset2]) >> 4; v += high; buf[7] = (((p[offset7] + v) << 1) - p[offset4] - p[offset3]) >> 4; p[offset0] = buf[0]; p[offset1] = buf[1]; p[offset2] = buf[2]; p[offset3] = buf[3]; p[offset4] = buf[4]; p[offset5] = buf[5]; p[offset6] = buf[6]; p[offset7] = buf[7]; p++; } } static void deblock_v_do_boundaries(guchar *blocks, guint stride) { guchar *p; gint offset0, offset1, offset2, offset3; gint offset4, offset5, offset6, offset7; gint i; p = blocks + (stride * 3); offset0 = stride - (stride * 3); offset1 = (stride * 2) - (stride * 3); offset2 = 0; offset3 = (stride * 4) - (stride * 3); offset4 = (stride * 5) - (stride * 3); offset5 = (stride * 6) - (stride * 3); offset6 = (stride * 7) - (stride * 3); offset7 = (stride * 8) - (stride * 3); for (i = 0; i < 8; i++) { gint v1, v2, v3, v; v1 = ((p[offset4] - p[offset3]) * 5) + ((p[offset2] - p[offset5]) * 2); if (abs(v1) < 80) { v2 = ((p[offset2] - p[offset1]) * 5) + ((p[offset0] - p[offset3]) * 2); v3 = ((p[offset6] - p[offset5]) * 5) + ((p[offset4] - p[offset7]) * 2); v = abs(v1) - MIN(abs(v2), abs(v3)); if (v < 0) v = 0; v2 = (p[offset3] - p[offset4]) / 2; v3 = (((v * 5) + 32) >> 6) * (((v1 < 0) * 2) - 1); if (v2 > 0) v = MIN(v2, ((v3 < 0) - 1) & v3); else v = MAX(v2, ((v3 > 0) - 1) & v3); } else { v = 0; } p[offset3] -= v; p[offset4] += v; p++; } } amsn-0.98.9/utils/webcamsn/src/Webcamsn.dsp0000644000175000017500000000771611244666345020414 0ustar billiobbilliob# Microsoft Developer Studio Project File - Name="Webcamsn" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 CFG=Webcamsn - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "Webcamsn.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "Webcamsn.mak" CFG="Webcamsn - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "Webcamsn - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "Webcamsn - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "Webcamsn - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WEBCAMSN_EXPORTS" /YX /FD /c # ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WEBCAMSN_EXPORTS" /D "USE_TCL_STUBS" /D "USE_TK_STUBS" /YX /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x40c /d "NDEBUG" # ADD RSC /l 0x40c /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 # ADD LINK32 tclstub85.lib tkstub85.lib /nologo /dll /machine:I386 !ELSEIF "$(CFG)" == "Webcamsn - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Webcamsn___Win32_Debug" # PROP BASE Intermediate_Dir "Webcamsn___Win32_Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WEBCAMSN_EXPORTS" /YX /FD /GZ /c # ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "USE_TCL_STUBS" /D "USE_TK_STUBS" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WEBCAMSN_EXPORTS" /YX /FD /GZ /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x40c /d "_DEBUG" # ADD RSC /l 0x40c /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept # ADD LINK32 /nologo /dll /debug /machine:I386 /pdbtype:sept !ENDIF # Begin Target # Name "Webcamsn - Win32 Release" # Name "Webcamsn - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=.\kidhash.c # End Source File # Begin Source File SOURCE=.\webcamsn.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=.\kidhash.h # End Source File # Begin Source File SOURCE=.\webcamsn.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project amsn-0.98.9/utils/webcamsn/src/mimic.h0000644000175000017500000000440510225230720017362 0ustar billiobbilliob/* Copyright (C) 2005 Ole André Vadla Ravnås * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef MIMIC_H #define MIMIC_H //#include #include "glib_replacement.h" /** * @defgroup libmimic libmimic public API * @brief The public API of the libmimic library * * libmimic provides the API required for encoding and decoding * MIMIC v2.x-encoded content. * * @{ */ #ifdef __cplusplus #define EXTERN extern "C" #else #define EXTERN #endif /** * The mimic encoding/decoding context returned by #mimic_open * and used for all further API calls until #mimic_close. */ typedef struct _MimCtx MimCtx; typedef enum { MIMIC_RES_LOW, /**< 160x120 resolution */ MIMIC_RES_HIGH /**< 320x240 resolution */ } MimicResEnum; EXTERN MimCtx *mimic_open(); EXTERN void mimic_close(MimCtx *ctx); EXTERN gboolean mimic_encoder_init(MimCtx *ctx, const MimicResEnum resolution); EXTERN gboolean mimic_decoder_init(MimCtx *ctx, const guchar *frame_buffer); EXTERN gboolean mimic_get_property(MimCtx *ctx, const gchar *name, gpointer data); EXTERN gboolean mimic_set_property(MimCtx *ctx, const gchar *name, gpointer data); EXTERN gboolean mimic_encode_frame(MimCtx *ctx, const guchar *input_buffer, guchar *output_buffer, gint *output_length, gboolean make_keyframe); EXTERN gboolean mimic_decode_frame(MimCtx *ctx, const guchar *input_buffer, guchar *output_buffer); /** @} */ #endif // MIMIC_H amsn-0.98.9/utils/webcamsn/src/glib_replacement.h0000644000175000017500000000456710733262326021604 0ustar billiobbilliob/* No need for this file if glib.h was already included from somewhere else */ #ifndef __G_TYPES_H__ #ifndef GLIB_REPLACEMENT_H #define GLIB_REPLACEMENT_H #include typedef char gchar; typedef short gshort; typedef long glong; typedef int gint; typedef gint gboolean; typedef unsigned char guchar; typedef unsigned short gushort; typedef unsigned long gulong; typedef unsigned int guint; typedef float gfloat; typedef double gdouble; typedef void* gpointer; typedef const void *gconstpointer; typedef signed char gint8; typedef unsigned char guint8; typedef signed short gint16; typedef unsigned short guint16; typedef signed int gint32; typedef unsigned int guint32; #ifndef FALSE #define FALSE (0) #endif #ifndef TRUE #define TRUE (!FALSE) #endif #undef MAX #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #undef MIN #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #undef GUINT16_FROM_LE #undef GUINT32_FROM_LE #undef GUINT16_TO_LE #undef GUINT32_TO_LE #ifdef __BIG_ENDIAN__ #define POW_2_8 256 #define POW_2_16 65536 #define POW_2_24 16777216 #define IDX(val, i) ((unsigned int) ((unsigned char *) &val)[i]) #define GUINT16_FROM_LE(val) ( (unsigned short) ( IDX(val, 0) + IDX(val, 1) * 256 )) #define GUINT32_FROM_LE(val) ( (int) (IDX(val, 0) + IDX(val, 1) * 256 + \ IDX(val, 2) * 65536 + IDX(val, 3) * 16777216)) #define GUINT16_TO_LE(val) ( (unsigned short) (\ (((unsigned short)val % 256) & 0xff) << 8 | \ ((((unsigned short)val / POW_2_8) % 256) & 0xff) )) #define GUINT32_TO_LE(val) ( (int) (\ ((((unsigned int) val ) % 256) & 0xff) << 24 | \ ((((unsigned int) val / POW_2_8 ) % 256) & 0xff) << 16| \ ((((unsigned int) val / POW_2_16) % 256) & 0xff) << 8 | \ ((((unsigned int) val / POW_2_24) % 256) & 0xff) )) #else #define GUINT16_TO_LE(val) ( (unsigned short) (val)) #define GUINT32_TO_LE(val) ( (unsigned int) (val)) #define GUINT16_FROM_LE(val) ( (unsigned short) (val)) #define GUINT32_FROM_LE(val) ( (unsigned int) (val)) #endif #undef g_new #undef g_new0 #undef g_free #undef g_realloc #define g_new(struct_type, n_structs) \ ((struct_type *) malloc (sizeof (struct_type) * n_structs)) #define g_new0(struct_type, n_structs) \ ((struct_type *) memset(malloc (sizeof (struct_type) * n_structs), 0, sizeof (struct_type) * n_structs)) #define g_free free #endif #endif amsn-0.98.9/utils/webcamsn/src/vlc_encode.c0000644000175000017500000000504310225230720020357 0ustar billiobbilliob/* Copyright (C) 2005 Ole André Vadla Ravnås * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "mimic-private.h" extern guchar _col_zag[64]; extern VlcSymbol _vlc_alphabet[16][128]; /* * _vlc_encode_block * * Serialize an 8x8 block using variable length coding. */ void _vlc_encode_block(MimCtx *ctx, const gint *block, gint num_coeffs) { gint i, num_zeroes; /* The DC value is written out as is. */ _write_bits(ctx, block[0], 8); /* Number of zeroes prefixing the next non-zero value. */ num_zeroes = 0; for (i = 1; i < num_coeffs && num_zeroes <= 14; i++) { /* Fetch AC coefficients from block in zig-zag order. */ gint value = block[_col_zag[i]]; if (value != 0) { VlcSymbol sym; /* Clip input values to [-128, +128]. */ if (value < -128) value = -128; else if (value > 128) value = 128; /* Look up symbol for the current non-zero value. */ sym = _vlc_alphabet[num_zeroes][abs(value) - 1]; /* No symbol? very rare... */ if (sym.length1 <= 0) break; /* The symbols for negative values are the same as for positives, minus one. */ if (value < 0) { if (sym.length2 > 0) sym.part2 -= 1; else sym.part1 -= 1; } /* Write out the full symbol. */ _write_bits(ctx, sym.part1, sym.length1); if (sym.length2 > 0) _write_bits(ctx, sym.part2, sym.length2); /* Start counting zeroes again. */ num_zeroes = 0; } else { num_zeroes++; } } /* Write out EOB if necessary. */ if (num_zeroes > 0) _write_bits(ctx, 0xA, 4); } amsn-0.98.9/utils/webcamsn/src/webcamsn.c0000644000175000017500000004477311234130207020072 0ustar billiobbilliob/* File : Webcamsn.c Description : Contains all functions for the Webcamsn extension Author : Youness El Alaoui (KaKaRoTo - kakaroto@users.sourceforge.net) */ // Include the header file #include "webcamsn.h" #include "kidhash.h" static int encoder_counter = 0; static int decoder_counter = 0; static Tcl_HashTable *Codecs = NULL; BYTE * RGBA2RGB(Tk_PhotoImageBlock data) { int i; int size = data.height * data.width * data.pixelSize; BYTE * FrameData = (BYTE *) malloc(data.height * data.width * 3); BYTE * pixelPtr = FrameData; for (i = 0; i < size; i+= data.pixelSize) { *(pixelPtr++) = *(data.pixelPtr + i + data.offset[0]); *(pixelPtr++) = *(data.pixelPtr + i + data.offset[1]); *(pixelPtr++) = *(data.pixelPtr + i + data.offset[2]); } return FrameData; } int Webcamsn_NewDecoder _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { CodecInfo *new_decoder; char name[30]; char *req_name = NULL; Tcl_HashEntry *hPtr = NULL; int newHash; // We verify the arguments if( objc > 2) { Tcl_AppendResult (interp, "Wrong number of args.\nShould be \"::Webcamsn::NewDecoder ?name?\"" , (char *) NULL); return TCL_ERROR; } new_decoder = (struct CodecInfo *) malloc(sizeof(struct CodecInfo)); if ( objc == 2) { // Set the requested name and see if it exists... req_name = Tcl_GetStringFromObj(objv[1], NULL); if (Tcl_FindHashEntry(Codecs, req_name) == NULL) { strcpy(name, req_name ); }else { sprintf(name, "decoder%d", ++decoder_counter); } } else { sprintf(name, "decoder%d", ++decoder_counter); } new_decoder->codec = mimic_open(); strcpy(new_decoder->name, name); new_decoder->type = DECODER_UNINITIALIZED; new_decoder->frames = 0; hPtr = Tcl_CreateHashEntry(Codecs, name, &newHash); Tcl_SetHashValue(hPtr, (ClientData) new_decoder); Tcl_ResetResult(interp); Tcl_AppendResult(interp, name, NULL); return TCL_OK; } int Webcamsn_NewEncoder _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { CodecInfo *new_encoder; MimCtx * encoder = NULL; char name[15]; char * req_name = NULL; char * strResolution = NULL; MimicResEnum resolution; Tcl_HashEntry *hPtr = NULL; int newHash; // We verify the arguments if( objc < 2 || objc > 3) { Tcl_AppendResult (interp, "Wrong number of args.\nShould be \"::Webcamsn::NewEncoder resolution ?name?\" " , "where the resolution is either \"LOW\" or \"HIGH\"", (char *) NULL); return TCL_ERROR; } strResolution = Tcl_GetStringFromObj(objv[1], NULL); if (!strcmp(strResolution, "LOW")) { resolution = MIMIC_RES_LOW; } else if (!strcmp(strResolution, "HIGH")) { resolution = MIMIC_RES_HIGH; } else { Tcl_ResetResult(interp); Tcl_AppendResult (interp, "Invalid resolution. The resolution is either \"LOW\" or \"HIGH\"", (char *) NULL); return TCL_ERROR; } new_encoder = (struct CodecInfo *) malloc(sizeof(struct CodecInfo)); if ( objc == 3) { // Set the requested name and see if it exists... req_name = Tcl_GetStringFromObj(objv[2], NULL); if (Tcl_FindHashEntry(Codecs, req_name) == NULL) { strcpy(name, req_name); }else { sprintf(name, "encoder%d", ++encoder_counter); } } else { sprintf(name, "encoder%d", ++encoder_counter); } new_encoder->codec = mimic_open(); strcpy(new_encoder->name, name); new_encoder->type = ENCODER; new_encoder->frames = 0; mimic_encoder_init(new_encoder->codec, resolution); hPtr = Tcl_CreateHashEntry(Codecs, name, &newHash); Tcl_SetHashValue(hPtr, (ClientData) new_encoder); Tcl_ResetResult(interp); Tcl_AppendResult(interp, name, NULL); return TCL_OK; } int Webcamsn_Decode _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { char * name = NULL; CodecInfo * decoder; char * image_name = NULL; Tk_PhotoHandle Photo; Tk_PhotoImageBlock block; MimicHeader *header; BYTE * buffer = NULL; BYTE * FrameData = NULL; BYTE * output = NULL; Tcl_HashEntry *hPtr = NULL; int length = 0; int width = 0; int height = 0; // We verify the arguments if( objc != 4) { Tcl_AppendResult (interp, "Wrong number of args.\nShould be \"::Webcamsn::Decode decoder to_image data\"" , (char *) NULL); return TCL_ERROR; } name = Tcl_GetStringFromObj(objv[1], NULL); hPtr = Tcl_FindHashEntry(Codecs, name); if (hPtr != NULL) { decoder = (CodecInfo *) Tcl_GetHashValue(hPtr); } if (!decoder) { Tcl_AppendResult (interp, "Invalid decoder : " , name, (char *) NULL); return TCL_ERROR; } if (decoder->type == ENCODER) { Tcl_AppendResult (interp, name, " is an encoder, not a decoder" , (char *) NULL); return TCL_ERROR; } image_name = Tcl_GetStringFromObj(objv[2], NULL); if ( (Photo = Tk_FindPhoto(interp, image_name)) == NULL) { Tcl_AppendResult(interp, "The image you specified is not a valid photo image", NULL); return TCL_ERROR; } buffer = Tcl_GetByteArrayFromObj(objv[3], &length); header = (MimicHeader *) buffer; header->header_size = GUINT16_FROM_LE(header->header_size); header->fourcc = GUINT32_FROM_LE(header->fourcc); header->payload_size = GUINT32_FROM_LE(header->payload_size); if (!(header->header_size == 24 && header->fourcc == 0x30324C4D && length >= (header->header_size + header->payload_size))) { Tcl_AppendResult(interp, "Wrong format or not enough data", NULL); return TCL_ERROR; } FrameData = buffer + header->header_size; if (decoder->type == DECODER_UNINITIALIZED) { if (!mimic_decoder_init(decoder->codec, FrameData)) { Tcl_AppendResult(interp, "Unable to initialize the decoder, the data you supplied is not valid", (char *) NULL); return TCL_ERROR; } else { decoder->type = DECODER_INITIALIZED; } } mimic_get_property(decoder->codec, "buffer_size", &length); mimic_get_property(decoder->codec, "width", &width); mimic_get_property(decoder->codec, "height", &height); output = (BYTE *) malloc(length); if (mimic_decode_frame(decoder->codec, FrameData, output)) { decoder->frames++; Tk_PhotoSetSize( #if TK_MINOR_VERSION >= 5 interp, #endif Photo, width, height); block.pixelPtr = output; // pixel ptr block.width = width; block.height = height; block.pitch = width*3; block.pixelSize = 3; block.offset[0] = 0; block.offset[1] = 1; block.offset[2] = 2; block.offset[3] = -1; Tk_PhotoPutBlock( #if TK_MINOR_VERSION >= 5 interp, #endif Photo, &block, 0, 0, width, height #if TK_MINOR_VERSION > 3 ,TK_PHOTO_COMPOSITE_OVERLAY #endif ); free(output); return TCL_OK; } else { Tcl_AppendResult(interp, "Unable to decode current frame, the data you supplied is not valid", (char *) NULL); return TCL_ERROR; } } int Webcamsn_Encode _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { char * name = NULL; CodecInfo * encoder; char * image_name = NULL; Tk_PhotoHandle Photo; Tk_PhotoImageBlock photoData; BYTE * buffer = NULL; BYTE * FrameData = NULL; BYTE * output = NULL; Tcl_HashEntry *hPtr = NULL; int length = 0; int width = 0; int height = 0; // We verify the arguments if( objc != 3) { Tcl_AppendResult (interp, "Wrong number of args.\nShould be \"::Webcamsn::Encode encoder from_image\"" , (char *) NULL); return TCL_ERROR; } name = Tcl_GetStringFromObj(objv[1], NULL); hPtr = Tcl_FindHashEntry(Codecs, name); if (hPtr != NULL) { encoder = (CodecInfo *) Tcl_GetHashValue(hPtr); } if (!encoder) { Tcl_AppendResult (interp, "Invalid encoder : " , name, (char *) NULL); return TCL_ERROR; } if (encoder->type != ENCODER) { Tcl_AppendResult (interp, name, " is a decoder, not an encoder" , (char *) NULL); return TCL_ERROR; } image_name = Tcl_GetStringFromObj(objv[2], NULL); if ( (Photo = Tk_FindPhoto(interp, image_name)) == NULL) { Tcl_AppendResult(interp, "The image you specified is not a valid photo image", NULL); return TCL_ERROR; } Tk_PhotoGetImage(Photo, &photoData); mimic_get_property(encoder->codec, "buffer_size", &length); mimic_get_property(encoder->codec, "width", &width); mimic_get_property(encoder->codec, "height", &height); output = (BYTE *) malloc(length*5); FrameData = RGBA2RGB(photoData); if (mimic_encode_frame(encoder->codec, FrameData, output, &length, ((encoder->frames % MAX_INTERFRAMES) == 0? TRUE : FALSE) )) { encoder->frames++; Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(output, length)); free(output); free(FrameData); return TCL_OK; } else { free(output); free(FrameData); Tcl_AppendResult(interp, "Unable to encode the image", (char *) NULL); return TCL_ERROR; } } int Webcamsn_SetQuality _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { int quality = 0; char * name = NULL; CodecInfo * encoder; Tcl_HashEntry *hPtr = NULL; // We verify the arguments if( objc != 3) { Tcl_AppendResult (interp, "Wrong number of args.\nShould be \"::Webcamsn::SetQuality encoder quality\"" , (char *) NULL); return TCL_ERROR; } name = Tcl_GetStringFromObj(objv[1], NULL); hPtr = Tcl_FindHashEntry(Codecs, name); if (hPtr != NULL) { encoder = (CodecInfo *) Tcl_GetHashValue(hPtr); } if (!encoder) { Tcl_AppendResult (interp, "Invalid encoder : " , name, (char *) NULL); return TCL_ERROR; } if (encoder->type != ENCODER) { Tcl_AppendResult (interp, name, " is a decoder, not an encoder" , (char *) NULL); return TCL_ERROR; } if( Tcl_GetIntFromObj(interp, objv[2], &quality) == TCL_ERROR) return TCL_ERROR; if (mimic_set_property(encoder->codec, "quality", &quality)) { return TCL_OK; } else { Tcl_AppendResult(interp, "unable to change quality of encoder : ", name, (char *) NULL); return TCL_ERROR; } } int Webcamsn_GetWidth _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { int width = 0; char * name = NULL; CodecInfo * codec; Tcl_HashEntry *hPtr = NULL; // We verify the arguments if( objc != 2) { Tcl_AppendResult (interp, "Wrong number of args.\nShould be \"::Webcamsn::GetWidth codec\"" , (char *) NULL); return TCL_ERROR; } name = Tcl_GetStringFromObj(objv[1], NULL); hPtr = Tcl_FindHashEntry(Codecs, name); if (hPtr != NULL) { codec = (CodecInfo *) Tcl_GetHashValue(hPtr); } if (!codec) { Tcl_AppendResult (interp, "Invalid encoder/decoder : " , name, (char *) NULL); return TCL_ERROR; } if(codec->type == DECODER_UNINITIALIZED) { Tcl_AppendResult (interp, "Before requesting this data, the decoder must have been initialized ", "with at least one chunk of data" , (char *) NULL); return TCL_ERROR; } if (mimic_get_property(codec->codec, "width", &width)) { Tcl_SetObjResult(interp, Tcl_NewIntObj(width)); return TCL_OK; } else { Tcl_AppendResult(interp, "unable to get width for codec : ", name, (char *) NULL); return TCL_ERROR; } } int Webcamsn_GetHeight _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { int height = 0; char * name = NULL; CodecInfo * codec; Tcl_HashEntry *hPtr = NULL; // We verify the arguments if( objc != 2) { Tcl_AppendResult (interp, "Wrong number of args.\nShould be \"::Webcamsn::GetHeight codec\"" , (char *) NULL); return TCL_ERROR; } name = Tcl_GetStringFromObj(objv[1], NULL); hPtr = Tcl_FindHashEntry(Codecs, name); if (hPtr != NULL) { codec = (CodecInfo *) Tcl_GetHashValue(hPtr); } if (!codec) { Tcl_AppendResult (interp, "Invalid encoder/decoder : " , name, (char *) NULL); return TCL_ERROR; } if(codec->type == DECODER_UNINITIALIZED) { Tcl_AppendResult (interp, "Before requesting this data, the decoder must have been initialized ", "with at least one chunk of data" , (char *) NULL); return TCL_ERROR; } if (mimic_get_property(codec->codec, "height", &height)) { Tcl_SetObjResult(interp, Tcl_NewIntObj(height)); return TCL_OK; } else { Tcl_AppendResult(interp, "unable to get height for codec : ", name, (char *) NULL); return TCL_ERROR; } return TCL_OK; } int Webcamsn_GetQuality _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { int quality = 0; char * name = NULL; CodecInfo * codec; Tcl_HashEntry *hPtr = NULL; // We verify the arguments if( objc != 2) { Tcl_AppendResult (interp, "Wrong number of args.\nShould be \"::Webcamsn::GetQuality codec\"" , (char *) NULL); return TCL_ERROR; } name = Tcl_GetStringFromObj(objv[1], NULL); hPtr = Tcl_FindHashEntry(Codecs, name); if (hPtr != NULL) { codec = (CodecInfo *) Tcl_GetHashValue(hPtr); } if (!codec) { Tcl_AppendResult (interp, "Invalid encoder/decoder : " , name, (char *) NULL); return TCL_ERROR; } if(codec->type == DECODER_UNINITIALIZED) { Tcl_AppendResult (interp, "Before requesting this data, the decoder must have been initialized ", "with at least one chunk of data" , (char *) NULL); return TCL_ERROR; } if (mimic_get_property(codec->codec, "quality", &quality)) { Tcl_SetObjResult(interp, Tcl_NewIntObj(quality)); return TCL_OK; } else { Tcl_AppendResult(interp, "Unable to get the quality of the codec : ", name, (char *) NULL); return TCL_ERROR; } return TCL_OK; } int Webcamsn_Close _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { char * name = NULL; CodecInfo * codec; Tcl_HashEntry *hPtr = NULL; // We verify the arguments if( objc != 2) { Tcl_AppendResult (interp, "Wrong number of args.\nShould be \"::Webcamsn::Close codec\"" , (char *) NULL); return TCL_ERROR; } name = Tcl_GetStringFromObj(objv[1], NULL); hPtr = Tcl_FindHashEntry(Codecs, name); if (hPtr != NULL) { codec = (CodecInfo *) Tcl_GetHashValue(hPtr); } if (!codec) { Tcl_AppendResult (interp, "Invalid encoder/decoder : " , name, (char *) NULL); return TCL_ERROR; } mimic_close(codec->codec); Tcl_DeleteHashEntry(hPtr); free(codec); return TCL_OK; } int Webcamsn_Count _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { Tcl_HashSearch searchPtr; Tcl_HashEntry *hPtr = NULL; int count = 0; for (hPtr = Tcl_FirstHashEntry(Codecs, &searchPtr); hPtr; hPtr = Tcl_NextHashEntry(&searchPtr)) { count++; } Tcl_SetObjResult(interp, Tcl_NewIntObj(count)); return TCL_OK; } int Webcamsn_Frames _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { char * name = NULL; CodecInfo * codec; Tcl_HashEntry *hPtr = NULL; // We verify the arguments if( objc != 2) { Tcl_AppendResult (interp, "Wrong number of args.\nShould be \"::Webcamsn::NbFrames codec\"" , (char *) NULL); return TCL_ERROR; } name = Tcl_GetStringFromObj(objv[1], NULL); hPtr = Tcl_FindHashEntry(Codecs, name); if (hPtr != NULL) { codec = (CodecInfo *) Tcl_GetHashValue(hPtr); } if (!codec) { Tcl_AppendResult (interp, "Invalid encoder/decoder : " , name, (char *) NULL); return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewIntObj((int) codec->frames)); return TCL_OK; } int Webcamsn_KidHash _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { char * sid = NULL; char * key = NULL; int kid; char a[30]; int a_size = 30; // We verify the arguments if( objc != 3) { Tcl_AppendResult (interp, "Wrong number of args.\nShould be " "\"::Webcamsn::CreateHashFromKid kid sid\"" , (char *) NULL); return TCL_ERROR; } Tcl_GetIntFromObj(interp, objv[1], &kid); sid = Tcl_GetStringFromObj(objv[2], NULL); key = (char *) malloc (strlen(sid) + 10); sprintf(key, "sid=%s", sid); if (MakeKidHash(a, &a_size, kid, key)) { Tcl_ResetResult(interp); Tcl_AppendResult (interp, a, (char *) NULL); free(key); return TCL_OK; } else { Tcl_ResetResult(interp); free(key); return TCL_OK; } } /* Function : Webcamsn_Init Description : The Init function that will be called when the extension is loaded to your tk shell Arguments : Tcl_Interp *interp : This is the interpreter from which the load was made and to which we'll add the new command Return value : TCL_OK in case everything is ok, or TCL_ERROR in case there is an error (Tk version < 8.3) Comments : hummmm... not much, it's simple :) */ int Webcamsn_Init (Tcl_Interp *interp ) { //Check Tcl version is 8.3 or higher if (Tcl_InitStubs(interp, TCL_VERSION, 1) == NULL) { return TCL_ERROR; } //Check TK version is 8.3 or higher if (Tk_InitStubs(interp, TK_VERSION, 1) == NULL) { return TCL_ERROR; } Codecs = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable)); Tcl_InitHashTable(Codecs, TCL_STRING_KEYS); // Create the wrapping commands in the Webcamsn namespace linked to custom functions with a NULL clientdata and // no deleteproc inside the current interpreter Tcl_CreateObjCommand(interp, "::Webcamsn::NewEncoder", Webcamsn_NewEncoder, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Webcamsn::NewDecoder", Webcamsn_NewDecoder, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Webcamsn::Decode", Webcamsn_Decode, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Webcamsn::Encode", Webcamsn_Encode, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Webcamsn::SetQuality", Webcamsn_SetQuality, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Webcamsn::GetWidth", Webcamsn_GetWidth, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Webcamsn::GetHeight", Webcamsn_GetHeight, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Webcamsn::GetQuality", Webcamsn_GetQuality, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Webcamsn::Close", Webcamsn_Close, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Webcamsn::NumberOfOpenCodecs", Webcamsn_Count, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Webcamsn::NbFrames", Webcamsn_Frames, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "::Webcamsn::CreateHashFromKid", Webcamsn_KidHash, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); // end of Initialisation return TCL_OK; } int Webcamsn_SafeInit (Tcl_Interp *interp) { return Webcamsn_Init(interp); } amsn-0.98.9/utils/webcamsn/src/mimic.c0000644000175000017500000002125010225230720017352 0ustar billiobbilliob/* Copyright (C) 2005 Ole André Vadla Ravnås * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "mimic-private.h" /** * Creates a new instance and returns a pointer to the new context * that can be used for either encoding or decoding by calling * #mimic_encoder_init or #mimic_decoder_init. * * #mimic_close is called to free any resources associated with * the context once done. * * @returns a new mimic context */ MimCtx *mimic_open() { MimCtx *ctx; ctx = g_new0(MimCtx, 1); ctx->encoder_initialized = FALSE; ctx->decoder_initialized = FALSE; return ctx; } /** * Frees any resources associated with the given context. * * @param ctx the mimic context to free */ void mimic_close(MimCtx *ctx) { if (ctx->encoder_initialized || ctx->decoder_initialized) { gint i; g_free(ctx->cur_frame_buf); for (i = 0; i < 16; i++) g_free(ctx->buf_ptrs[i]); } g_free(ctx); } /* * mimic_init * * Internal helper-function used to initialize * a given context. */ static void mimic_init(MimCtx *ctx, gint width, gint height) { gint bufsize, i; /* * Dimensions-related. */ ctx->frame_width = width; ctx->frame_height = height; ctx->y_stride = ctx->frame_width; ctx->y_row_count = ctx->frame_height; ctx->y_size = ctx->y_stride * ctx->y_row_count; ctx->crcb_stride = ctx->y_stride / 2; ctx->crcb_row_count = ctx->y_row_count / 2; ctx->crcb_size = ctx->crcb_stride * ctx->crcb_row_count; ctx->num_vblocks_y = ctx->frame_height / 8; ctx->num_hblocks_y = ctx->frame_width / 8; ctx->num_vblocks_cbcr = ctx->frame_height / 16; ctx->num_hblocks_cbcr = ctx->frame_width / 16; if (ctx->frame_height % 16 != 0) ctx->num_vblocks_cbcr++; /* * Initialize state. */ ctx->frame_num = 0; ctx->ptr_index = 15; ctx->num_coeffs = 28; /* * Allocate memory for buffers. */ ctx->cur_frame_buf = g_new(guchar, (320 * 240 * 3) / 2); bufsize = ctx->y_size + (ctx->crcb_size * 2); for (i = 0; i < 16; i++) ctx->buf_ptrs[i] = g_new(guchar, bufsize); /* * Initialize vlc lookup used by decoder. */ _initialize_vlcdec_lookup(ctx->vlcdec_lookup); } /** * Initialize the mimic encoder and prepare for encoding by * initializing internal state and allocating resources as * needed. * * After initializing use #mimic_get_property to determine * the size of the output buffer needed for calls to * #mimic_encode_frame. Use #mimic_set_property to set * encoding quality. * * Note that once a given context has been initialized * for either encoding or decoding it is not possible * to initialize it again. * * @param ctx the mimic context to initialize * @param resolution a #MimicResEnum used to specify the resolution * @returns #TRUE on success */ gboolean mimic_encoder_init(MimCtx *ctx, const MimicResEnum resolution) { gint width, height; /* Check if we've been initialized before. */ if (ctx->encoder_initialized || ctx->decoder_initialized) return FALSE; /* Check resolution. */ if (resolution == MIMIC_RES_LOW) { width = 160; height = 120; } else if (resolution == MIMIC_RES_HIGH) { width = 320; height = 240; } else { return FALSE; } /* Initialize! */ mimic_init(ctx, width, height); /* Set a default quality setting. */ ctx->quality = MIMIC_ENCODER_DEFAULT_QUALITY; ctx->encoder_initialized = TRUE; return TRUE; } /** * Initialize the mimic decoder. The frame passed in frame_buffer * is used to determine the resolution so that the internal state * can be prepared and resources allocated accordingly. Note that * the frame passed has to be a keyframe. * * After initializing use #mimic_get_property to determine required * buffer-size, resolution, quality, etc. * * Note that once a given context has been initialized * for either encoding or decoding it is not possible * to initialize it again. * * @param ctx the mimic context to initialize * @param frame_buffer buffer containing the first frame to decode * @returns #TRUE on success */ gboolean mimic_decoder_init(MimCtx *ctx, const guchar *frame_buffer) { gint width, height; gboolean is_keyframe; /* Check if we've been initialized before and that * frame_buffer is not NULL. */ if (ctx->encoder_initialized || ctx->decoder_initialized || frame_buffer == NULL) { return FALSE; } /* Check resolution. */ width = GUINT16_FROM_LE(*((guint16 *) (frame_buffer + 4))); height = GUINT16_FROM_LE(*((guint16 *) (frame_buffer + 6))); if (!(width == 160 && height == 120) && !(width == 320 && height == 240)) return FALSE; /* Check that we're initialized with a keyframe. */ is_keyframe = (GUINT32_FROM_LE(*((guint32 *) (frame_buffer + 12))) == 0); if (!is_keyframe) return FALSE; /* Get quality setting (in case we get queried for it before decoding). */ ctx->quality = GUINT16_FROM_LE(*((guint16 *) (frame_buffer + 2))); /* Initialize! */ mimic_init(ctx, width, height); ctx->decoder_initialized = TRUE; return TRUE; } /** * Get a property from a given mimic context. The context * has to be initialized. * * Currently the following properties are defined: * - "buffer_size" * - Required output buffer size * - "width" * - Frame width * - "height" * - Frame height * - "quality" * - Encoder: Encoding quality used * - Decoder: Decoding quality of the last known frame * * @param ctx the mimic context to retrieve the property from * @param name of the property to retrieve the current value of * @param data pointer to the data that will receive the retrieved value * @returns #TRUE on success */ gboolean mimic_get_property(MimCtx *ctx, const gchar *name, gpointer data) { /* Either the encoder or the decoder has to be initialized. */ if (!ctx->encoder_initialized && !ctx->decoder_initialized) return FALSE; if (ctx->encoder_initialized) { if (strcmp(name, "buffer_size") == 0) { *((gint *) data) = (ctx->frame_width == 160) ? 3840 : 7680; return TRUE; } } else { /* decoder_initialized */ if (strcmp(name, "buffer_size") == 0) { *((gint *) data) = ctx->frame_width * ctx->frame_height * 3; return TRUE; } } if (strcmp(name, "width") == 0) { *((gint *) data) = ctx->frame_width; return TRUE; } else if (strcmp(name, "height") == 0) { *((gint *) data) = ctx->frame_height; return TRUE; } else if (strcmp(name, "quality") == 0) { *((gint *) data) = ctx->quality; return TRUE; } return FALSE; } /** * Set a property in a given mimic context. The context * has to be initialized. * * Currently the following properties are defined: * - "quality" * - Encoding quality used by encoder. * * @param ctx the mimic context to set a property in * @param name of the property to set to a new value * @param data pointer to the data that contains the new value * @returns #TRUE on success */ gboolean mimic_set_property(MimCtx *ctx, const gchar *name, gpointer data) { /* Either the encoder or the decoder has to be initialized. */ if (!ctx->encoder_initialized && !ctx->decoder_initialized) return FALSE; if (ctx->encoder_initialized) { if (strcmp(name, "quality") == 0) { ctx->quality = *((gint *) data); return TRUE; } } else { /* decoder_initialized */ } return FALSE; } /* * _clamp_value * * Internal helper-function used to clamp a given * value to the range [ 0, 255 ]. */ guchar _clamp_value(gint value) { if (value < 0) return 0; else if (value > 255) return 255; else return value; } amsn-0.98.9/utils/webcamsn/ChangeLog0000644000175000017500000000000010225230720017061 0ustar billiobbilliobamsn-0.98.9/utils/webcamsn/INSTALL0000644000175000017500000002203010225230720016347 0ustar billiobbilliobCopyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is free documentation; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. (Caching is disabled by default to prevent problems with accidental use of stale cache files.) If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You only need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not support the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=PATH' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the `--target=TYPE' option to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc will cause the specified gcc to be used as the C compiler (unless it is overridden in the site shell script). `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of the options to `configure', and exit. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. amsn-0.98.9/utils/webcamsn/doc/0000755000175000017500000000000011757711632016107 5ustar billiobbilliobamsn-0.98.9/utils/webcamsn/doc/Makefile.am0000644000175000017500000000020010225236340020116 0ustar billiobbilliobEXTRA_DIST = Doxyfile.in if LIBMIMIC_DOXYGEN_DOCS_ENABLED all-local: dox dox: Doxyfile -rm -rf api/ doxygen Doxyfile endif amsn-0.98.9/utils/webcamsn/doc/Doxyfile.in0000644000175000017500000002012710225236340020207 0ustar billiobbilliob# Doxyfile 1.4.0 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = libmimic PROJECT_NUMBER = @VERSION@ OUTPUT_DIRECTORY = api CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English USE_WINDOWS_ENCODING = NO BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = YES STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = NO INHERIT_DOCS = YES DISTRIBUTE_GROUP_DOC = NO TAB_SIZE = 8 ALIASES = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = NO EXTRACT_PRIVATE = NO EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = NO SORT_BRIEF_DOCS = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_DIRECTORIES = YES FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = ../src FILE_PATTERNS = *.c *.h RECURSIVE = YES EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXAMPLE_PATH = EXAMPLE_PATTERNS = EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = NO INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = YES REFERENCES_RELATION = YES VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = YES LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = NO USE_PDFLATEX = NO LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = MAX_DOT_GRAPH_WIDTH = 1024 MAX_DOT_GRAPH_HEIGHT = 1024 MAX_DOT_GRAPH_DEPTH = 0 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO amsn-0.98.9/utils/webcamsn/doc/Makefile.in0000644000175000017500000001410410225236340020137 0ustar billiobbilliob# Makefile.in generated by automake 1.6.3 from Makefile.am. # @configure_input@ # Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 # Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ SHELL = @SHELL@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ sbindir = @sbindir@ libexecdir = @libexecdir@ datadir = @datadir@ sysconfdir = @sysconfdir@ sharedstatedir = @sharedstatedir@ localstatedir = @localstatedir@ libdir = @libdir@ infodir = @infodir@ mandir = @mandir@ includedir = @includedir@ oldincludedir = /usr/include pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = .. ACLOCAL = @ACLOCAL@ AUTOCONF = @AUTOCONF@ AUTOMAKE = @AUTOMAKE@ AUTOHEADER = @AUTOHEADER@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_HEADER = $(INSTALL_DATA) transform = @program_transform_name@ NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : host_alias = @host_alias@ host_triplet = @host@ EXEEXT = @EXEEXT@ OBJEXT = @OBJEXT@ PATH_SEPARATOR = @PATH_SEPARATOR@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AWK = @AWK@ CC = @CC@ CXX = @CXX@ CXXCPP = @CXXCPP@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOXYGEN = @DOXYGEN@ ECHO = @ECHO@ EGREP = @EGREP@ F77 = @F77@ GCJ = @GCJ@ GCJFLAGS = @GCJFLAGS@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ MAINT = @MAINT@ MIMIC_AGE = @MIMIC_AGE@ MIMIC_CURRENT = @MIMIC_CURRENT@ MIMIC_REVISION = @MIMIC_REVISION@ OBJDUMP = @OBJDUMP@ PACKAGE = @PACKAGE@ PKG_CONFIG = @PKG_CONFIG@ RANLIB = @RANLIB@ RC = @RC@ STRIP = @STRIP@ VERSION = @VERSION@ am__include = @am__include@ am__quote = @am__quote@ install_sh = @install_sh@ EXTRA_DIST = Doxyfile.in subdir = doc mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = Doxyfile DIST_SOURCES = DIST_COMMON = Doxyfile.in Makefile.am Makefile.in all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) cd $(top_srcdir) && \ $(AUTOMAKE) --gnu doc/Makefile Makefile: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.in $(top_builddir)/config.status cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) Doxyfile: $(top_builddir)/config.status Doxyfile.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool uninstall-info-am: tags: TAGS TAGS: DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) top_distdir = .. distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) distdir: $(DISTFILES) @list='$(DISTFILES)'; for file in $$list; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ $(mkinstalldirs) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ if test -d $$d/$$file; then \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile all-local installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -rm -f Makefile $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am distclean-am: clean-am distclean-generic distclean-libtool dvi: dvi-am dvi-am: info: info-am info-am: install-data-am: install-exec-am: install-info: install-info-am install-man: installcheck-am: maintainer-clean: maintainer-clean-am maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool uninstall-am: uninstall-info-am .PHONY: all all-am all-local check check-am clean clean-generic \ clean-libtool distclean distclean-generic distclean-libtool \ distdir dvi dvi-am info info-am install install-am install-data \ install-data-am install-exec install-exec-am install-info \ install-info-am install-man install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool uninstall uninstall-am uninstall-info-am @LIBMIMIC_DOXYGEN_DOCS_ENABLED_TRUE@all-local: dox @LIBMIMIC_DOXYGEN_DOCS_ENABLED_TRUE@dox: Doxyfile @LIBMIMIC_DOXYGEN_DOCS_ENABLED_TRUE@ -rm -rf api/ @LIBMIMIC_DOXYGEN_DOCS_ENABLED_TRUE@ doxygen Doxyfile # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: amsn-0.98.9/utils/webcamsn/AUTHORS0000644000175000017500000000005510225230720016371 0ustar billiobbilliobOle André Vadla Ravnås amsn-0.98.9/utils/webcamsn/webcamsn.tcl0000644000175000017500000001464210630227077017646 0ustar billiobbilliob#!/usr/bin/wish proc GetDataSize { data } { binary scan $data ssssiiii h_size w h r1 p_size fcc r2 r3 binary scan "\x30\x32\x4C\x4D" I r_fcc if { [string length $data] < 24 } { return 0 } if { $h_size != 24 } { puts "invalid - $h_size" return -1 } if { $fcc != $r_fcc} { puts "fcc invalide - $fcc - $r_fcc" return -1 } #puts "resolution : $w x $h - $h_size $p_size - frame : $::frame - data size : [string length $data]" if { $::frame == 271 } { set fd [open khra w] fconfigure $fd -encoding binary -translation binary puts $fd $data close $fd } return [expr $h_size + $p_size] } proc DecodeFile { filename } { if { ![file readable $filename] } { error "Can't find the specified file" } set debug [open debug.log w] fconfigure $debug -buffering none puts $debug "Start :\n" set fd [open $filename] fconfigure $fd -encoding binary -translation binary set data [read $fd] close $fd puts $debug "Creating widgets :\n" set img [image create photo] catch {destroy .webcam} toplevel .webcam label .webcam.l -image $img pack .webcam.l set ::sem 0 set ::frame 0 puts $debug "Creating decoder" set decoder [::Webcamsn::NewDecoder] puts $debug "$decoder - [::Webcamsn::NumberOfOpenCodecs]" while { [set size [GetDataSize $data] ] > 0 } { puts $debug "decoding frame [::Webcamsn::NbFrames $decoder]" if { ![winfo exists .webcam] } { break } ::Webcamsn::Decode $decoder $img $data set data [string range $data $size end] after 100 "incr ::sem" tkwait variable ::sem incr ::frame } puts $debug "$decoder - [::Webcamsn::NumberOfOpenCodecs]" ::Webcamsn::Close $decoder puts $debug "$decoder - [::Webcamsn::NumberOfOpenCodecs]" } proc Switch { cmd1 time1 cmd2 time2 } { eval $cmd1 after $time1 "Switch $cmd2 $time2 $cmd1 $time1" } proc EncodeToFile { filename } { if { $::tkcx == 0 } { error "Unable to find TkCximage" } if { $::file_to_test == "" || ![file readable $::file_to_test] } { error "Can't find movie2.gif" } set debug [open debug.log w] fconfigure $debug -buffering none puts $debug "Start :\n" set fd [open $filename w] fconfigure $fd -encoding binary -translation binary -buffering none puts $debug "Creating widgets :\n" set img [image create photo -file $::file_to_test] #Switch ::CxImage::DisableAnimated 1000 ::CxImage::EnableAnimated 1000 catch {destroy .webcam} toplevel .webcam label .webcam.l -image $img pack .webcam.l set ::sem 0 set ::frame 0 puts $debug "creating encoder" set encoder [::Webcamsn::NewEncoder LOW] puts $debug "$encoder - [::Webcamsn::NumberOfOpenCodecs]" for {set i 0 } { $i < 1000 } { incr i} { if { ![winfo exists .webcam] } { break } puts $debug "encoding frame [::Webcamsn::NbFrames $encoder]" if { [catch {set data [::Webcamsn::Encode $encoder $img]} res] } { puts $debug "ERROR : $res\n" } else { set header "[binary format ssssi 24 160 120 0 [string length $data]]" set header "$header\x4D\x4C\x32\x30\x00\x00\x00\x00\x00\x00\x00\x00" puts -nonewline $fd $header puts -nonewline $fd $data } after 10 "incr ::sem" tkwait variable ::sem incr ::frame } close $fd puts $debug "$encoder - [::Webcamsn::NumberOfOpenCodecs]" ::Webcamsn::Close $encoder puts $debug "$encoder - [::Webcamsn::NumberOfOpenCodecs]" } proc EncodeFromWebcam { filename } { if { $::qttcl == 0 } { error "unable to find QuickTimeTcl AND tkvideo AND capture" } set debug [open debug.log w] fconfigure $debug -buffering none puts $debug "Start :\n" set fd [open $filename w] fconfigure $fd -encoding binary -translation binary -buffering none puts $debug "Creating widgets and sequencer :\n" catch {destroy .webcam} toplevel .webcam seqgrabber .webcam.seq -width 160 pack .webcam.seq set img [image create photo] #If you want to see the pictures you shot, uncomment the 2 next lines # label .webcam.l -image $img # pack .webcam.l set ::sem 0 set ::frame 0 puts $debug "Creating encoder" set encoder [::Webcamsn::NewEncoder LOW] puts $debug "$encoder - [::Webcamsn::NumberOfOpenCodecs]" for {set i 0 } { $i < 1000 } { incr i} { if { ![winfo exists .webcam] } { break } puts $debug "encoding frame [::Webcamsn::NbFrames $encoder]" if {![catch {tk windowingsystem} wsystem] && $wsystem == "aqua"} { .webcam.seq image shot $img #shot .webcam.seq $img } else { .webcam.seq picture $img } if { [catch {set data [::Webcamsn::Encode $encoder $img]} res] } { puts $debug "ERROR : $res\n" } else { set header "[binary format ssssi 24 160 120 0 [string length $data]]" set header "$header\x4D\x4C\x32\x30\x00\x00\x00\x00\x00\x00\x00\x00" puts -nonewline $fd $header puts -nonewline $fd $data } after 10 "incr ::sem" tkwait variable ::sem incr ::frame } close $fd puts $debug "$encoder - [::Webcamsn::NumberOfOpenCodecs]" ::Webcamsn::Close $encoder puts $debug "$encoder - [::Webcamsn::NumberOfOpenCodecs]" } proc shot {w img} { } lappend ::auto_path [pwd] lappend ::auto_path "utils/" lappend ::auto_path "utils/webcamsn" lappend ::auto_path "utils/webcamsn/src" lappend ::auto_path "utils/linux/capture" lappend ::auto_path "utils/TkCximage" lappend ::auto_path "utils/windows" if { [catch { package require webcamsn} res] } { error "Can't load Webcamsn package : $res" } set ::qttcl 1 set ::tkcx 1 set ::capture 1 set ::tkvideo 1 catch {console show} if { [catch { package require QuickTimeTcl} ] } { set ::qttcl 0 } if { [catch { package require capture} ] } { set ::capture 0 } if { [catch { package require tkvideo} ] } { set ::tkvideo 0 } if { [catch { package require TkCximage }] } { set ::tkcx 0 } if { $::qttcl == 0 && $::tkcx == 0 && $::capture == 0 && $::tkvideo == 0 } { error "You must have at least TkCximage OR QuickTimeTcl OR Capture OR Tkvideo extensions to test the application" } proc GetMovieFile { } { foreach lib [info loaded] { if { [lindex $lib 1] == "Tkcximage" } { set dir [file dirname [lindex $lib 0]] return "[file join $dir demos movie2.gif]" } } return "" } set ::file_to_test [GetMovieFile] amsn-0.98.9/utils/webcamsn/Rules.mk0000644000175000017500000000056310750446030016756 0ustar billiobbilliobOBJS-webcamsn := $(webcamsn_dir)/src/webcamsn.$(SHLIB_EXTENSION) TARGETS-webcamsn := $(webcamsn_dir)/webcamsn.$(SHLIB_EXTENSION) $(TARGETS-webcamsn): $(OBJS-webcamsn) cp $< $@ all:: $(TARGETS-webcamsn) check:: check-webcamsn check-webcamsn: wish $(webcamsn_dir)/webcamsn.tcl clean:: clean-webcamsn clean-webcamsn:: rm -f $(TARGETS-webcamsn) $(OBJS-webcamsn) amsn-0.98.9/utils/linux/0000755000175000017500000000000011757711632014702 5ustar billiobbilliobamsn-0.98.9/utils/linux/capture/0000755000175000017500000000000011757711632016345 5ustar billiobbilliobamsn-0.98.9/utils/linux/capture/libng/0000755000175000017500000000000011757711632017440 5ustar billiobbilliobamsn-0.98.9/utils/linux/capture/libng/videodev2.h0000644000175000017500000006207310574640152021502 0ustar billiobbilliob#ifndef __LINUX_VIDEODEV2_H #define __LINUX_VIDEODEV2_H /* * Video for Linux Two * * Header file for v4l or V4L2 drivers and applications, for * Linux kernels 2.2.x or 2.4.x. * * See http://www.thedirks.org/v4l2/ for API specs and other * v4l2 documentation. * * Author: Bill Dirks * Justin Schoeman * et al. */ /* * M I S C E L L A N E O U S */ /* Four-character-code (FOURCC) */ #define v4l2_fourcc(a,b,c,d)\ (((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24)) /* * E N U M S */ enum v4l2_field { V4L2_FIELD_ANY = 0, /* driver can choose from none, top, bottom, interlaced depending on whatever it thinks is approximate ... */ V4L2_FIELD_NONE = 1, /* this device has no fields ... */ V4L2_FIELD_TOP = 2, /* top field only */ V4L2_FIELD_BOTTOM = 3, /* bottom field only */ V4L2_FIELD_INTERLACED = 4, /* both fields interlaced */ V4L2_FIELD_SEQ_TB = 5, /* both fields sequential into one buffer, top-bottom order */ V4L2_FIELD_SEQ_BT = 6, /* same as above + bottom-top order */ V4L2_FIELD_ALTERNATE = 7, /* both fields alternating into separate buffers */ }; #define V4L2_FIELD_HAS_TOP(field) \ ((field) == V4L2_FIELD_TOP ||\ (field) == V4L2_FIELD_INTERLACED ||\ (field) == V4L2_FIELD_SEQ_TB ||\ (field) == V4L2_FIELD_SEQ_BT) #define V4L2_FIELD_HAS_BOTTOM(field) \ ((field) == V4L2_FIELD_BOTTOM ||\ (field) == V4L2_FIELD_INTERLACED ||\ (field) == V4L2_FIELD_SEQ_TB ||\ (field) == V4L2_FIELD_SEQ_BT) #define V4L2_FIELD_HAS_BOTH(field) \ ((field) == V4L2_FIELD_INTERLACED ||\ (field) == V4L2_FIELD_SEQ_TB ||\ (field) == V4L2_FIELD_SEQ_BT) enum v4l2_buf_type { V4L2_BUF_TYPE_VIDEO_CAPTURE = 1, V4L2_BUF_TYPE_VIDEO_OUTPUT = 2, V4L2_BUF_TYPE_VIDEO_OVERLAY = 3, V4L2_BUF_TYPE_VBI_CAPTURE = 4, V4L2_BUF_TYPE_VBI_OUTPUT = 5, V4L2_BUF_TYPE_PRIVATE = 0x80, }; enum v4l2_ctrl_type { V4L2_CTRL_TYPE_INTEGER = 1, V4L2_CTRL_TYPE_BOOLEAN = 2, V4L2_CTRL_TYPE_MENU = 3, V4L2_CTRL_TYPE_BUTTON = 4, }; enum v4l2_tuner_type { V4L2_TUNER_RADIO = 1, V4L2_TUNER_ANALOG_TV = 2, }; enum v4l2_memory { V4L2_MEMORY_MMAP = 1, V4L2_MEMORY_USERPTR = 2, V4L2_MEMORY_OVERLAY = 3, }; /* see also http://vektor.theorem.ca/graphics/ycbcr/ */ enum v4l2_colorspace { /* ITU-R 601 -- broadcast NTSC/PAL */ V4L2_COLORSPACE_SMPTE170M = 1, /* 1125-Line (US) HDTV */ V4L2_COLORSPACE_SMPTE240M = 2, /* HD and modern captures. */ V4L2_COLORSPACE_REC709 = 3, /* broken BT878 extents (601, luma range 16-253 instead of 16-235) */ V4L2_COLORSPACE_BT878 = 4, /* These should be useful. Assume 601 extents. */ V4L2_COLORSPACE_470_SYSTEM_M = 5, V4L2_COLORSPACE_470_SYSTEM_BG = 6, /* I know there will be cameras that send this. So, this is * unspecified chromaticities and full 0-255 on each of the * Y'CbCr components */ V4L2_COLORSPACE_JPEG = 7, /* For RGB colourspaces, this is probably a good start. */ V4L2_COLORSPACE_SRGB = 8, }; struct v4l2_rect { __s32 left; __s32 top; __s32 width; __s32 height; }; struct v4l2_fract { __u32 numerator; __u32 denominator; }; /* * D R I V E R C A P A B I L I T I E S */ struct v4l2_capability { __u8 driver[16]; /* i.e. "bttv" */ __u8 card[32]; /* i.e. "Hauppauge WinTV" */ __u8 bus_info[32]; /* "PCI:" + pci_dev->slot_name */ __u32 version; /* should use KERNEL_VERSION() */ __u32 capabilities; /* Device capabilities */ __u32 reserved[4]; }; /* Values for 'capabilities' field */ #define V4L2_CAP_VIDEO_CAPTURE 0x00000001 /* Is a video capture device */ #define V4L2_CAP_VIDEO_OUTPUT 0x00000002 /* Is a video output device */ #define V4L2_CAP_VIDEO_OVERLAY 0x00000004 /* Can do video overlay */ #define V4L2_CAP_VBI_CAPTURE 0x00000010 /* Is a VBI capture device */ #define V4L2_CAP_VBI_OUTPUT 0x00000020 /* Is a VBI output device */ #define V4L2_CAP_RDS_CAPTURE 0x00000100 /* RDS data capture */ #define V4L2_CAP_TUNER 0x00010000 /* Has a tuner */ #define V4L2_CAP_AUDIO 0x00020000 /* has audio support */ #define V4L2_CAP_READWRITE 0x01000000 /* read/write systemcalls */ #define V4L2_CAP_ASYNCIO 0x02000000 /* async I/O */ #define V4L2_CAP_STREAMING 0x04000000 /* streaming I/O ioctls */ /* * V I D E O I M A G E F O R M A T */ struct v4l2_pix_format { __u32 width; __u32 height; __u32 pixelformat; enum v4l2_field field; __u32 bytesperline; /* for padding, zero if unused */ __u32 sizeimage; enum v4l2_colorspace colorspace; __u32 priv; /* private data, depends on pixelformat */ }; /* Pixel format FOURCC depth Description */ #define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R','G','B','1') /* 8 RGB-3-3-2 */ #define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R','G','B','O') /* 16 RGB-5-5-5 */ #define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R','G','B','P') /* 16 RGB-5-6-5 */ #define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R','G','B','Q') /* 16 RGB-5-5-5 BE */ #define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R','G','B','R') /* 16 RGB-5-6-5 BE */ #define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B','G','R','3') /* 24 BGR-8-8-8 */ #define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R','G','B','3') /* 24 RGB-8-8-8 */ #define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B','G','R','4') /* 32 BGR-8-8-8-8 */ #define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R','G','B','4') /* 32 RGB-8-8-8-8 */ #define V4L2_PIX_FMT_GREY v4l2_fourcc('G','R','E','Y') /* 8 Greyscale */ #define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y','V','U','9') /* 9 YVU 4:1:0 */ #define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y','V','1','2') /* 12 YVU 4:2:0 */ #define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y','U','Y','V') /* 16 YUV 4:2:2 */ #define V4L2_PIX_FMT_UYVY v4l2_fourcc('U','Y','V','Y') /* 16 YUV 4:2:2 */ #define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4','2','2','P') /* 16 YVU422 planar */ #define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4','1','1','P') /* 16 YVU411 planar */ #define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y','4','1','P') /* 12 YUV 4:1:1 */ /* two planes -- one Y, one Cr + Cb interleaved */ #define V4L2_PIX_FMT_NV12 v4l2_fourcc('N','V','1','2') /* 12 Y/CbCr 4:2:0 */ #define V4L2_PIX_FMT_NV21 v4l2_fourcc('N','V','2','1') /* 12 Y/CrCb 4:2:0 */ /* The following formats are not defined in the V4L2 specification */ #define V4L2_PIX_FMT_YUV410 v4l2_fourcc('Y','U','V','9') /* 9 YUV 4:1:0 */ #define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y','U','1','2') /* 12 YUV 4:2:0 */ #define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y','Y','U','V') /* 16 YUV 4:2:2 */ #define V4L2_PIX_FMT_HI240 v4l2_fourcc('H','I','2','4') /* 8 8-bit color */ /* compressed formats */ #define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M','J','P','G') /* Motion-JPEG */ #define V4L2_PIX_FMT_JPEG v4l2_fourcc('J','P','E','G') /* JFIF JPEG */ #define V4L2_PIX_FMT_DV v4l2_fourcc('d','v','s','d') /* 1394 */ #define V4L2_PIX_FMT_MPEG v4l2_fourcc('M','P','E','G') /* MPEG */ /* Vendor-specific formats */ #define V4L2_PIX_FMT_WNVA v4l2_fourcc('W','N','V','A') /* Winnov hw compres */ #define V4L2_PIX_FMT_BA81 v4l2_fourcc('B','A','8','1') /* Bayer */ #define V4L2_PIX_FMT_S910 v4l2_fourcc('S','9','1','0') /* SN9C102 Driver Compressed Format */ /* * F O R M A T E N U M E R A T I O N */ struct v4l2_fmtdesc { __u32 index; /* Format number */ enum v4l2_buf_type type; /* buffer type */ __u32 flags; __u8 description[32]; /* Description string */ __u32 pixelformat; /* Format fourcc */ __u32 reserved[4]; }; #define V4L2_FMT_FLAG_COMPRESSED 0x0001 /* * T I M E C O D E */ struct v4l2_timecode { __u32 type; __u32 flags; __u8 frames; __u8 seconds; __u8 minutes; __u8 hours; __u8 userbits[4]; }; /* Type */ #define V4L2_TC_TYPE_24FPS 1 #define V4L2_TC_TYPE_25FPS 2 #define V4L2_TC_TYPE_30FPS 3 #define V4L2_TC_TYPE_50FPS 4 #define V4L2_TC_TYPE_60FPS 5 /* Flags */ #define V4L2_TC_FLAG_DROPFRAME 0x0001 /* "drop-frame" mode */ #define V4L2_TC_FLAG_COLORFRAME 0x0002 #define V4L2_TC_USERBITS_field 0x000C #define V4L2_TC_USERBITS_USERDEFINED 0x0000 #define V4L2_TC_USERBITS_8BITCHARS 0x0008 /* The above is based on SMPTE timecodes */ /* * C O M P R E S S I O N P A R A M E T E R S */ #if 0 /* ### generic compression settings don't work, there is too much * ### codec-specific stuff. Maybe reuse that for MPEG codec settings * ### later ... */ struct v4l2_compression { __u32 quality; __u32 keyframerate; __u32 pframerate; __u32 reserved[5]; }; #endif struct v4l2_jpegcompression { int quality; int APPn; /* Number of APP segment to be written, * must be 0..15 */ int APP_len; /* Length of data in JPEG APPn segment */ char APP_data[60]; /* Data in the JPEG APPn segment. */ int COM_len; /* Length of data in JPEG COM segment */ char COM_data[60]; /* Data in JPEG COM segment */ __u32 jpeg_markers; /* Which markers should go into the JPEG * output. Unless you exactly know what * you do, leave them untouched. * Inluding less markers will make the * resulting code smaller, but there will * be fewer aplications which can read it. * The presence of the APP and COM marker * is influenced by APP_len and COM_len * ONLY, not by this property! */ #define V4L2_JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */ #define V4L2_JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */ #define V4L2_JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */ #define V4L2_JPEG_MARKER_COM (1<<6) /* Comment segment */ #define V4L2_JPEG_MARKER_APP (1<<7) /* App segment, driver will * allways use APP0 */ }; /* * M E M O R Y - M A P P I N G B U F F E R S */ struct v4l2_requestbuffers { __u32 count; enum v4l2_buf_type type; enum v4l2_memory memory; __u32 reserved[2]; }; struct v4l2_buffer { __u32 index; enum v4l2_buf_type type; __u32 bytesused; __u32 flags; enum v4l2_field field; struct timeval timestamp; struct v4l2_timecode timecode; __u32 sequence; /* memory location */ enum v4l2_memory memory; union { __u32 offset; unsigned long userptr; } m; __u32 length; __u32 reserved[2]; }; /* Flags for 'flags' field */ #define V4L2_BUF_FLAG_MAPPED 0x0001 /* Buffer is mapped (flag) */ #define V4L2_BUF_FLAG_QUEUED 0x0002 /* Buffer is queued for processing */ #define V4L2_BUF_FLAG_DONE 0x0004 /* Buffer is ready */ #define V4L2_BUF_FLAG_KEYFRAME 0x0008 /* Image is a keyframe (I-frame) */ #define V4L2_BUF_FLAG_PFRAME 0x0010 /* Image is a P-frame */ #define V4L2_BUF_FLAG_BFRAME 0x0020 /* Image is a B-frame */ #define V4L2_BUF_FLAG_TIMECODE 0x0100 /* timecode field is valid */ /* * O V E R L A Y P R E V I E W */ struct v4l2_framebuffer { __u32 capability; __u32 flags; /* FIXME: in theory we should pass something like PCI device + memory * region + offset instead of some physical address */ void* base; struct v4l2_pix_format fmt; }; /* Flags for the 'capability' field. Read only */ #define V4L2_FBUF_CAP_EXTERNOVERLAY 0x0001 #define V4L2_FBUF_CAP_CHROMAKEY 0x0002 #define V4L2_FBUF_CAP_LIST_CLIPPING 0x0004 #define V4L2_FBUF_CAP_BITMAP_CLIPPING 0x0008 /* Flags for the 'flags' field. */ #define V4L2_FBUF_FLAG_PRIMARY 0x0001 #define V4L2_FBUF_FLAG_OVERLAY 0x0002 #define V4L2_FBUF_FLAG_CHROMAKEY 0x0004 struct v4l2_clip { struct v4l2_rect c; struct v4l2_clip *next; }; struct v4l2_window { struct v4l2_rect w; enum v4l2_field field; __u32 chromakey; struct v4l2_clip *clips; __u32 clipcount; void *bitmap; }; /* * C A P T U R E P A R A M E T E R S */ struct v4l2_captureparm { __u32 capability; /* Supported modes */ __u32 capturemode; /* Current mode */ struct v4l2_fract timeperframe; /* Time per frame in .1us units */ __u32 extendedmode; /* Driver-specific extensions */ __u32 readbuffers; /* # of buffers for read */ __u32 reserved[4]; }; /* Flags for 'capability' and 'capturemode' fields */ #define V4L2_MODE_HIGHQUALITY 0x0001 /* High quality imaging mode */ #define V4L2_CAP_TIMEPERFRAME 0x1000 /* timeperframe field is supported */ struct v4l2_outputparm { __u32 capability; /* Supported modes */ __u32 outputmode; /* Current mode */ struct v4l2_fract timeperframe; /* Time per frame in seconds */ __u32 extendedmode; /* Driver-specific extensions */ __u32 writebuffers; /* # of buffers for write */ __u32 reserved[4]; }; /* * I N P U T I M A G E C R O P P I N G */ struct v4l2_cropcap { enum v4l2_buf_type type; struct v4l2_rect bounds; struct v4l2_rect defrect; struct v4l2_fract pixelaspect; }; struct v4l2_crop { enum v4l2_buf_type type; struct v4l2_rect c; }; /* * A N A L O G V I D E O S T A N D A R D */ typedef __u64 v4l2_std_id; /* one bit for each */ #define V4L2_STD_PAL_B ((v4l2_std_id)0x00000001) #define V4L2_STD_PAL_B1 ((v4l2_std_id)0x00000002) #define V4L2_STD_PAL_G ((v4l2_std_id)0x00000004) #define V4L2_STD_PAL_H ((v4l2_std_id)0x00000008) #define V4L2_STD_PAL_I ((v4l2_std_id)0x00000010) #define V4L2_STD_PAL_D ((v4l2_std_id)0x00000020) #define V4L2_STD_PAL_D1 ((v4l2_std_id)0x00000040) #define V4L2_STD_PAL_K ((v4l2_std_id)0x00000080) #define V4L2_STD_PAL_M ((v4l2_std_id)0x00000100) #define V4L2_STD_PAL_N ((v4l2_std_id)0x00000200) #define V4L2_STD_PAL_Nc ((v4l2_std_id)0x00000400) #define V4L2_STD_PAL_60 ((v4l2_std_id)0x00000800) #define V4L2_STD_NTSC_M ((v4l2_std_id)0x00001000) #define V4L2_STD_NTSC_M_JP ((v4l2_std_id)0x00002000) #define V4L2_STD_SECAM_B ((v4l2_std_id)0x00010000) #define V4L2_STD_SECAM_D ((v4l2_std_id)0x00020000) #define V4L2_STD_SECAM_G ((v4l2_std_id)0x00040000) #define V4L2_STD_SECAM_H ((v4l2_std_id)0x00080000) #define V4L2_STD_SECAM_K ((v4l2_std_id)0x00100000) #define V4L2_STD_SECAM_K1 ((v4l2_std_id)0x00200000) #define V4L2_STD_SECAM_L ((v4l2_std_id)0x00400000) /* ATSC/HDTV */ #define V4L2_STD_ATSC_8_VSB ((v4l2_std_id)0x01000000) #define V4L2_STD_ATSC_16_VSB ((v4l2_std_id)0x02000000) /* some common needed stuff */ #define V4L2_STD_PAL_BG (V4L2_STD_PAL_B |\ V4L2_STD_PAL_B1 |\ V4L2_STD_PAL_G) #define V4L2_STD_PAL_DK (V4L2_STD_PAL_D |\ V4L2_STD_PAL_D1 |\ V4L2_STD_PAL_K) #define V4L2_STD_PAL (V4L2_STD_PAL_BG |\ V4L2_STD_PAL_DK |\ V4L2_STD_PAL_H |\ V4L2_STD_PAL_I) #define V4L2_STD_NTSC (V4L2_STD_NTSC_M |\ V4L2_STD_NTSC_M_JP) #define V4L2_STD_SECAM (V4L2_STD_SECAM_B |\ V4L2_STD_SECAM_D |\ V4L2_STD_SECAM_G |\ V4L2_STD_SECAM_H |\ V4L2_STD_SECAM_K |\ V4L2_STD_SECAM_K1 |\ V4L2_STD_SECAM_L) #define V4L2_STD_525_60 (V4L2_STD_PAL_M |\ V4L2_STD_PAL_60 |\ V4L2_STD_NTSC) #define V4L2_STD_625_50 (V4L2_STD_PAL |\ V4L2_STD_PAL_N |\ V4L2_STD_PAL_Nc |\ V4L2_STD_SECAM) #define V4L2_STD_UNKNOWN 0 #define V4L2_STD_ALL (V4L2_STD_525_60 |\ V4L2_STD_625_50) struct v4l2_standard { __u32 index; v4l2_std_id id; __u8 name[24]; struct v4l2_fract frameperiod; /* Frames, not fields */ __u32 framelines; __u32 reserved[4]; }; /* * V I D E O I N P U T S */ struct v4l2_input { __u32 index; /* Which input */ __u8 name[32]; /* Label */ __u32 type; /* Type of input */ __u32 audioset; /* Associated audios (bitfield) */ __u32 tuner; /* Associated tuner */ v4l2_std_id std; __u32 status; __u32 reserved[4]; }; /* Values for the 'type' field */ #define V4L2_INPUT_TYPE_TUNER 1 #define V4L2_INPUT_TYPE_CAMERA 2 /* field 'status' - general */ #define V4L2_IN_ST_NO_POWER 0x00000001 /* Attached device is off */ #define V4L2_IN_ST_NO_SIGNAL 0x00000002 #define V4L2_IN_ST_NO_COLOR 0x00000004 /* field 'status' - analog */ #define V4L2_IN_ST_NO_H_LOCK 0x00000100 /* No horizontal sync lock */ #define V4L2_IN_ST_COLOR_KILL 0x00000200 /* Color killer is active */ /* field 'status' - digital */ #define V4L2_IN_ST_NO_SYNC 0x00010000 /* No synchronization lock */ #define V4L2_IN_ST_NO_EQU 0x00020000 /* No equalizer lock */ #define V4L2_IN_ST_NO_CARRIER 0x00040000 /* Carrier recovery failed */ /* field 'status' - VCR and set-top box */ #define V4L2_IN_ST_MACROVISION 0x01000000 /* Macrovision detected */ #define V4L2_IN_ST_NO_ACCESS 0x02000000 /* Conditional access denied */ #define V4L2_IN_ST_VTR 0x04000000 /* VTR time constant */ /* * V I D E O O U T P U T S */ struct v4l2_output { __u32 index; /* Which output */ __u8 name[32]; /* Label */ __u32 type; /* Type of output */ __u32 audioset; /* Associated audios (bitfield) */ __u32 modulator; /* Associated modulator */ v4l2_std_id std; __u32 reserved[4]; }; /* Values for the 'type' field */ #define V4L2_OUTPUT_TYPE_MODULATOR 1 #define V4L2_OUTPUT_TYPE_ANALOG 2 #define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY 3 /* * C O N T R O L S */ struct v4l2_control { __u32 id; __s32 value; }; /* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */ struct v4l2_queryctrl { __u32 id; enum v4l2_ctrl_type type; __u8 name[32]; /* Whatever */ __s32 minimum; /* Note signedness */ __s32 maximum; __s32 step; __s32 default_value; __u32 flags; __u32 reserved[2]; }; /* Used in the VIDIOC_QUERYMENU ioctl for querying menu items */ struct v4l2_querymenu { __u32 id; __u32 index; __u8 name[32]; /* Whatever */ __u32 reserved; }; /* Control flags */ #define V4L2_CTRL_FLAG_DISABLED 0x0001 #define V4L2_CTRL_FLAG_GRABBED 0x0002 /* Control IDs defined by V4L2 */ #define V4L2_CID_BASE 0x00980900 /* IDs reserved for driver specific controls */ #define V4L2_CID_PRIVATE_BASE 0x08000000 #define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE+0) #define V4L2_CID_CONTRAST (V4L2_CID_BASE+1) #define V4L2_CID_SATURATION (V4L2_CID_BASE+2) #define V4L2_CID_HUE (V4L2_CID_BASE+3) #define V4L2_CID_AUDIO_VOLUME (V4L2_CID_BASE+5) #define V4L2_CID_AUDIO_BALANCE (V4L2_CID_BASE+6) #define V4L2_CID_AUDIO_BASS (V4L2_CID_BASE+7) #define V4L2_CID_AUDIO_TREBLE (V4L2_CID_BASE+8) #define V4L2_CID_AUDIO_MUTE (V4L2_CID_BASE+9) #define V4L2_CID_AUDIO_LOUDNESS (V4L2_CID_BASE+10) #define V4L2_CID_BLACK_LEVEL (V4L2_CID_BASE+11) #define V4L2_CID_AUTO_WHITE_BALANCE (V4L2_CID_BASE+12) #define V4L2_CID_DO_WHITE_BALANCE (V4L2_CID_BASE+13) #define V4L2_CID_RED_BALANCE (V4L2_CID_BASE+14) #define V4L2_CID_BLUE_BALANCE (V4L2_CID_BASE+15) #define V4L2_CID_GAMMA (V4L2_CID_BASE+16) #define V4L2_CID_WHITENESS (V4L2_CID_GAMMA) /* ? Not sure */ #define V4L2_CID_EXPOSURE (V4L2_CID_BASE+17) #define V4L2_CID_AUTOGAIN (V4L2_CID_BASE+18) #define V4L2_CID_GAIN (V4L2_CID_BASE+19) #define V4L2_CID_HFLIP (V4L2_CID_BASE+20) #define V4L2_CID_VFLIP (V4L2_CID_BASE+21) #define V4L2_CID_HCENTER (V4L2_CID_BASE+22) #define V4L2_CID_VCENTER (V4L2_CID_BASE+23) #define V4L2_CID_LASTP1 (V4L2_CID_BASE+24) /* last CID + 1 */ /* * T U N I N G */ struct v4l2_tuner { __u32 index; __u8 name[32]; enum v4l2_tuner_type type; __u32 capability; __u32 rangelow; __u32 rangehigh; __u32 rxsubchans; __u32 audmode; __s32 signal; __s32 afc; __u32 reserved[4]; }; struct v4l2_modulator { __u32 index; __u8 name[32]; __u32 capability; __u32 rangelow; __u32 rangehigh; __u32 txsubchans; __u32 reserved[4]; }; /* Flags for the 'capability' field */ #define V4L2_TUNER_CAP_LOW 0x0001 #define V4L2_TUNER_CAP_NORM 0x0002 #define V4L2_TUNER_CAP_STEREO 0x0010 #define V4L2_TUNER_CAP_LANG2 0x0020 #define V4L2_TUNER_CAP_SAP 0x0020 #define V4L2_TUNER_CAP_LANG1 0x0040 /* Flags for the 'rxsubchans' field */ #define V4L2_TUNER_SUB_MONO 0x0001 #define V4L2_TUNER_SUB_STEREO 0x0002 #define V4L2_TUNER_SUB_LANG2 0x0004 #define V4L2_TUNER_SUB_SAP 0x0004 #define V4L2_TUNER_SUB_LANG1 0x0008 /* Values for the 'audmode' field */ #define V4L2_TUNER_MODE_MONO 0x0000 #define V4L2_TUNER_MODE_STEREO 0x0001 #define V4L2_TUNER_MODE_LANG2 0x0002 #define V4L2_TUNER_MODE_SAP 0x0002 #define V4L2_TUNER_MODE_LANG1 0x0003 struct v4l2_frequency { __u32 tuner; enum v4l2_tuner_type type; __u32 frequency; __u32 reserved[8]; }; /* * A U D I O */ struct v4l2_audio { __u32 index; __u8 name[32]; __u32 capability; __u32 mode; __u32 reserved[2]; }; /* Flags for the 'capability' field */ #define V4L2_AUDCAP_STEREO 0x00001 #define V4L2_AUDCAP_AVL 0x00002 /* Flags for the 'mode' field */ #define V4L2_AUDMODE_AVL 0x00001 struct v4l2_audioout { __u32 index; __u8 name[32]; __u32 capability; __u32 mode; __u32 reserved[2]; }; /* * D A T A S E R V I C E S ( V B I ) * * Data services API by Michael Schimek */ struct v4l2_vbi_format { __u32 sampling_rate; /* in 1 Hz */ __u32 offset; __u32 samples_per_line; __u32 sample_format; /* V4L2_PIX_FMT_* */ __s32 start[2]; __u32 count[2]; __u32 flags; /* V4L2_VBI_* */ __u32 reserved[2]; /* must be zero */ }; /* VBI flags */ #define V4L2_VBI_UNSYNC (1<< 0) #define V4L2_VBI_INTERLACED (1<< 1) /* * A G G R E G A T E S T R U C T U R E S */ /* Stream data format */ struct v4l2_format { enum v4l2_buf_type type; union { struct v4l2_pix_format pix; // V4L2_BUF_TYPE_VIDEO_CAPTURE struct v4l2_window win; // V4L2_BUF_TYPE_VIDEO_OVERLAY struct v4l2_vbi_format vbi; // V4L2_BUF_TYPE_VBI_CAPTURE __u8 raw_data[200]; // user-defined } fmt; }; /* Stream type-dependent parameters */ struct v4l2_streamparm { enum v4l2_buf_type type; union { struct v4l2_captureparm capture; struct v4l2_outputparm output; __u8 raw_data[200]; /* user-defined */ } parm; }; /* * I O C T L C O D E S F O R V I D E O D E V I C E S * */ #define VIDIOC_QUERYCAP _IOR ('V', 0, struct v4l2_capability) #define VIDIOC_RESERVED _IO ('V', 1) #define VIDIOC_ENUM_FMT _IOWR ('V', 2, struct v4l2_fmtdesc) #define VIDIOC_G_FMT _IOWR ('V', 4, struct v4l2_format) #define VIDIOC_S_FMT _IOWR ('V', 5, struct v4l2_format) #if 0 #define VIDIOC_G_COMP _IOR ('V', 6, struct v4l2_compression) #define VIDIOC_S_COMP _IOW ('V', 7, struct v4l2_compression) #endif #define VIDIOC_REQBUFS _IOWR ('V', 8, struct v4l2_requestbuffers) #define VIDIOC_QUERYBUF _IOWR ('V', 9, struct v4l2_buffer) #define VIDIOC_G_FBUF _IOR ('V', 10, struct v4l2_framebuffer) #define VIDIOC_S_FBUF _IOW ('V', 11, struct v4l2_framebuffer) #define VIDIOC_OVERLAY _IOWR ('V', 14, int) #define VIDIOC_QBUF _IOWR ('V', 15, struct v4l2_buffer) #define VIDIOC_DQBUF _IOWR ('V', 17, struct v4l2_buffer) #define VIDIOC_STREAMON _IOW ('V', 18, int) #define VIDIOC_STREAMOFF _IOW ('V', 19, int) #define VIDIOC_G_PARM _IOWR ('V', 21, struct v4l2_streamparm) #define VIDIOC_S_PARM _IOW ('V', 22, struct v4l2_streamparm) #define VIDIOC_G_STD _IOR ('V', 23, v4l2_std_id) #define VIDIOC_S_STD _IOW ('V', 24, v4l2_std_id) #define VIDIOC_ENUMSTD _IOWR ('V', 25, struct v4l2_standard) #define VIDIOC_ENUMINPUT _IOWR ('V', 26, struct v4l2_input) #define VIDIOC_G_CTRL _IOWR ('V', 27, struct v4l2_control) #define VIDIOC_S_CTRL _IOW ('V', 28, struct v4l2_control) #define VIDIOC_G_TUNER _IOWR ('V', 29, struct v4l2_tuner) #define VIDIOC_S_TUNER _IOW ('V', 30, struct v4l2_tuner) #define VIDIOC_G_AUDIO _IOWR ('V', 33, struct v4l2_audio) #define VIDIOC_S_AUDIO _IOW ('V', 34, struct v4l2_audio) #define VIDIOC_QUERYCTRL _IOWR ('V', 36, struct v4l2_queryctrl) #define VIDIOC_QUERYMENU _IOWR ('V', 37, struct v4l2_querymenu) #define VIDIOC_G_INPUT _IOR ('V', 38, int) #define VIDIOC_S_INPUT _IOWR ('V', 39, int) #define VIDIOC_G_OUTPUT _IOR ('V', 46, int) #define VIDIOC_S_OUTPUT _IOWR ('V', 47, int) #define VIDIOC_ENUMOUTPUT _IOWR ('V', 48, struct v4l2_output) #define VIDIOC_G_AUDOUT _IOWR ('V', 49, struct v4l2_audioout) #define VIDIOC_S_AUDOUT _IOW ('V', 50, struct v4l2_audioout) #define VIDIOC_G_MODULATOR _IOWR ('V', 54, struct v4l2_modulator) #define VIDIOC_S_MODULATOR _IOW ('V', 55, struct v4l2_modulator) #define VIDIOC_G_FREQUENCY _IOWR ('V', 56, struct v4l2_frequency) #define VIDIOC_S_FREQUENCY _IOW ('V', 57, struct v4l2_frequency) #define VIDIOC_CROPCAP _IOR ('V', 58, struct v4l2_cropcap) #define VIDIOC_G_CROP _IOWR ('V', 59, struct v4l2_crop) #define VIDIOC_S_CROP _IOW ('V', 60, struct v4l2_crop) #define VIDIOC_G_JPEGCOMP _IOR ('V', 61, struct v4l2_jpegcompression) #define VIDIOC_S_JPEGCOMP _IOW ('V', 62, struct v4l2_jpegcompression) #define VIDIOC_QUERYSTD _IOR ('V', 63, v4l2_std_id) #define VIDIOC_TRY_FMT _IOWR ('V', 64, struct v4l2_format) #define BASE_VIDIOC_PRIVATE 192 /* 192-255 are private */ #endif /* __LINUX_VIDEODEV2_H */ /* * Local variables: * c-basic-offset: 8 * End: */ amsn-0.98.9/utils/linux/capture/libng/Makefile0000644000175000017500000000003110246003435021055 0ustar billiobbilliobdefault: cd ..; $(MAKE) amsn-0.98.9/utils/linux/capture/libng/misc.c0000644000175000017500000000155410246003435020527 0ustar billiobbilliob#include "config.h" #include #include #include "grab-ng.h" #include "misc.h" /* ------------------------------------------------------------------------ */ /* prehistoric libc ;) */ #ifndef HAVE_STRCASESTR char* __used strcasestr(char *haystack, char *needle) { int hlen = strlen(haystack); int nlen = strlen(needle); int offset; for (offset = 0; offset <= hlen - nlen; offset++) if (0 == strncasecmp(haystack+offset,needle,nlen)) return haystack+offset; return NULL; } #endif #ifndef HAVE_MEMMEM void __used *memmem(unsigned char *haystack, size_t haystacklen, unsigned char *needle, size_t needlelen) { int i; for (i = 0; i < haystacklen - needlelen; i++) if (0 == memcmp(haystack+i,needle,needlelen)) return haystack+i; return NULL; } #endif amsn-0.98.9/utils/linux/capture/libng/writefile.c0000644000175000017500000003625610246003435021575 0ustar billiobbilliob/* * save pictures to disk (ppm,pgm,jpeg) * * (c) 1998-2000 Gerd Knorr * */ #define NG_PRIVATE #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "byteswap.h" #include "grab-ng.h" #include "writefile.h" /* ---------------------------------------------------------------------- */ /* * count up the latest block of digits in the passed string * (used for filename numbering */ int patch_up(char *name) { char *ptr; for (ptr = name+strlen(name); ptr >= name; ptr--) if (isdigit(*ptr)) break; if (ptr < name) return 0; while (*ptr == '9' && ptr >= name) *(ptr--) = '0'; if (ptr < name) return 0; if (isdigit(*ptr)) { (*ptr)++; return 1; } return 0; } char* snap_filename(char *base, char *channel, char *ext) { static time_t last = 0; static int count = 0; static char *filename = NULL; time_t now; struct tm* tm; char timestamp[32]; time(&now); tm = localtime(&now); if (last != now) count = 0; last = now; count++; if (filename != NULL) free(filename); filename = malloc(strlen(base)+strlen(channel)+strlen(ext)+32); strftime(timestamp,31,"%Y%m%d-%H%M%S",tm); sprintf(filename,"%s-%s-%s-%d.%s", base,channel,timestamp,count,ext); return filename; } /* ---------------------------------------------------------------------- */ static int do_write_jpeg(FILE *fp, struct ng_video_buf *buf, int quality, int gray) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; unsigned int i; unsigned char *line; int line_length; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, fp); cinfo.image_width = buf->fmt.width; cinfo.image_height = buf->fmt.height; cinfo.input_components = gray ? 1: 3; cinfo.in_color_space = gray ? JCS_GRAYSCALE: JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE); jpeg_start_compress(&cinfo, TRUE); line_length = gray ? buf->fmt.width : buf->fmt.width * 3; for (i = 0, line = buf->data; i < buf->fmt.height; i++, line += line_length) jpeg_write_scanlines(&cinfo, &line, 1); jpeg_finish_compress(&(cinfo)); jpeg_destroy_compress(&(cinfo)); fclose(fp); return 0; } int write_jpeg(char *filename, struct ng_video_buf *buf, int quality, int gray) { FILE *fp; if (NULL == (fp = fopen(filename,"w"))) { fprintf(stderr,"grab: can't open %s: %s\n",filename,strerror(errno)); return -1; } return do_write_jpeg(fp,buf,quality,gray); } #if 0 int write_jpeg_fd(int fd, struct ng_video_buf *buf, int quality, int gray) { FILE *fp; if (NULL == (fp = fdopen(fd,"w"))) { fprintf(stderr,"grab: can't fdopen(%d): %s\n",fd,strerror(errno)); return -1; } return do_write_jpeg(fp,buf,quality,gray); } #endif int write_ppm(char *filename, struct ng_video_buf *buf) { FILE *fp; if (NULL == (fp = fopen(filename,"w"))) { fprintf(stderr,"grab: can't open %s: %s\n",filename,strerror(errno)); return -1; } fprintf(fp,"P6\n%d %d\n255\n", buf->fmt.width,buf->fmt.height); fwrite(buf->data, buf->fmt.height, 3*buf->fmt.width,fp); fclose(fp); return 0; } int write_pgm(char *filename, struct ng_video_buf *buf) { FILE *fp; if (NULL == (fp = fopen(filename,"w"))) { fprintf(stderr,"grab: can't open %s: %s\n",filename,strerror(errno)); return -1; } fprintf(fp,"P5\n%d %d\n255\n", buf->fmt.width, buf->fmt.height); fwrite(buf->data, buf->fmt.height, buf->fmt.width, fp); fclose(fp); return 0; } /* ---------------------------------------------------------------------- */ /* *.wav I/O stolen from cdda2wav */ /* Copyright (C) by Heiko Eissfeldt */ typedef uint8_t BYTE; typedef uint16_t WORD; typedef uint32_t DWORD; typedef uint32_t FOURCC; /* a four character code */ /* flags for 'wFormatTag' field of WAVEFORMAT */ #define WAVE_FORMAT_PCM 1 /* MMIO macros */ #define mmioFOURCC(ch0, ch1, ch2, ch3) \ ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \ ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24)) #define FOURCC_RIFF mmioFOURCC ('R', 'I', 'F', 'F') #define FOURCC_LIST mmioFOURCC ('L', 'I', 'S', 'T') #define FOURCC_WAVE mmioFOURCC ('W', 'A', 'V', 'E') #define FOURCC_FMT mmioFOURCC ('f', 'm', 't', ' ') #define FOURCC_DATA mmioFOURCC ('d', 'a', 't', 'a') typedef struct CHUNKHDR { FOURCC ckid; /* chunk ID */ DWORD dwSize; /* chunk size */ } CHUNKHDR; /* simplified Header for standard WAV files */ typedef struct WAVEHDR { CHUNKHDR chkRiff; FOURCC fccWave; CHUNKHDR chkFmt; WORD wFormatTag; /* format type */ WORD nChannels; /* number of channels (i.e. mono, stereo, etc.) */ DWORD nSamplesPerSec; /* sample rate */ DWORD nAvgBytesPerSec; /* for buffer estimation */ WORD nBlockAlign; /* block size of data */ WORD wBitsPerSample; CHUNKHDR chkData; } WAVEHDR; #if BYTE_ORDER == BIG_ENDIAN # define cpu_to_le32(x) SWAP4((x)) # define cpu_to_le16(x) SWAP2((x)) # define le32_to_cpu(x) SWAP4((x)) # define le16_to_cpu(x) SWAP2((x)) #else # define cpu_to_le32(x) (x) # define cpu_to_le16(x) (x) # define le32_to_cpu(x) (x) # define le16_to_cpu(x) (x) #endif static void wav_init_header(WAVEHDR *fileheader, struct ng_audio_fmt *audio) { /* stolen from cdda2wav */ int nBitsPerSample = ng_afmt_to_bits[audio->fmtid]; int channels = ng_afmt_to_channels[audio->fmtid]; int rate = audio->rate; unsigned long nBlockAlign = channels * ((nBitsPerSample + 7) / 8); unsigned long nAvgBytesPerSec = nBlockAlign * rate; unsigned long temp = /* data length */ 0 + sizeof(WAVEHDR) - sizeof(CHUNKHDR); fileheader->chkRiff.ckid = cpu_to_le32(FOURCC_RIFF); fileheader->fccWave = cpu_to_le32(FOURCC_WAVE); fileheader->chkFmt.ckid = cpu_to_le32(FOURCC_FMT); fileheader->chkFmt.dwSize = cpu_to_le32(16); fileheader->wFormatTag = cpu_to_le16(WAVE_FORMAT_PCM); fileheader->nChannels = cpu_to_le16(channels); fileheader->nSamplesPerSec = cpu_to_le32(rate); fileheader->nAvgBytesPerSec = cpu_to_le32(nAvgBytesPerSec); fileheader->nBlockAlign = cpu_to_le16(nBlockAlign); fileheader->wBitsPerSample = cpu_to_le16(nBitsPerSample); fileheader->chkData.ckid = cpu_to_le32(FOURCC_DATA); fileheader->chkRiff.dwSize = cpu_to_le32(temp); fileheader->chkData.dwSize = cpu_to_le32(0 /* data length */); } static void wav_start_write(int fd, WAVEHDR *fileheader, struct ng_audio_fmt *audio) { wav_init_header(fileheader,audio); write(fd,fileheader,sizeof(WAVEHDR)); } static void wav_stop_write(int fd, WAVEHDR *fileheader, int wav_size) { unsigned long temp = wav_size + sizeof(WAVEHDR) - sizeof(CHUNKHDR); fileheader->chkRiff.dwSize = cpu_to_le32(temp); fileheader->chkData.dwSize = cpu_to_le32(wav_size); lseek(fd,0,SEEK_SET); write(fd,fileheader,sizeof(WAVEHDR)); } /* ---------------------------------------------------------------------- */ struct files_handle { /* file name */ char file[MAXPATHLEN]; /* format */ struct ng_video_fmt video; struct ng_audio_fmt audio; /* *.wav file */ int wav_fd; WAVEHDR wav_header; int wav_size; /* misc */ int gotcha; }; static void* files_open(char *filesname, char *audioname, struct ng_video_fmt *video, const void *priv_video, int fps, struct ng_audio_fmt *audio, const void *priv_audio) { struct files_handle *h; if (video->fmtid != VIDEO_NONE && NULL == filesname) return NULL; if (NULL == (h = malloc(sizeof(*h)))) return NULL; /* init */ memset(h,0,sizeof(*h)); h->video = *video; h->audio = *audio; if (filesname) strcpy(h->file,filesname); if (h->audio.fmtid != AUDIO_NONE) { h->wav_fd = open(audioname, O_CREAT | O_RDWR | O_TRUNC, 0666); if (-1 == h->wav_fd) { fprintf(stderr,"open %s: %s\n",audioname,strerror(errno)); free(h); return NULL; } wav_start_write(h->wav_fd,&h->wav_header,&h->audio); } return h; } static int files_video(void *handle, struct ng_video_buf *buf) { struct files_handle *h = handle; int rc = -1; FILE *fp; if (h->gotcha) { fprintf(stderr,"Oops: can't count up file names any more\n"); return -1; } switch (h->video.fmtid) { case VIDEO_RGB24: rc = write_ppm(h->file, buf); break; case VIDEO_GRAY: rc = write_pgm(h->file, buf); break; case VIDEO_JPEG: if (NULL == (fp = fopen(h->file,"w"))) { fprintf(stderr,"grab: can't open %s: %s\n",h->file,strerror(errno)); rc = -1; } else { fwrite(buf->data,buf->size,1,fp); fclose(fp); rc = 0; } } if (1 != patch_up(h->file)) h->gotcha = 1; return rc; } static int files_audio(void *handle, struct ng_audio_buf *buf) { struct files_handle *h = handle; if (buf->size != write(h->wav_fd,buf->data,buf->size)) return -1; h->wav_size += buf->size; return 0; } static int files_close(void *handle) { struct files_handle *h = handle; if (h->audio.fmtid != AUDIO_NONE) { wav_stop_write(h->wav_fd,&h->wav_header,h->wav_size); close(h->wav_fd); } free(h); return 0; } /* ---------------------------------------------------------------------- */ struct raw_priv { int yuv4mpeg; }; struct raw_handle { /* format */ struct ng_video_fmt video; struct ng_audio_fmt audio; const struct raw_priv *vpriv; /* video file*/ int fd; /* *.wav file */ int wav_fd; WAVEHDR wav_header; int wav_size; }; static void* raw_open(char *videoname, char *audioname, struct ng_video_fmt *video, const void *priv_video, int fps, struct ng_audio_fmt *audio, const void *priv_audio) { struct raw_handle *h; int frame_rate_code = 0; int frame_rate_mul = fps; int frame_rate_div = 1000; if (NULL == (h = malloc(sizeof(*h)))) return NULL; /* init */ memset(h,0,sizeof(*h)); h->video = *video; h->audio = *audio; h->vpriv = priv_video; /* audio */ if (h->audio.fmtid != AUDIO_NONE) { h->wav_fd = open(audioname, O_CREAT | O_RDWR | O_TRUNC, 0666); if (-1 == h->wav_fd) { fprintf(stderr,"open %s: %s\n",audioname,strerror(errno)); free(h); return NULL; } wav_start_write(h->wav_fd,&h->wav_header,&h->audio); } /* video */ if (h->video.fmtid != VIDEO_NONE) { if (h->vpriv && h->vpriv->yuv4mpeg) { switch (fps) { case 23976: frame_rate_code = 1; /* 24000 / 1001 */ frame_rate_mul = 24000; frame_rate_div = 1001; break; case 29970: frame_rate_code = 4; /* 30000 / 1001 */ frame_rate_mul = 30000; frame_rate_div = 1001; break; case 59940: frame_rate_code = 7; /* 60000 / 1001 */ frame_rate_mul = 60000; frame_rate_div = 1001; break; case 24000: frame_rate_code = 2; break; case 25000: frame_rate_code = 3; break; case 30000: frame_rate_code = 5; break; case 50000: frame_rate_code = 6; break; case 60000: frame_rate_code = 8; break; default: fprintf(stderr,"illegal frame rate\n"); free(h); return NULL; } } if (NULL != videoname) { h->fd = open(videoname, O_CREAT | O_RDWR | O_TRUNC, 0666); if (-1 == h->fd) { fprintf(stderr,"open %s: %s\n",videoname,strerror(errno)); if (h->wav_fd) close(h->wav_fd); free(h); return NULL; } } else { h->fd = 1; /* use stdout */ } if (h->vpriv && h->vpriv->yuv4mpeg) { char header[64]; switch (h->vpriv->yuv4mpeg) { case 1: sprintf(header, "YUV4MPEG %d %d %d\n", h->video.width, h->video.height,frame_rate_code); break; case 2: sprintf(header, "YUV4MPEG2 W%d H%d F%d:%d\n", h->video.width, h->video.height, frame_rate_mul, frame_rate_div); break; } write(h->fd, header, strlen(header)); } } return h; } static int raw_video(void *handle, struct ng_video_buf *buf) { struct raw_handle *h = handle; if (h->vpriv && h->vpriv->yuv4mpeg) switch (h->vpriv->yuv4mpeg) { case 1: if (6 != write(h->fd, "FRAME\n", 6)) return -1; break; case 2: if (7 != write(h->fd, "FRAME \n", 7)) return -1; break; } if (buf->size != write(h->fd,buf->data,buf->size)) return -1; return 0; } static int raw_audio(void *handle, struct ng_audio_buf *buf) { struct raw_handle *h = handle; if (buf->size != write(h->wav_fd,buf->data,buf->size)) return -1; h->wav_size += buf->size; return 0; } static int raw_close(void *handle) { struct raw_handle *h = handle; if (h->audio.fmtid != AUDIO_NONE) { wav_stop_write(h->wav_fd,&h->wav_header,h->wav_size); close(h->wav_fd); } if (h->video.fmtid != VIDEO_NONE && 1 != h->fd) close(h->fd); free(h); return 0; } /* ----------------------------------------------------------------------- */ /* data structures describing our capabilities */ static const struct ng_format_list files_vformats[] = { { name: "ppm", ext: "ppm", fmtid: VIDEO_RGB24, },{ name: "pgm", ext: "pgm", fmtid: VIDEO_GRAY, },{ name: "jpeg", ext: "jpeg", fmtid: VIDEO_JPEG, },{ /* EOF */ } }; static struct raw_priv yuv4mpeg = { yuv4mpeg: 1 }; static struct raw_priv yuv4mpeg2 = { yuv4mpeg: 2 }; static const struct ng_format_list raw_vformats[] = { { name: "rgb", ext: "raw", fmtid: VIDEO_RGB24, },{ name: "gray", ext: "raw", fmtid: VIDEO_GRAY, },{ name: "422", ext: "raw", fmtid: VIDEO_YUYV, },{ name: "422p", ext: "raw", fmtid: VIDEO_YUV422P, },{ name: "4mpeg", desc: "yuv4mpeg (mpeg2enc >= 1.6)", ext: "yuv", fmtid: VIDEO_YUV420P, priv: &yuv4mpeg2, },{ name: "4mpeg-o", desc: "yuv4mpeg (old mpeg2enc)", ext: "yuv", fmtid: VIDEO_YUV420P, priv: &yuv4mpeg, },{ /* EOF */ } }; static const struct ng_format_list wav_aformats[] = { { name: "mono8", ext: "wav", fmtid: AUDIO_U8_MONO, },{ name: "mono16", ext: "wav", fmtid: AUDIO_S16_LE_MONO, },{ name: "stereo", ext: "wav", fmtid: AUDIO_S16_LE_STEREO, },{ /* EOF */ } }; struct ng_writer files_writer = { name: "files", desc: "multiple image files", video: files_vformats, audio: wav_aformats, wr_open: files_open, wr_video: files_video, wr_audio: files_audio, wr_close: files_close, }; struct ng_writer raw_writer = { name: "raw", desc: "single file, raw video data", video: raw_vformats, audio: wav_aformats, wr_open: raw_open, wr_video: raw_video, wr_audio: raw_audio, wr_close: raw_close, }; /* ------------------------------------------------------------------- */ static void __init writefile_init(void) { ng_writer_register(NG_PLUGIN_MAGIC,__FILE__,&files_writer); ng_writer_register(NG_PLUGIN_MAGIC,__FILE__,&raw_writer); } amsn-0.98.9/utils/linux/capture/libng/devices.h0000644000175000017500000000037210246003435021220 0ustar billiobbilliob struct ng_device_config { char *video; char *radio; char *vbi; char *dsp; char *mixer; char *video_scan[32]; char *vbi_scan[32]; char *mixer_scan[32]; char *dsp_scan[32]; }; extern struct ng_device_config ng_dev; amsn-0.98.9/utils/linux/capture/libng/color_common.c0000644000175000017500000000247510246003435022265 0ustar billiobbilliob#define NG_PRIVATE #include "config.h" #include #include #include #include #include #include #include "grab-ng.h" /* ------------------------------------------------------------------- */ void* ng_packed_init(struct ng_video_fmt *out, void *priv) { return priv; } void ng_packed_frame(void *handle, struct ng_video_buf *out, struct ng_video_buf *in) { int (*func)(unsigned char *dest, unsigned char *src, int p) = handle; unsigned char *sp,*dp; unsigned int i,sw,dw; dw = (out->fmt.width * ng_vfmt_to_depth[out->fmt.fmtid]) >> 3; sw = (in->fmt.width * ng_vfmt_to_depth[in->fmt.fmtid]) >> 3; if (in->fmt.bytesperline == sw && out->fmt.bytesperline == dw) { /* can convert in one go */ func(out->data, in->data, in->fmt.width * in->fmt.height); } else { /* convert line by line */ dp = out->data; sp = in->data; for (i = 0; i < in->fmt.height; i++) { func(dp,sp,in->fmt.width); dp += out->fmt.bytesperline; sp += in->fmt.bytesperline; } } out->info = in->info; } /* ------------------------------------------------------------------- */ void* ng_conv_nop_init(struct ng_video_fmt *out, void *priv) { /* nothing */ return NULL; } void ng_conv_nop_fini(void *handle) { /* nothing */ } amsn-0.98.9/utils/linux/capture/libng/OVERVIEW0000644000175000017500000001566310246003435020627 0ustar billiobbilliob libng overview ============== some general notes ------------------ The text below is not a complete reference (yet?), it just tries to give a overview and explain the design of the library. Have a look at grab-ng.h, this is the header file where everything is defined. If you are looking for some simple sample code check out console/webcam.c. More complex usages of libng can be found everythere in the xawtv source code: In common/capture.c for example, where most of the threaded movie recording code for xawtv+streamer is. There are two types of structs: Those which carrying some data (like ng_video_fmt or ng_video_buf) and those which define a interface (like ng_driver). The interfaces all have a initialization function which returns a void pointer as handle. All other interface functions expect getting that handle passed in. The complete state information is kept there. Global variables are a no-no, the interfaces need to be reentrant (so you can use multiple instances of them at the same time). video buffers (struct ng_video_buf) ----------------------------------- One video buffer holds one frame. There are some rules for video frames: (1) Multiple instances (threads for example) may hold a pointer to the buffer. The refcount variable is used to keep track of the number of references. If you hand out a pointer to the buffer to someone else *and* keep a pointer to the buffer yourself to use it later refcount must be increased by one. If you don't need the buffer any more, just free it with ng_release_video_buf(). That function will take care about count down the reference counter and freeing the buffer if refcount is zero. (2) The above implies you should not write to ng_video_buf->data because another thread might use the image data while you are modifying it. Allocate a new buffer and put the new data in there instead if you want process the image data. You can use ng_malloc_video_buf() to get a buffer. Don't forget to copy the frame meta data to the new buffer (ng_video_buf->info). Within the current implementation two types of buffers exist: Those malloc()ed ones which are returned by ng_malloc_video_buf() and buffers provided by the hardware drivers, where ng_video_buf->data is a pointer directly to the mmap()ed buffer(s). video capture / overlay drivers (struct ng_vid_driver) ------------------------------------------------------ This is a interface to a capture driver. Right now three different ones exist: (1) video4linux (current linux API, see plugins/drv1-v4l.c). (2) video4linux two (work in progress - new API for linux, see plugins/drv0-v4l2.c). (3) bktr (bt848/878 driver for FreeBSD + OpenBSD, see plugins/drv0-bsd.c). xawtv uses struct ng_vid_driver for Xvideo support too (see x11/xv.c). open()/close() should be clear. The capabilities() function returns a bitfield which specifies the capabilities of the driver. The *attr* functions can be used to control several (hardware) settings (see below for more on attributes). To for a overlay use setupfb() and overlay(). For linux setupfb() just verifies the driver parameters, it expects the setup is done with a extern utility like v4l-conf (because one needs root priviliges for that). To capture frames you have to configure the format with setformat() first. Be aware that the image size might have changed on return, depending on the capabilities of the underlying hardware. For video recording use startvideo(), multiple nextframe() calls and stopvideo(), for single frames use getimage(). output drivers (struct ng_writer) --------------------------------- This is a interface for movie writer code. Four different ones exist: (1) Microsoft's AVI (2) Apple Quicktime (using the libquicktime library). (3) raw, uncompressed data (one big file). (4) one image file/frame (jpeg or ppm). The first two write audio and video data into the same stream, the last two can write audio data to a separate wav file. The audio/video args hold a list of supported formats. Usage should be pretty straight forward: wr_open(), write data with wr_video() + wr_audio(), then wr_close(). You can write both audio-only and video-only streams if you want. attributes (struct ng_attribute) -------------------------------- Attributes can be used to control properties attributes. Right now they are only used for video drivers (struct ng_driver), but that might change in the future. There are a number of standard attributes defined (tv norm, volume and the like), but it is also possible to specify non-standard attributes. struct ng_attribute also has functions to list/read/modify the given attribute. A number of helper functions to search a attribute list by id / name and for multiple choice attribute handling are available too. audio recording + mixer control ------------------------------- There are only some structs for audio formats and audio data chunks. The movie writers use these. There are also interfaces for sound recording and mixer control (struct ng_dsp_driver + struct ng_mix_driver) and a implementation for the OSS API (in plugins/snd-oss.c). I'm not that happy with the current design of the mixer stuff, it likely will change in the future. color space conversion and compression -------------------------------------- struct ng_video_conv describes a converter. There are plenty built-in into libng, but it is also possible to add more using plugins. These converters handle (a) color space conversion (yuv -> rgb), (b) convert rgb with different color depths, (c) handle compression. image filtering --------------- I've recently added a interfaces for image filtering (i.e. on-the-fly image processing). struct ng_filter is it, in plugins/flt-*.c is some sample code. There is no complex stuff yet. For now filters are limited: They work on a frame-by-frame base, i.e. for one frame which gets passed in one is expected to come out. Read: you can't (yet?) merge multiple frames into one. The input and output format is expected to be the same. Filters should be able to handle as much formats as possible, neither xawtv nor libng attempt to do any conversions (i.e. do yuv->rgb -> filter -> rgb->yuv for you because the filter works in RGB space only). ng_filter->fmts lists the supported formats of a given filter, and if the required format isn't supported by some filter it is simply skipped and no filtering takes place. Most frequently formats are: * RGB (various depts), to display images on the X11 screen, for ppm capture, ... * packed pixel yuv (If xawtv/motv blits images using the Xvideo extension instead of normal X11 ximages). * planar yuv (for recording compressed video, libjpeg can be feeded directly with planar yuv to save some CPU cycles for rgb->yuv color space conversion). misc ---- There are some helper functions for various stuff, see grab-ng.[ch]. There are also some arrays with text descriptions and other informations about audio/video formats: ng_[va]fmt_to_*. amsn-0.98.9/utils/linux/capture/libng/color_packed.c0000644000175000017500000001304111755523031022220 0ustar billiobbilliob/* * colorspace conversion functions * -- packed pixel formats (rgb/gray right now) * * (c) 1998-2001 Gerd Knorr * */ #define NG_PRIVATE #include "config.h" #include #include #include #include #include #include #include "grab-ng.h" /* ------------------------------------------------------------------- */ /* RGB conversions */ static void redblue_swap(unsigned char *dest, unsigned char *src, int p) { register unsigned char *s = src; register unsigned char *d = dest; while (p--) { *(d++) = s[2]; *(d++) = s[1]; *(d++) = s[0]; s += 3; } } static void bgr24_to_bgr32(unsigned char* restrict dest, unsigned char* restrict src, int p) { register unsigned char* restrict s = src; register unsigned char* restrict d = dest; while (p--) { *(d++) = *(s++); *(d++) = *(s++); *(d++) = *(s++); *(d++) = 0; } } static void bgr24_to_rgb32(unsigned char* restrict dest, unsigned char* restrict src, int p) { register unsigned char* restrict s = src; register unsigned char* restrict d = dest; while (p--) { *(d++) = 0; *(d++) = s[2]; *(d++) = s[1]; *(d++) = s[0]; s +=3; } } static void rgb32_to_rgb24(unsigned char* restrict dest, unsigned char* restrict src, int p) { register unsigned char* restrict s = src; register unsigned char* restrict d = dest; while (p--) { s++; *(d++) = *(s++); *(d++) = *(s++); *(d++) = *(s++); } } static void rgb32_to_bgr24(unsigned char* restrict dest, unsigned char* restrict src, int p) { register unsigned char* restrict s = src; register unsigned char* restrict d = dest; while (p--) { s++; d[2] = *(s++); d[1] = *(s++); d[0] = *(s++); d += 3; } } /* 15+16 bpp LE <=> BE */ static void byteswap_short(unsigned char* restrict dest, unsigned char* restrict src, int p) { register unsigned char* restrict s = src; register unsigned char* restrict d = dest; while (--p) { *(d++) = s[1]; *(d++) = s[0]; s += 2; } } /* ------------------------------------------------------------------- */ /* color => grayscale */ static void rgb15_native_gray(unsigned char* restrict dest, unsigned char *s, int p) { int r,g,b; unsigned short* restrict src = (unsigned short*)s; while (p--) { r = (src[0] & 0x7c00) >> 10; g = (src[0] & 0x03e0) >> 5; b = src[0] & 0x001f; *(dest++) = ((3*r + 6*g + b)/10) << 3; src++; } } #if BYTE_ORDER == LITTLE_ENDIAN static void rgb15_be_gray(unsigned char* restrict dest, unsigned char* restrict src, int p) { int r,g,b; register unsigned char* restrict d = dest; while (p--) { r = (src[0] & 0x7c) >> 2; g = (src[0] & 0x03) << 3 | (src[1] & 0xe0) >> 5; b = src[1] & 0x1f; *(d++) = ((3*r + 6*g + b)/10) << 3; src += 2; } } #endif #if BYTE_ORDER == BIG_ENDIAN static void rgb15_le_gray(unsigned char* restrict dest, unsigned char* restrict src, int p) { int r,g,b; register unsigned char* restrict d = dest; while (p--) { r = (src[1] & 0x7c) >> 2; g = (src[1] & 0x03) << 3 | (src[0] & 0xe0) >> 5; b = src[0] & 0x1f; *(d++) = ((3*r + 6*g + b)/10) << 3; src += 2; } } #endif /* ------------------------------------------------------------------- */ static struct ng_video_conv conv_list[] = { { /* ----------------------------------- write GRAY -- */ #if BYTE_ORDER == BIG_ENDIAN NG_GENERIC_PACKED, .fmtid_in = VIDEO_RGB15_BE, .fmtid_out = VIDEO_GRAY, .priv = rgb15_native_gray, }, { NG_GENERIC_PACKED, .fmtid_in = VIDEO_RGB15_LE, .fmtid_out = VIDEO_GRAY, .priv = rgb15_le_gray, }, { #else NG_GENERIC_PACKED, .fmtid_in = VIDEO_RGB15_BE, .fmtid_out = VIDEO_GRAY, .priv = rgb15_be_gray, }, { NG_GENERIC_PACKED, .fmtid_in = VIDEO_RGB15_LE, .fmtid_out = VIDEO_GRAY, .priv = rgb15_native_gray, }, { #endif /* ----------------------------------- write RGB15 -- */ NG_GENERIC_PACKED, .fmtid_in = VIDEO_RGB15_LE, .fmtid_out = VIDEO_RGB15_BE, .priv = byteswap_short, }, { NG_GENERIC_PACKED, .fmtid_in = VIDEO_RGB15_BE, .fmtid_out = VIDEO_RGB15_LE, .priv = byteswap_short, }, { /* ----------------------------------- write RGB16 -- */ NG_GENERIC_PACKED, .fmtid_in = VIDEO_RGB16_LE, .fmtid_out = VIDEO_RGB16_BE, .priv = byteswap_short, }, { NG_GENERIC_PACKED, .fmtid_in = VIDEO_RGB16_BE, .fmtid_out = VIDEO_RGB16_LE, .priv = byteswap_short, }, { /* ----------------------------------- write RGB24 -- */ NG_GENERIC_PACKED, .fmtid_in = VIDEO_BGR24, .fmtid_out = VIDEO_RGB24, .priv = redblue_swap, }, { NG_GENERIC_PACKED, .fmtid_in = VIDEO_RGB24, .fmtid_out = VIDEO_BGR24, .priv = redblue_swap, }, { NG_GENERIC_PACKED, .fmtid_in = VIDEO_RGB32, .fmtid_out = VIDEO_RGB24, .priv = rgb32_to_rgb24, }, { NG_GENERIC_PACKED, .fmtid_in = VIDEO_RGB32, .fmtid_out = VIDEO_BGR24, .priv = rgb32_to_bgr24, }, { /* ----------------------------------- write RGB32 -- */ NG_GENERIC_PACKED, .fmtid_in = VIDEO_BGR24, .fmtid_out = VIDEO_BGR32, .priv = bgr24_to_bgr32, }, { NG_GENERIC_PACKED, .fmtid_in = VIDEO_BGR24, .fmtid_out = VIDEO_RGB32, .priv = bgr24_to_rgb32, } }; static const int nconv = sizeof(conv_list)/sizeof(struct ng_video_conv); /* ------------------------------------------------------------------- */ void packed_init (void) { ng_conv_register(NG_PLUGIN_MAGIC,__FILE__,conv_list,nconv); } amsn-0.98.9/utils/linux/capture/libng/parse-dvb.c0000644000175000017500000002021310246003435021450 0ustar billiobbilliob/* * parse various TV stuff out of DVB TS streams. * */ #include #include #include #include #include #include #include #include "grab-ng.h" #include "parse-mpeg.h" /* ----------------------------------------------------------------------- */ static unsigned int unbcd(unsigned int bcd) { unsigned int factor = 1; unsigned int ret = 0; unsigned int digit; while (bcd) { digit = bcd & 0x0f; ret += digit * factor; bcd /= 16; factor *= 10; } return ret; } static int iconv_string(char *from, char *to, char *src, size_t len, char *dst, size_t max) { size_t ilen = (-1 != len) ? len : strlen(src); size_t olen = max-1; iconv_t ic; ic = iconv_open(to,from); if (NULL == ic) return 0; while (ilen > 0) { if (-1 == iconv(ic,&src,&ilen,&dst,&olen)) { /* skip + quote broken byte unless we are out of space */ if (E2BIG == errno) break; if (olen < 4) break; sprintf(dst,"\\x%02x",(int)(unsigned char)src[0]); src += 1; dst += 4; ilen -= 1; olen -= 4; } } dst[0] = 0; iconv_close(ic); return max-1 - olen; } static int handle_control_8(unsigned char *src, int slen, unsigned char *dest, int dlen) { int s,d; for (s = 0, d = 0; s < slen && d < dlen;) { if (src[s] >= 0x80 && src[s] <= 0x9f) { switch (src[s]) { case 0x86: /* */ case 0x87: /* */ s++; break; case 0x1a: /* ^Z */ dest[d++] = ' '; s++; break; case 0x8a: /*
*/ dest[d++] = '\n'; s++; break; default: s++; } } else { dest[d++] = src[s++]; } } return d; } void mpeg_parse_psi_string(unsigned char *src, int slen, unsigned char *dest, int dlen) { unsigned char *tmp; int tlen,ch = 0; if (src[0] < 0x20) { ch = src[0]; src++; slen--; } memset(dest,0,dlen); if (ch < 0x10) { /* 8bit charset */ tmp = malloc(slen); tlen = handle_control_8(src, slen, tmp, slen); iconv_string(psi_charset[ch], "UTF-8", tmp, tlen, dest, dlen); free(tmp); } else { /* 16bit charset */ iconv_string(psi_charset[ch], "UTF-8", src, slen, dest, dlen); } } static void parse_nit_desc_1(unsigned char *desc, int dlen, char *dest, int max) { int i,t,l; for (i = 0; i < dlen; i += desc[i+1] +2) { t = desc[i]; l = desc[i+1]; switch (t) { case 0x40: mpeg_parse_psi_string(desc+i+2,l,dest,max); break; } } } static void parse_nit_desc_2(unsigned char *desc, int dlen, struct psi_stream *stream) { static char *bw[4] = { [ 0 ] = "8", [ 1 ] = "7", [ 2 ] = "6", }; static char *co_t[4] = { [ 0 ] = "0", [ 1 ] = "16", [ 2 ] = "64", }; static char *co_c[16] = { [ 0 ] = "0", [ 1 ] = "16", [ 2 ] = "32", [ 3 ] = "64", [ 4 ] = "128", [ 5 ] = "256", }; static char *hi[4] = { [ 0 ] = "0", [ 1 ] = "1", [ 2 ] = "2", [ 3 ] = "4", }; static char *ra_t[8] = { [ 0 ] = "12", [ 1 ] = "23", [ 2 ] = "34", [ 3 ] = "56", [ 4 ] = "78", }; static char *ra_sc[8] = { [ 1 ] = "12", [ 2 ] = "23", [ 3 ] = "34", [ 4 ] = "56", [ 5 ] = "78", }; static char *gu[4] = { [ 0 ] = "32", [ 1 ] = "16", [ 2 ] = "8", [ 3 ] = "4", }; static char *tr[2] = { [ 0 ] = "2", [ 1 ] = "8", }; static char *po[4] = { [ 0 ] = "H", [ 1 ] = "V", [ 2 ] = "L", // circular left [ 3 ] = "R", // circular right }; unsigned int freq,rate,fec; int i,t,l; for (i = 0; i < dlen; i += desc[i+1] +2) { t = desc[i]; l = desc[i+1]; switch (t) { case 0x43: /* dvb-s */ freq = mpeg_getbits(desc+i+2, 0, 32); rate = mpeg_getbits(desc+i+2, 56, 28); fec = mpeg_getbits(desc+i+2, 85, 3); stream->frequency = unbcd(freq) * 10; stream->symbol_rate = unbcd(rate*16) * 10; stream->fec_inner = ra_sc[fec]; stream->polarization = po[ mpeg_getbits(desc+i+2, 49, 2) ]; break; case 0x44: /* dvb-c */ freq = mpeg_getbits(desc+i+2, 0, 32); rate = mpeg_getbits(desc+i+2, 56, 28); fec = mpeg_getbits(desc+i+2, 85, 3); stream->frequency = unbcd(freq) * 100; stream->symbol_rate = unbcd(rate*16) * 10; stream->fec_inner = ra_sc[fec]; stream->constellation = co_c[ mpeg_getbits(desc+i+2, 52, 4) ]; break; case 0x5a: /* dvb-t */ stream->frequency = mpeg_getbits(desc+i+2, 0, 32) * 10; stream->bandwidth = bw[ mpeg_getbits(desc+i+2, 33, 2) ]; stream->constellation = co_t[ mpeg_getbits(desc+i+2, 40, 2) ]; stream->hierarchy = hi[ mpeg_getbits(desc+i+2, 43, 2) ]; stream->code_rate_hp = ra_t[ mpeg_getbits(desc+i+2, 45, 3) ]; stream->code_rate_lp = ra_t[ mpeg_getbits(desc+i+2, 48, 3) ]; stream->guard = gu[ mpeg_getbits(desc+i+2, 51, 2) ]; stream->transmission = tr[ mpeg_getbits(desc+i+2, 54, 1) ]; break; } } return; } static void parse_sdt_desc(unsigned char *desc, int dlen, struct psi_program *pr) { int i,t,l; char *name,*net; for (i = 0; i < dlen; i += desc[i+1] +2) { t = desc[i]; l = desc[i+1]; switch (t) { case 0x48: pr->type = desc[i+2]; pr->updated = 1; net = desc + i+3; name = net + net[0] + 1; mpeg_parse_psi_string(net+1, net[0], pr->net, sizeof(pr->net)); mpeg_parse_psi_string(name+1, name[0], pr->name, sizeof(pr->name)); break; } } } /* ----------------------------------------------------------------------- */ int mpeg_parse_psi_sdt(struct psi_info *info, unsigned char *data, int verbose) { static const char *running[] = { [ 0 ] = "undefined", [ 1 ] = "not running", [ 2 ] = "starts soon", [ 3 ] = "pausing", [ 4 ] = "running", [ 5 ... 8 ] = "reserved", }; struct psi_program *pr; int tsid,pnr,version,current; int j,len,dlen,run,ca; len = mpeg_getbits(data,12,12) + 3 - 4; tsid = mpeg_getbits(data,24,16); version = mpeg_getbits(data,42,5); current = mpeg_getbits(data,47,1); if (!current) return len+4; if (info->tsid == tsid && info->sdt_version == version) return len+4; info->sdt_version = version; if (verbose) fprintf(stderr, "ts [sdt]: tsid %d ver %2d [%d/%d]\n", tsid, version, mpeg_getbits(data,48, 8), mpeg_getbits(data,56, 8)); j = 88; while (j < len*8) { pnr = mpeg_getbits(data,j,16); run = mpeg_getbits(data,j+24,3); ca = mpeg_getbits(data,j+27,1); dlen = mpeg_getbits(data,j+28,12); if (verbose > 1) { fprintf(stderr," pnr %3d ca %d %s #", pnr, ca, running[run]); mpeg_dump_desc(data+j/8+5,dlen); fprintf(stderr,"\n"); } pr = psi_program_get(info, tsid, pnr, 1); parse_sdt_desc(data+j/8+5,dlen,pr); pr->running = run; pr->ca = ca; j += 40 + dlen*8; } if (verbose > 1) fprintf(stderr,"\n"); return len+4; } int mpeg_parse_psi_nit(struct psi_info *info, unsigned char *data, int verbose) { struct psi_stream *stream; char network[PSI_STR_MAX] = ""; int id,version,current,len; int j,dlen,tsid; len = mpeg_getbits(data,12,12) + 3 - 4; id = mpeg_getbits(data,24,16); version = mpeg_getbits(data,42,5); current = mpeg_getbits(data,47,1); if (!current) return len+4; if (0 /* info->id == id */ && info->nit_version == version) return len+4; info->nit_version = version; j = 80; dlen = mpeg_getbits(data,68,12); parse_nit_desc_1(data + j/8, dlen, network, sizeof(network)); if (verbose) { fprintf(stderr, "ts [nit]: id %3d ver %2d [%d/%d] #", id, version, mpeg_getbits(data,48, 8), mpeg_getbits(data,56, 8)); mpeg_dump_desc(data + j/8, dlen); fprintf(stderr,"\n"); } j += 16 + 8*dlen; while (j < len*8) { tsid = mpeg_getbits(data,j,16); dlen = mpeg_getbits(data,j+36,12); j += 48; stream = psi_stream_get(info, tsid, 1); stream->updated = 1; if (network) strcpy(stream->net, network); parse_nit_desc_2(data + j/8, dlen, stream); if (verbose > 1) { fprintf(stderr," tsid %3d #", tsid); mpeg_dump_desc(data + j/8, dlen); fprintf(stderr,"\n"); } j += 8*dlen; } if (verbose > 1) fprintf(stderr,"\n"); return len+4; } amsn-0.98.9/utils/linux/capture/libng/devices.c0000644000175000017500000000462610733772533021236 0ustar billiobbilliob/* * default devices names */ #include #include #include #include #include #include #include "devices.h" #if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) struct ng_device_config ng_dev = { video: "/dev/bktr0", radio: NULL, vbi: "/dev/vbi0", dsp: "/dev/dsp", mixer: "/dev/mixer", video_scan: { "/dev/bktr0", "/dev/bktr1", "/dev/cxm0", "/dev/cxm1", NULL }, vbi_scan: { "/dev/vbi0", "/dev/vbi1", NULL }, mixer_scan: { "/dev/mixer", "/dev/mixer1", "/dev/mixer2", "/dev/mixer3", NULL }, dsp_scan: { "/dev/dsp", "/dev/dsp1", "/dev/dsp2", "/dev/dsp3", NULL }, }; #endif #if defined(__linux__) || defined(__sun) struct ng_device_config ng_dev = { video: "/dev/video0", /* thank you redhat breaking * /dev/video as symbolic link to the * default video device ... */ radio: "/dev/radio", vbi: "/dev/vbi", dsp: "/dev/dsp", mixer: "/dev/mixer", video_scan: { "/dev/video0", "/dev/video1", "/dev/video2", "/dev/video3", NULL }, vbi_scan: { "/dev/vbi0", "/dev/vbi1", "/dev/vbi2", "/dev/vbi3", NULL }, mixer_scan: { "/dev/mixer", "/dev/mixer1", "/dev/mixer2", "/dev/mixer3", NULL }, dsp_scan: { "/dev/dsp", "/dev/adsp", "/dev/dsp1", "/dev/adsp1", "/dev/dsp2", "/dev/adsp2", "/dev/dsp3", "/dev/adsp3", NULL }, }; struct ng_device_config ng_dev_devfs = { video: "/dev/v4l/video0", radio: "/dev/v4l/radio0", vbi: "/dev/v4l/vbi0", dsp: "/dev/sound/dsp", mixer: "/dev/sound/mixer", video_scan: { "/dev/v4l/video0", "/dev/v4l/video1", "/dev/v4l/video2", "/dev/v4l/video3", NULL }, vbi_scan: { "/dev/v4l/vbi0", "/dev/v4l/vbi1", "/dev/v4l/vbi2", "/dev/v4l/vbi3", NULL }, mixer_scan: { "/dev/sound/mixer", "/dev/sound/mixer1", "/dev/sound/mixer2", "/dev/sound/mixer3", NULL }, dsp_scan: { "/dev/sound/dsp", "/dev/sound/adsp", "/dev/sound/dsp1", "/dev/sound/adsp1", "/dev/sound/dsp2", "/dev/sound/adsp2", "/dev/sound/dsp3", "/dev/sound/adsp3", NULL }, }; #endif #if defined(__linux__) static void __attribute__ ((constructor)) device_init(void) { struct stat st; if (-1 == lstat("/dev/.devfsd",&st)) return; if (!S_ISCHR(st.st_mode)) return; ng_dev = ng_dev_devfs; } #endif amsn-0.98.9/utils/linux/capture/libng/grab-ng.h0000644000175000017500000005304311755523031021123 0ustar billiobbilliob/* * next generation[tm] xawtv capture interfaces * * (c) 2001-03 Gerd Knorr * */ #include #include #include "devices.h" #include "list.h" extern int ng_debug; extern int ng_log_bad_stream; extern int ng_log_resync; extern int ng_chromakey; extern int ng_ratio_x; extern int ng_ratio_y; extern char ng_v4l_conf[256]; extern int ng_jpeg_quality; extern int ng_mpeg_vpid; extern int ng_mpeg_apid; #undef BUG_ON #undef BUG #define BUG_ON(condition,message,arg...) if (condition) {\ fprintf(stderr,"BUG: " message " [%s:%s:%d]\n",\ ## arg, __FILE__, __FUNCTION__, __LINE__);\ abort();} #define BUG(message,arg...) if (1) {\ fprintf(stderr,"BUG: " message " [%s:%s:%d]\n",\ ## arg, __FILE__, __FUNCTION__, __LINE__);\ abort();} #define OOPS_ON(condition,message,arg...) if (condition) {\ fprintf(stderr,"Oops: " message " [%s:%s:%d]\n",\ ## arg, __FILE__, __FUNCTION__, __LINE__);} #define OOPS(message,arg...) if (1) {\ fprintf(stderr,"Oops: " message " [%s:%s:%d]\n",\ ## arg, __FILE__, __FUNCTION__, __LINE__);} #if !defined(__cplusplus) && __STDC_VERSION__ < 199901 # undef bool # define bool int #endif #if __STDC_VERSION__ < 199901 # define restrict #endif #define UNSET (-1U) #define DIMOF(array) (sizeof(array)/sizeof(array[0])) #define SDIMOF(array) ((signed int)(sizeof(array)/sizeof(array[0]))) #define GETELEM(array,index,default) \ (index < sizeof(array)/sizeof(array[0]) ? array[index] : default) #ifdef __sun #include /* For major() */ #define __u32 uint32_t #define __u16 uint16_t #define __u8 uint8_t #endif /* --------------------------------------------------------------------- */ /* defines */ #define VIDEO_NONE 0 #define VIDEO_RGB08 1 /* bt848 dithered */ #define VIDEO_GRAY 2 #define VIDEO_RGB15_LE 3 /* 15 bpp little endian */ #define VIDEO_RGB16_LE 4 /* 16 bpp little endian */ #define VIDEO_RGB15_BE 5 /* 15 bpp big endian */ #define VIDEO_RGB16_BE 6 /* 16 bpp big endian */ #define VIDEO_BGR24 7 /* bgrbgrbgrbgr (LE) */ #define VIDEO_BGR32 8 /* bgr-bgr-bgr- (LE) */ #define VIDEO_RGB24 9 /* rgbrgbrgbrgb (BE) */ #define VIDEO_RGB32 10 /* -rgb-rgb-rgb (BE) */ #define VIDEO_LUT2 11 /* lookup-table 2 byte depth */ #define VIDEO_LUT4 12 /* lookup-table 4 byte depth */ #define VIDEO_YUYV 13 /* 4:2:2 */ #define VIDEO_YUV422P 14 /* YUV 4:2:2 (planar) */ #define VIDEO_YUV420P 15 /* YUV 4:2:0 (planar) */ #define VIDEO_MJPEG 16 /* MJPEG (AVI) */ #define VIDEO_JPEG 17 /* JPEG (JFIF) */ #define VIDEO_UYVY 18 /* 4:2:2 */ #define VIDEO_MPEG 19 /* MPEG1/2 */ #define VIDEO_BAYER 20 #define VIDEO_S910 21 #define VIDEO_FMT_COUNT 22 #define AUDIO_NONE 0 #define AUDIO_U8_MONO 1 #define AUDIO_U8_STEREO 2 #define AUDIO_S16_LE_MONO 3 #define AUDIO_S16_LE_STEREO 4 #define AUDIO_S16_BE_MONO 5 #define AUDIO_S16_BE_STEREO 6 #define AUDIO_MP3 7 #define AUDIO_FMT_COUNT 8 #if BYTE_ORDER == BIG_ENDIAN # define AUDIO_S16_NATIVE_MONO AUDIO_S16_BE_MONO # define AUDIO_S16_NATIVE_STEREO AUDIO_S16_BE_STEREO # define VIDEO_RGB15_NATIVE VIDEO_RGB15_BE # define VIDEO_RGB16_NATIVE VIDEO_RGB16_BE #endif #if BYTE_ORDER == LITTLE_ENDIAN # define AUDIO_S16_NATIVE_MONO AUDIO_S16_LE_MONO # define AUDIO_S16_NATIVE_STEREO AUDIO_S16_LE_STEREO # define VIDEO_RGB15_NATIVE VIDEO_RGB15_LE # define VIDEO_RGB16_NATIVE VIDEO_RGB16_LE #endif #define ATTR_TYPE_INTEGER 1 /* range 0 - 65535 */ #define ATTR_TYPE_CHOICE 2 /* multiple choice */ #define ATTR_TYPE_BOOL 3 /* yes/no */ #define ATTR_ID_NORM 1 #define ATTR_ID_INPUT 2 #define ATTR_ID_VOLUME 3 #define ATTR_ID_MUTE 4 #define ATTR_ID_AUDIO_MODE 5 #define ATTR_ID_COLOR 6 #define ATTR_ID_BRIGHT 7 #define ATTR_ID_HUE 8 #define ATTR_ID_CONTRAST 9 #define ATTR_ID_COUNT 10 #define CAN_OVERLAY 1 #define CAN_CAPTURE 2 #define CAN_TUNE 4 #define NEEDS_CHROMAKEY 8 #define CAN_MPEG_PS 16 #define CAN_MPEG_TS 32 #define MPEG_FLAGS_PS 1 #define MPEG_FLAGS_TS 2 /* --------------------------------------------------------------------- */ extern const unsigned int ng_vfmt_to_depth[VIDEO_FMT_COUNT]; extern const char* ng_vfmt_to_desc[VIDEO_FMT_COUNT]; extern const unsigned int ng_afmt_to_channels[AUDIO_FMT_COUNT]; extern const unsigned int ng_afmt_to_bits[AUDIO_FMT_COUNT]; extern const char* ng_afmt_to_desc[AUDIO_FMT_COUNT]; extern const char* ng_attr_to_desc[ATTR_ID_COUNT]; /* --------------------------------------------------------------------- */ struct STRTAB { long nr; char *str; }; struct OVERLAY_CLIP { int x1,x2,y1,y2; }; /* fwd decl */ struct ng_devinfo; struct ng_devstate; /* --------------------------------------------------------------------- */ /* video data structures */ struct ng_video_fmt { unsigned int fmtid; /* VIDEO_* */ unsigned int width; unsigned int height; unsigned int bytesperline; /* zero for compressed formats */ }; enum ng_video_frame { NG_FRAME_UNKNOWN = 0, NG_FRAME_I_FRAME = 1, NG_FRAME_P_FRAME = 2, NG_FRAME_B_FRAME = 3, }; enum ng_video_ratio { // same numbers mpeg2 uses NG_RATIO_UNSPEC = 0, NG_RATIO_SQUARE = 1, NG_RATIO_3_4 = 2, NG_RATIO_9_16 = 3, NG_RATIO_2dot21 = 4, }; struct ng_video_buf { struct ng_video_fmt fmt; size_t size; unsigned char *data; /* meta info for frame */ struct { int64_t ts; /* time stamp */ int file_seq; int play_seq; int twice; enum ng_video_frame frame; enum ng_video_ratio ratio; int broken; int slowdown; } info; /* * the lock is for the reference counter. * if the reference counter goes down to zero release() * should be called. priv is for the owner of the * buffer (can be used by the release callback) */ pthread_mutex_t lock; pthread_cond_t cond; int refcount; void (*release)(struct ng_video_buf *buf); void *priv; }; struct ng_video_fifo { struct list_head next; struct ng_video_buf *buf; }; void ng_init_video_buf(struct ng_video_buf *buf); void ng_release_video_buf(struct ng_video_buf *buf); void ng_print_video_buf(char *tag, struct ng_video_buf *buf); void ng_copy_video_buf(struct ng_video_buf *dst, struct ng_video_buf *src); struct ng_video_buf* ng_malloc_video_buf(void *handle, struct ng_video_fmt *fmt); void ng_wakeup_video_buf(struct ng_video_buf *buf); void ng_waiton_video_buf(struct ng_video_buf *buf); /* --------------------------------------------------------------------- */ /* audio data structures */ struct ng_audio_fmt { unsigned int fmtid; /* AUDIO_* */ unsigned int rate; }; struct ng_audio_buf { struct ng_audio_fmt fmt; int size; int written; /* for partial writes */ char *data; struct { int64_t ts; int broken; int slowdown; } info; }; struct ng_audio_buf* ng_malloc_audio_buf(struct ng_audio_fmt *fmt, int size); void ng_free_audio_buf(struct ng_audio_buf *buf); /* --------------------------------------------------------------------- */ /* someone who receives video and/or audio data (writeavi, ...) */ struct ng_format_list { char *name; char *desc; /* if standard fmtid description doesn't work because it's converted somehow */ char *ext; unsigned int fmtid; void *priv; }; struct ng_writer { const char *name; const char *desc; const struct ng_format_list *video; const struct ng_format_list *audio; const int combined; /* both audio + video in one file */ void* (*wr_open)(char *moviename, char *audioname, struct ng_video_fmt *video, const void *priv_video, int fps, struct ng_audio_fmt *audio, const void *priv_audio); int (*wr_video)(void *handle, struct ng_video_buf *buf); int (*wr_audio)(void *handle, struct ng_audio_buf *buf); int (*wr_close)(void *handle); struct list_head list; }; struct ng_reader { const char *name; const char *desc; char *magic[8]; int moff[8]; int mlen[8]; void* (*rd_open)(char *moviename); struct ng_video_fmt* (*rd_vfmt)(void *handle, int *vfmt, int vn); struct ng_audio_fmt* (*rd_afmt)(void *handle); struct ng_video_buf* (*rd_vdata)(void *handle, unsigned int *drop); struct ng_audio_buf* (*rd_adata)(void *handle); int64_t (*frame_time)(void *handle); int (*rd_close)(void *handle); struct list_head list; }; /* --------------------------------------------------------------------- */ /* attributes */ struct ng_attribute { /* attribute name + identity */ int id; int priority; const char *name; const char *group; /* attribute properties */ int type; int defval; struct STRTAB *choices; /* ATTR_TYPE_CHOICE */ int min,max; /* ATTR_TYPE_INTEGER */ int points; /* ATTR_TYPE_INTEGER -- fixed point */ int (*read)(struct ng_attribute*); void (*write)(struct ng_attribute*, int val); /* attribute owner's data */ void *handle; const void *priv; /* attribute user's data */ struct list_head device_list; struct ng_devstate *dev; struct list_head global_list; void *app; }; struct ng_attribute* ng_attr_byid(struct ng_devstate *dev, int id); struct ng_attribute* ng_attr_byname(struct ng_devstate *dev, char *name); const char* ng_attr_getstr(struct ng_attribute *attr, int value); int ng_attr_getint(struct ng_attribute *attr, char *value); void ng_attr_listchoices(struct ng_attribute *attr); int ng_attr_int2percent(struct ng_attribute *attr, int value); int ng_attr_percent2int(struct ng_attribute *attr, int percent); int ng_attr_parse_int(struct ng_attribute *attr, char *str); /* --------------------------------------------------------------------- */ void ng_ratio_fixup(int *width, int *height, int *xoff, int *yoff); void ng_ratio_fixup2(int *width, int *height, int *xoff, int *yoff, int ratio_x, int ratio_y, int up); /* --------------------------------------------------------------------- */ /* capture/overlay + sound interface drivers */ struct ng_vid_driver { const char *name; int priority; /* open/close */ struct ng_devinfo* (*probe)(int debug); void* (*init)(char *device); int (*open)(void *handle); int (*close)(void *handle); int (*fini)(void *handle); char* (*devname)(void *handle); char* (*busname)(void *handle); /* attributes */ int (*capabilities)(void *handle); struct ng_attribute* (*list_attrs)(void *handle); #if 0 /* overlay */ int (*setupfb)(void *handle, struct ng_video_fmt *fmt, void *base); int (*overlay)(void *handle, struct ng_video_fmt *fmt, int x, int y, struct OVERLAY_CLIP *oc, int count, int aspect); #else int (*overlay)(void *handle, int enable, int aspect, long window, int dw, int dh); #endif /* capture */ int (*setformat)(void *handle, struct ng_video_fmt *fmt); int (*startvideo)(void *handle, int fps, unsigned int buffers); void (*stopvideo)(void *handle); struct ng_video_buf* (*nextframe)(void *handle); /* video frame */ struct ng_video_buf* (*getimage)(void *handle); /* single image */ /* read MPEG stream */ char* (*setup_mpeg)(void *handle, int flags); /* tuner */ unsigned long (*getfreq)(void *handle); void (*setfreq)(void *handle, unsigned long freq); int (*is_tuned)(void *handle); struct list_head list; }; struct ng_dsp_driver { const char *name; int priority; /* open/close */ struct ng_devinfo* (*probe)(int record, int debug); void* (*init)(char *device, int record); int (*open)(void *handle); int (*close)(void *handle); int (*fini)(void *handle); char* (*devname)(void *handle); /* record/playback */ int (*setformat)(void *handle, struct ng_audio_fmt *fmt); int (*fd)(void *handle); int (*startrec)(void *handle); int (*startplay)(void *handle); struct ng_audio_buf* (*read)(void *handle, int64_t stopby); struct ng_audio_buf* (*write)(void *handle, struct ng_audio_buf *buf); int64_t (*latency)(void *handle); struct list_head list; }; struct ng_mix_driver { const char *name; int priority; struct ng_devinfo* (*probe)(int debug); struct ng_devinfo* (*channels)(char *device); void* (*init)(char *device, char *control); int (*open)(void *handle); int (*close)(void *handle); int (*fini)(void *handle); char* (*devname)(void *handle); struct ng_attribute* (*list_attrs)(void *handle); struct list_head list; }; struct ng_devinfo { char device[32]; char name[32]; char bus[32]; int flags; }; struct ng_devstate { enum { NG_DEV_NONE = 0, NG_DEV_VIDEO = 1, NG_DEV_DSP = 2, NG_DEV_MIX = 3, } type; union { struct ng_vid_driver *v; struct ng_dsp_driver *a; struct ng_mix_driver *m; }; char *device; void *handle; struct list_head attrs; int flags; int refcount; }; /* --------------------------------------------------------------------- */ /* frame processing (color space conversion / compression / filtering) */ typedef struct ng_video_buf* (*ng_get_video_buf) (void *handle, struct ng_video_fmt *fmt); typedef struct ng_audio_buf* (*ng_get_audio_buf) (void *handle); enum ng_process_mode { NG_MODE_UNDEF = 0, NG_MODE_TRIVIAL = 1, NG_MODE_COMPLEX = 2, }; struct ng_video_process { enum ng_process_mode mode; /* trivial filters -- one frame in, one frame out */ void (*frame)(void *handle, struct ng_video_buf *out, struct ng_video_buf *in); /* complex filters -- anything trivial can't handle */ void (*setup)(void *handle, ng_get_video_buf get, void *ghandle); void (*put_frame)(void *handle, struct ng_video_buf* buf); struct ng_video_buf* (*get_frame)(void *handle); /* cleanup */ void (*fini)(void *handle); }; struct ng_video_conv { void* (*init)(struct ng_video_fmt *out, void *priv); struct ng_video_process p; unsigned int fmtid_in; unsigned int fmtid_out; void *priv; struct list_head list; }; struct ng_video_filter { void* (*init)(struct ng_video_fmt *fmt); struct ng_video_process p; char *name; int fmts; struct ng_attribute* attrs; struct list_head list; }; struct ng_process_handle; struct ng_process_handle* ng_conv_init(struct ng_video_conv *conv, struct ng_video_fmt *i, struct ng_video_fmt *o); struct ng_process_handle* ng_filter_init(struct ng_video_filter *filter, struct ng_video_fmt *fmt); void ng_process_setup(struct ng_process_handle*, ng_get_video_buf get, void *ghandle); void ng_process_put_frame(struct ng_process_handle*, struct ng_video_buf*); struct ng_video_buf* ng_process_get_frame(struct ng_process_handle*); void ng_process_fini(struct ng_process_handle*); #if 0 struct ng_convert_handle* ng_convert_alloc(struct ng_video_conv *conv, struct ng_video_fmt *i, struct ng_video_fmt *o); void ng_convert_init(struct ng_convert_handle *h); struct ng_video_buf* ng_convert_frame(struct ng_convert_handle *h, struct ng_video_buf *dest, struct ng_video_buf *buf); void ng_convert_fini(struct ng_convert_handle *h); struct ng_video_buf* ng_convert_single(struct ng_convert_handle *h, struct ng_video_buf *in); #endif /* --------------------------------------------------------------------- */ /* audio converters */ struct ng_audio_conv { unsigned int fmtid_in; unsigned int fmtid_out; void* (*init)(void *priv); struct ng_audio_buf* (*data)(void *handle, struct ng_audio_buf *in); void (*fini)(void *handle); void *priv; struct list_head list; }; /* --------------------------------------------------------------------- */ /* must be changed if we break compatibility */ #define NG_PLUGIN_MAGIC 0x20041201 #define __init __attribute__ ((constructor)) #define __fini __attribute__ ((destructor)) #ifndef __used #define __used __attribute__ ((used)) #endif extern struct list_head ng_conv; extern struct list_head ng_aconv; extern struct list_head ng_filters; extern struct list_head ng_writers; extern struct list_head ng_readers; extern struct list_head ng_vid_drivers; extern struct list_head ng_dsp_drivers; extern struct list_head ng_mix_drivers; int ng_conv_register(int magic, char *plugname, struct ng_video_conv *list, int count); int ng_aconv_register(int magic, char *plugname, struct ng_audio_conv *list, int count); int ng_filter_register(int magic, char *plugname, struct ng_video_filter *filter); int ng_writer_register(int magic, char *plugname, struct ng_writer *writer); int ng_reader_register(int magic, char *plugname, struct ng_reader *reader); int ng_vid_driver_register(int magic, char *plugname, struct ng_vid_driver *driver); int ng_dsp_driver_register(int magic, char *plugname, struct ng_dsp_driver *driver); int ng_mix_driver_register(int magic, char *plugname, struct ng_mix_driver *driver); struct ng_video_conv* ng_conv_find_to(unsigned int out, int *i); struct ng_video_conv* ng_conv_find_from(unsigned int out, int *i); struct ng_video_conv* ng_conv_find_match(unsigned int in, unsigned int out); struct ng_devinfo* ng_vid_probe(char *driver); int ng_vid_init(struct ng_devstate *dev, char *device); int ng_dsp_init(struct ng_devstate *dev, char *device, int record); int ng_mix_init(struct ng_devstate *dev, char *device, char *control); int ng_dev_fini(struct ng_devstate *dev); int ng_dev_open(struct ng_devstate *dev); int ng_dev_close(struct ng_devstate *dev); int ng_dev_users(struct ng_devstate *dev); int ng_chardev_open(char *device, int flags, int major, int complain, int is_v4l2); struct ng_reader* ng_find_reader_magic(char *filename); struct ng_reader* ng_find_reader_name(char *name); struct ng_writer* ng_find_writer_name(char *name); int64_t ng_tofday_to_timestamp(struct timeval *tv); int64_t ng_get_timestamp(void); void ng_check_clipping(int width, int height, int xadjust, int yadjust, struct OVERLAY_CLIP *oc, int *count); struct ng_video_buf* ng_filter_single(struct ng_video_filter *filter, struct ng_video_buf *in); /* --------------------------------------------------------------------- */ void ng_init(void); void ng_print_stacktrace(void); void ng_lut_init(unsigned long red_mask, unsigned long green_mask, unsigned long blue_mask, unsigned int fmtid, int swap); void ng_rgb24_to_lut2(unsigned char *dest, unsigned char *src, int p); void ng_rgb24_to_lut4(unsigned char *dest, unsigned char *src, int p); /* --------------------------------------------------------------------- */ /* internal stuff starts here */ #ifdef NG_PRIVATE /* for yuv2rgb using lookup tables (color_lut.c, color_yuv2rgb.c) */ extern int32_t ng_lut_red[256]; extern int32_t ng_lut_green[256]; extern int32_t ng_lut_blue[256]; void ng_yuv422_to_lut2(unsigned char *dest, unsigned char *s, int p); void ng_yuv422_to_lut4(unsigned char *dest, unsigned char *s, int p); void ng_yuv420p_to_lut2(void *h, struct ng_video_buf *out, struct ng_video_buf *in); void ng_yuv420p_to_lut4(void *h, struct ng_video_buf *out, struct ng_video_buf *in); void ng_yuv422p_to_lut2(void *h, struct ng_video_buf *out, struct ng_video_buf *in); void ng_yuv422p_to_lut4(void *h, struct ng_video_buf *out, struct ng_video_buf *in); void yuv2rgb_init(void); void packed_init(void); /* color_common.c stuff */ void* ng_packed_init(struct ng_video_fmt *out, void *priv); void ng_packed_frame(void *handle, struct ng_video_buf *out, struct ng_video_buf *in); void* ng_conv_nop_init(struct ng_video_fmt *out, void *priv); void ng_conv_nop_fini(void *handle); #define NG_GENERIC_PACKED \ .init = ng_packed_init, \ .p.mode = NG_MODE_TRIVIAL, \ .p.frame = ng_packed_frame, \ .p.fini = ng_conv_nop_fini #endif /* NG_PRIVATE */ /* --------------------------------------------------------------------- */ /* * Local variables: * compile-command: "(cd ..; make)" * End: */ amsn-0.98.9/utils/linux/capture/libng/list.h0000644000175000017500000001045410246003435020553 0ustar billiobbilliob#ifndef _LIST_H #define _LIST_H 1 /* * Simple doubly linked list implementation. * -- shameless stolen from the linux kernel sources * * Some of the internal functions ("__xxx") are useful when * manipulating whole lists rather than single entries, as * sometimes we already know the next/prev entries and we can * generate better code by using them directly rather than * using the generic single-entry routines. */ struct list_head { struct list_head *next, *prev; }; #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) #define INIT_LIST_HEAD(ptr) do { \ (ptr)->next = (ptr); (ptr)->prev = (ptr); \ } while (0) /* * Insert a item entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static __inline__ void __list_add(struct list_head * item, struct list_head * prev, struct list_head * next) { next->prev = item; item->next = next; item->prev = prev; prev->next = item; } /** * list_add - add a item entry * @item: item entry to be added * @head: list head to add it after * * Insert a item entry after the specified head. * This is good for implementing stacks. */ static __inline__ void list_add(struct list_head *item, struct list_head *head) { __list_add(item, head, head->next); } /** * list_add_tail - add a item entry * @item: item entry to be added * @head: list head to add it before * * Insert a item entry before the specified head. * This is useful for implementing queues. */ static __inline__ void list_add_tail(struct list_head *item, struct list_head *head) { __list_add(item, head->prev, head); } /* * Delete a list entry by making the prev/next entries * point to each other. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static __inline__ void __list_del(struct list_head * prev, struct list_head * next) { next->prev = prev; prev->next = next; } /** * list_del - deletes entry from list. * @entry: the element to delete from the list. * Note: list_empty on entry does not return true after this, the entry is in an undefined state. */ static __inline__ void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); } /** * list_del_init - deletes entry from list and reinitialize it. * @entry: the element to delete from the list. */ static __inline__ void list_del_init(struct list_head *entry) { __list_del(entry->prev, entry->next); INIT_LIST_HEAD(entry); } /** * list_empty - tests whether a list is empty * @head: the list to test. */ static __inline__ int list_empty(struct list_head *head) { return head->next == head; } /** * list_splice - join two lists * @list: the item list to add. * @head: the place to add it in the first list. */ static __inline__ void list_splice(struct list_head *list, struct list_head *head) { struct list_head *first = list->next; if (first != list) { struct list_head *last = list->prev; struct list_head *at = head->next; first->prev = head; head->next = first; last->next = at; at->prev = last; } } /** * list_entry - get the struct for this entry * @ptr: the &struct list_head pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. */ #define list_entry(ptr, type, member) \ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) /** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. */ #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) /** * list_for_each_safe - iterate over a list safe against removal of list entry * @pos: the &struct list_head to use as a loop counter. * @n: another &struct list_head to use as temporary storage * @head: the head for your list. */ #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) /** * list_for_each_prev - iterate over a list in reverse order * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. */ #define list_for_each_prev(pos, head) \ for (pos = (head)->prev; pos != (head); pos = pos->prev) #endif /* _LIST_H */ amsn-0.98.9/utils/linux/capture/libng/convert.c0000644000175000017500000000772510246003435021262 0ustar billiobbilliob#include "config.h" #include #include #include #include #include "grab-ng.h" struct ng_process_handle { struct ng_video_fmt ifmt; struct ng_video_fmt ofmt; ng_get_video_buf get; void *ghandle; struct ng_video_process *p; void *phandle; struct ng_video_buf *in; }; /*-------------------------------------------------------------------------*/ /* color space conversion / compression helper functions */ static int processes; struct ng_process_handle* ng_conv_init(struct ng_video_conv *conv, struct ng_video_fmt *i, struct ng_video_fmt *o) { struct ng_process_handle *h; h = malloc(sizeof(*h)); if (NULL == h) return NULL; memset(h,0,sizeof(*h)); /* fixup output image size to match incoming */ if (0 == i->bytesperline) i->bytesperline = i->width * ng_vfmt_to_depth[i->fmtid] / 8; o->width = i->width; o->height = i->height; if (0 == o->bytesperline) o->bytesperline = o->width * ng_vfmt_to_depth[o->fmtid] / 8; h->ifmt = *i; h->ofmt = *o; h->p = &conv->p; h->phandle = conv->init(&h->ofmt,conv->priv); switch (h->p->mode) { case NG_MODE_TRIVIAL: case NG_MODE_COMPLEX: break; default: BUG_ON(1,"mode not initialited"); break; } if (ng_debug) { fprintf(stderr,"convert-in : %dx%d %s\n", h->ifmt.width, h->ifmt.height, ng_vfmt_to_desc[h->ifmt.fmtid]); fprintf(stderr,"convert-out: %dx%d %s\n", h->ofmt.width, h->ofmt.height, ng_vfmt_to_desc[h->ofmt.fmtid]); } processes++; return h; } struct ng_process_handle* ng_filter_init(struct ng_video_filter *filter, struct ng_video_fmt *fmt) { struct ng_process_handle *h; if (!(filter->fmts & (1 << fmt->fmtid))) { fprintf(stderr,"filter \"%s\" doesn't support video format \"%s\"\n", filter->name, ng_vfmt_to_desc[fmt->fmtid]); return NULL; } h = malloc(sizeof(*h)); if (NULL == h) return NULL; memset(h,0,sizeof(*h)); h->ifmt = *fmt; h->ofmt = *fmt; h->p = &filter->p; h->phandle = filter->init(fmt); switch (h->p->mode) { case NG_MODE_TRIVIAL: case NG_MODE_COMPLEX: break; default: BUG_ON(1,"mode not initialited"); break; } if (ng_debug) fprintf(stderr,"filtering: %s\n", filter->name); processes++; return h; } void ng_process_setup(struct ng_process_handle *h, ng_get_video_buf get, void *ghandle) { switch (h->p->mode) { case NG_MODE_TRIVIAL: BUG_ON(NULL != h->in, "already have frame"); h->get = get; h->ghandle = ghandle; break; case NG_MODE_COMPLEX: h->p->setup(h->phandle,get,ghandle); break; default: BUG_ON(1,"mode not implemented yet"); break; } } void ng_process_put_frame(struct ng_process_handle *h, struct ng_video_buf* buf) { switch (h->p->mode) { case NG_MODE_TRIVIAL: BUG_ON(NULL != h->in, "already have frame"); h->in = buf; break; case NG_MODE_COMPLEX: h->p->put_frame(h->phandle,buf); break; default: BUG_ON(1,"mode not implemented yet"); break; } } struct ng_video_buf* ng_process_get_frame(struct ng_process_handle *h) { struct ng_video_buf *buf = NULL; switch (h->p->mode) { case NG_MODE_TRIVIAL: BUG_ON(NULL == h->get, "no setup"); if (NULL != h->in) { buf = h->get(h->ghandle, &h->ofmt); #if 0 ng_print_video_buf("in",h->in); ng_print_video_buf("out",buf); #endif h->p->frame(h->phandle, buf, h->in); buf->info = h->in->info; ng_release_video_buf(h->in); h->in = NULL; } break; case NG_MODE_COMPLEX: buf = h->p->get_frame(h->phandle); break; default: BUG_ON(1,"mode not implemented yet"); break; } return buf; } void ng_process_fini(struct ng_process_handle *h) { h->p->fini(h->phandle); free(h); processes--; } static void __fini process_check(void) { OOPS_ON(processes > 0, "processes is %d (expected 0)",processes); } amsn-0.98.9/utils/linux/capture/libng/Rules.mk0000644000175000017500000000152711755465524021074 0ustar billiobbilliobOBJS-libng := \ $(capture_dir)/libng/grab-ng.o \ $(capture_dir)/libng/devices.o \ $(capture_dir)/libng/writefile.o \ $(capture_dir)/libng/parse-mpeg.o \ $(capture_dir)/libng/parse-dvb.o \ $(capture_dir)/libng/color_common.o \ $(capture_dir)/libng/color_packed.o \ $(capture_dir)/libng/color_lut.o \ $(capture_dir)/libng/color_yuv2rgb.o \ $(capture_dir)/libng/convert.o \ $(capture_dir)/libng/misc.o TARGET-libng := $(capture_dir)/libng/libng.so V4L_CFLAGS= ifeq ($(HAVE_LIBV4L),yes) V4L_CFLAGS += -DHAVE_LIBV4L endif $(OBJS-libng): CFLAGS+=-I$(capture_dir) $(V4L_CFLAGS) $(if $(strip ${LIBDIR}),-DLIBDIR=\"${LIBDIR}/$(capture_dir)/libng/plugins\",) $(TARGET-libng): MORE_LIBS=-ldl $(TARGET-libng): $(OBJS-libng) @$(echo_link_so) @$(link_so) all:: $(TARGET-libng) clean:: clean-libng clean-libng: rm -f $(TARGET-libng) $(OBJS-libng) amsn-0.98.9/utils/linux/capture/libng/grab-ng.c0000644000175000017500000006610211755465524021132 0ustar billiobbilliob/* * next generation[tm] xawtv capture interfaces * * (c) 2001 Gerd Knorr * */ #define NG_PRIVATE #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef RTLD_NOW # define RTLD_NOW RTLD_LAZY #endif #include "grab-ng.h" #ifdef HAVE_LIBV4L #include #else #define v4l2_open open #define v4l2_close close #endif int ng_debug = 0; int ng_log_bad_stream = 0; int ng_log_resync = 0; int ng_chromakey = 0x00ff00ff; int ng_ratio_x = 4; int ng_ratio_y = 3; int ng_jpeg_quality = 75; char ng_v4l_conf[256] = "v4l-conf"; /* --------------------------------------------------------------------- */ const unsigned int ng_vfmt_to_depth[VIDEO_FMT_COUNT] = { 0, /* unused */ 8, /* RGB8 */ 8, /* GRAY8 */ 16, /* RGB15 LE */ 16, /* RGB16 LE */ 16, /* RGB15 BE */ 16, /* RGB16 BE */ 24, /* BGR24 */ 32, /* BGR32 */ 24, /* RGB24 */ 32, /* RGB32 */ 16, /* LUT2 */ 32, /* LUT4 */ 16, /* YUYV */ 16, /* YUV422P */ 12, /* YUV420P */ 0, /* MJPEG */ 0, /* JPEG */ 16, /* UYVY */ 0, /* MPEG */ 24, /* BAYER */ 24, /* S910 */ }; const char* ng_vfmt_to_desc[VIDEO_FMT_COUNT] = { "none", "8 bit PseudoColor (dithering)", "8 bit StaticGray", "15 bit TrueColor (LE)", "16 bit TrueColor (LE)", "15 bit TrueColor (BE)", "16 bit TrueColor (BE)", "24 bit TrueColor (LE: bgr)", "32 bit TrueColor (LE: bgr-)", "24 bit TrueColor (BE: rgb)", "32 bit TrueColor (BE: -rgb)", "16 bit TrueColor (lut)", "32 bit TrueColor (lut)", "16 bit YUV 4:2:2 (packed, YUYV)", "16 bit YUV 4:2:2 (planar)", "12 bit YUV 4:2:0 (planar)", "MJPEG (AVI)", "JPEG (JFIF)", "16 bit YUV 4:2:2 (packed, UYVY)", "MPEG video", "Sequential Bayer (BA81)", "SN9C102 Driver Compressed Format (S910)", }; /* --------------------------------------------------------------------- */ const unsigned int ng_afmt_to_channels[AUDIO_FMT_COUNT] = { 0, 1, 2, 1, 2, 1, 2, 0 }; const unsigned int ng_afmt_to_bits[AUDIO_FMT_COUNT] = { 0, 8, 8, 16, 16, 16, 16, 0 }; const char* ng_afmt_to_desc[AUDIO_FMT_COUNT] = { "none", "8bit mono", "8bit stereo", "16bit mono (LE)", "16bit stereo (LE)", "16bit mono (BE)", "16bit stereo (BE)", "MPEG audio", }; /* --------------------------------------------------------------------- */ const char* ng_attr_to_desc[] = { "none", "norm", "input", "volume", "mute", "audio mode", "color", "bright", "hue", "contrast", }; /* --------------------------------------------------------------------- */ void ng_init_video_buf(struct ng_video_buf *buf) { memset(buf,0,sizeof(*buf)); pthread_mutex_init(&buf->lock,NULL); pthread_cond_init(&buf->cond,NULL); } void ng_release_video_buf(struct ng_video_buf *buf) { int release; pthread_mutex_lock(&buf->lock); buf->refcount--; release = (buf->refcount == 0); pthread_mutex_unlock(&buf->lock); if (release && NULL != buf->release) buf->release(buf); } void ng_print_video_buf(char *tag, struct ng_video_buf *buf) { fprintf(stderr,"buf %5s: %dx%d [%s]\n", tag, buf->fmt.width, buf->fmt.height, ng_vfmt_to_desc[buf->fmt.fmtid]); } void ng_copy_video_buf(struct ng_video_buf *dst, struct ng_video_buf *src) { memcpy(dst->data, src->data, src->size); dst->size = src->size; dst->info = src->info; } void ng_wakeup_video_buf(struct ng_video_buf *buf) { pthread_cond_signal(&buf->cond); } void ng_waiton_video_buf(struct ng_video_buf *buf) { pthread_mutex_lock(&buf->lock); while (buf->refcount) pthread_cond_wait(&buf->cond, &buf->lock); pthread_mutex_unlock(&buf->lock); } static int malloc_video_bufs; static int malloc_audio_bufs; static void ng_free_video_buf(struct ng_video_buf *buf) { free(buf->data); free(buf); malloc_video_bufs--; } struct ng_video_buf* ng_malloc_video_buf(void *handle, struct ng_video_fmt *fmt) { struct ng_video_buf *buf; buf = malloc(sizeof(*buf)); if (NULL == buf) return NULL; ng_init_video_buf(buf); buf->fmt = *fmt; buf->size = fmt->height * fmt->bytesperline; if (0 == buf->size) buf->size = fmt->width * fmt->height * 3; buf->data = malloc(buf->size); if (NULL == buf->data) { free(buf); return NULL; } buf->refcount = 1; buf->release = ng_free_video_buf; malloc_video_bufs++; return buf; } struct ng_audio_buf* ng_malloc_audio_buf(struct ng_audio_fmt *fmt, int size) { struct ng_audio_buf *buf; buf = malloc(sizeof(*buf)+size); memset(buf,0,sizeof(*buf)); buf->fmt = *fmt; buf->size = size; buf->data = (char*)buf + sizeof(*buf); malloc_audio_bufs++; return buf; } void ng_free_audio_buf(struct ng_audio_buf *buf) { malloc_audio_bufs--; free(buf); } static void __fini malloc_bufs_check(void) { OOPS_ON(malloc_video_bufs > 0, "malloc_video_bufs is %d (expected 0)", malloc_video_bufs); OOPS_ON(malloc_audio_bufs > 0, "malloc_audio_bufs is %d (expected 0)", malloc_audio_bufs); } /* --------------------------------------------------------------------- */ struct ng_attribute* ng_attr_byid(struct ng_devstate *dev, int id) { struct list_head *item; struct ng_attribute *attr; list_for_each(item, &dev->attrs) { attr = list_entry(item, struct ng_attribute, device_list); if (attr->id == id) return attr; } return NULL; } struct ng_attribute* ng_attr_byname(struct ng_devstate *dev, char *name) { struct list_head *item; struct ng_attribute *attr; list_for_each(item, &dev->attrs) { attr = list_entry(item, struct ng_attribute, device_list); if (0 == strcasecmp(attr->name,name)) return attr; } return NULL; } const char* ng_attr_getstr(struct ng_attribute *attr, int value) { int i; if (NULL == attr) return NULL; if (attr->type != ATTR_TYPE_CHOICE) return NULL; for (i = 0; attr->choices[i].str != NULL; i++) if (attr->choices[i].nr == value) return attr->choices[i].str; return NULL; } int ng_attr_getint(struct ng_attribute *attr, char *value) { int i,val; if (NULL == attr) return -1; if (attr->type != ATTR_TYPE_CHOICE) return -1; for (i = 0; attr->choices[i].str != NULL; i++) { if (0 == strcasecmp(attr->choices[i].str,value)) return attr->choices[i].nr; } if (isdigit(value[0])) { /* Hmm. String not found, but starts with a digit. Check if this is a valid number ... */ val = atoi(value); for (i = 0; attr->choices[i].str != NULL; i++) if (val == attr->choices[i].nr) return attr->choices[i].nr; } return -1; } void ng_attr_listchoices(struct ng_attribute *attr) { int i; fprintf(stderr,"valid choices for \"%s\": ",attr->name); for (i = 0; attr->choices[i].str != NULL; i++) fprintf(stderr,"%s\"%s\"", i ? ", " : "", attr->choices[i].str); fprintf(stderr,"\n"); } int ng_attr_int2percent(struct ng_attribute *attr, int value) { int range,percent; range = attr->max - attr->min; percent = (value - attr->min) * 100 / range; if (percent < 0) percent = 0; if (percent > 100) percent = 100; return percent; } int ng_attr_percent2int(struct ng_attribute *attr, int percent) { int range,value; range = attr->max - attr->min; value = percent * range / 100 + attr->min; if (value < attr->min) value = attr->min; if (value > attr->max) value = attr->max; return value; } int ng_attr_parse_int(struct ng_attribute *attr, char *str) { int value,n; if (0 == sscanf(str,"%d%n",&value,&n)) /* parse error */ return attr->defval; if (str[n] == '%') value = ng_attr_percent2int(attr,value); if (value < attr->min) value = attr->min; if (value > attr->max) value = attr->max; return value; } /* --------------------------------------------------------------------- */ void ng_ratio_fixup(int *width, int *height, int *xoff, int *yoff) { int h = *height; int w = *width; if (0 == ng_ratio_x || 0 == ng_ratio_y) return; if (w * ng_ratio_y < h * ng_ratio_x) { *height = *width * ng_ratio_y / ng_ratio_x; if (yoff) *yoff += (h-*height)/2; } else if (w * ng_ratio_y > h * ng_ratio_x) { *width = *height * ng_ratio_x / ng_ratio_y; if (yoff) *xoff += (w-*width)/2; } } void ng_ratio_fixup2(int *width, int *height, int *xoff, int *yoff, int ratio_x, int ratio_y, int up) { int h = *height; int w = *width; if (0 == ratio_x || 0 == ratio_y) return; if ((!up && w * ratio_y < h * ratio_x) || (up && w * ratio_y > h * ratio_x)) { *height = *width * ratio_y / ratio_x; if (yoff) *yoff += (h-*height)/2; } else if ((!up && w * ratio_y > h * ratio_x) || (up && w * ratio_y < h * ratio_x)) { *width = *height * ratio_x / ratio_y; if (yoff) *xoff += (w-*width)/2; } } /* --------------------------------------------------------------------- */ LIST_HEAD(ng_conv); LIST_HEAD(ng_aconv); LIST_HEAD(ng_filters); LIST_HEAD(ng_writers); LIST_HEAD(ng_readers); LIST_HEAD(ng_vid_drivers); LIST_HEAD(ng_dsp_drivers); LIST_HEAD(ng_mix_drivers); static int ng_check_magic(int magic, char *plugname, char *type) { char *h; h=strrchr(plugname,'/'); if (h) h++; else h=plugname; if (magic != NG_PLUGIN_MAGIC) { fprintf(stderr, "ERROR: plugin magic mismatch [me=%x,%s=%x]\n", NG_PLUGIN_MAGIC,h,magic); return -1; } #if 0 if (ng_debug) fprintf(stderr,"plugins: %s registered by %s\n",type,plugname); #endif return 0; } int ng_conv_register(int magic, char *plugname, struct ng_video_conv *list, int count) { int n; if (0 != ng_check_magic(magic,plugname,"video converters")) return -1; for (n = 0; n < count; n++) list_add_tail(&(list[n].list),&ng_conv); return 0; } int ng_aconv_register(int magic, char *plugname, struct ng_audio_conv *list, int count) { int n; if (0 != ng_check_magic(magic,plugname,"audio converters")) return -1; for (n = 0; n < count; n++) list_add_tail(&(list[n].list),&ng_aconv); return 0; } int ng_filter_register(int magic, char *plugname, struct ng_video_filter *filter) { if (0 != ng_check_magic(magic,plugname,"filter")) return -1; list_add_tail(&filter->list,&ng_filters); return 0; } int ng_writer_register(int magic, char *plugname, struct ng_writer *writer) { if (0 != ng_check_magic(magic,plugname,"writer")) return -1; list_add_tail(&writer->list,&ng_writers); return 0; } int ng_reader_register(int magic, char *plugname, struct ng_reader *reader) { if (0 != ng_check_magic(magic,plugname,"reader")) return -1; list_add_tail(&reader->list,&ng_readers); return 0; } int ng_vid_driver_register(int magic, char *plugname, struct ng_vid_driver *driver) { struct list_head *item; struct ng_vid_driver *drv; if (0 != ng_check_magic(magic,plugname,"video drv")) return -1; list_for_each(item,&ng_vid_drivers) { drv = list_entry(item, struct ng_vid_driver, list); if (drv->priority > driver->priority) { list_add_tail(&driver->list,&drv->list); return 0; } } list_add_tail(&driver->list,&ng_vid_drivers); return 0; } int ng_dsp_driver_register(int magic, char *plugname, struct ng_dsp_driver *driver) { struct list_head *item; struct ng_dsp_driver *drv; if (0 != ng_check_magic(magic,plugname,"dsp drv")) return -1; list_for_each(item,&ng_dsp_drivers) { drv = list_entry(item, struct ng_dsp_driver, list); if (drv->priority > driver->priority) { list_add_tail(&driver->list,&drv->list); return 0; } } list_add_tail(&driver->list,&ng_dsp_drivers); return 0; } int ng_mix_driver_register(int magic, char *plugname, struct ng_mix_driver *driver) { struct list_head *item; struct ng_mix_driver *drv; if (0 != ng_check_magic(magic,plugname,"mixer drv")) return -1; list_for_each(item,&ng_mix_drivers) { drv = list_entry(item, struct ng_mix_driver, list); if (drv->priority > driver->priority) { list_add_tail(&driver->list,&drv->list); return 0; } } list_add_tail(&driver->list,&ng_mix_drivers); return 0; } struct ng_video_conv* ng_conv_find_to(unsigned int out, int *i) { struct list_head *item; struct ng_video_conv *ret; int j = 0; list_for_each(item,&ng_conv) { if (j < *i) { j++; continue; } ret = list_entry(item, struct ng_video_conv, list); #if 0 fprintf(stderr,"\tconv to: %-28s => %s\n", ng_vfmt_to_desc[ret->fmtid_in], ng_vfmt_to_desc[ret->fmtid_out]); #endif if (ret->fmtid_out == out) { (*i)++; return ret; } (*i)++; j++; } return NULL; } struct ng_video_conv* ng_conv_find_from(unsigned int in, int *i) { struct list_head *item; struct ng_video_conv *ret; int j = 0; list_for_each(item,&ng_conv) { if (j < *i) { j++; continue; } ret = list_entry(item, struct ng_video_conv, list); #if 0 fprintf(stderr,"\tconv from: %-28s => %s\n", ng_vfmt_to_desc[ret->fmtid_in], ng_vfmt_to_desc[ret->fmtid_out]); #endif if (ret->fmtid_in == in) { (*i)++; return ret; } } return NULL; } struct ng_video_conv* ng_conv_find_match(unsigned int in, unsigned int out) { struct list_head *item; struct ng_video_conv *ret = NULL; list_for_each(item,&ng_conv) { ret = list_entry(item, struct ng_video_conv, list); if (ret->fmtid_in == in && ret->fmtid_out == out) return ret; } return NULL; } /* --------------------------------------------------------------------- */ int ng_vid_init(struct ng_devstate *dev, char *device) { struct list_head *item; struct ng_vid_driver *drv; struct ng_attribute *attr; void *handle; int i, err = ENODEV; /* check all grabber drivers */ memset(dev,0,sizeof(*dev)); list_for_each(item,&ng_vid_drivers) { drv = list_entry(item, struct ng_vid_driver, list); if (ng_debug) fprintf(stderr,"vid-open: trying: %s... \n", drv->name); if (NULL != (handle = drv->init(device))) break; if (errno) err = errno; if (ng_debug) fprintf(stderr,"vid-open: failed: %s\n",drv->name); } if (item == &ng_vid_drivers) return err; if (ng_debug) fprintf(stderr,"vid-open: ok: %s\n", drv->name); dev->type = NG_DEV_VIDEO; dev->v = drv; dev->handle = handle; dev->device = dev->v->devname(dev->handle); dev->flags = dev->v->capabilities(dev->handle); if (ng_debug) fprintf(stderr,"vid-open: flags: %x\n", dev->flags); INIT_LIST_HEAD(&dev->attrs); attr = dev->v->list_attrs(dev->handle); for (i = 0; attr && attr[i].name; i++) { attr[i].dev = dev; attr[i].group = dev->device; list_add_tail(&attr[i].device_list,&dev->attrs); } return 0; } struct ng_devinfo* ng_vid_probe(char *driver) { struct list_head *item; struct ng_vid_driver *drv; /* check all grabber drivers */ list_for_each(item,&ng_vid_drivers) { drv = list_entry(item, struct ng_vid_driver, list); if (ng_debug) fprintf(stderr,"vid-probe: trying: %s... \n", drv->name); if (strcmp(driver, drv->name)) continue; return drv->probe(ng_debug); } return NULL; } int ng_dsp_init(struct ng_devstate *dev, char *device, int record) { struct list_head *item; struct ng_dsp_driver *drv; void *handle; int err = ENODEV; /* check all dsp drivers */ list_for_each(item,&ng_dsp_drivers) { drv = list_entry(item, struct ng_dsp_driver, list); if (record && NULL == drv->read) continue; if (!record && NULL == drv->write) continue; if (ng_debug) fprintf(stderr, "dsp-open: trying: %s... \n", drv->name); if (NULL != (handle = drv->init(device, record))) break; if (errno) err = errno; if (ng_debug) fprintf(stderr,"dsp-open: failed: %s\n", drv->name); } if (item == &ng_dsp_drivers) return err; if (ng_debug) fprintf(stderr,"dsp-open: ok: %s\n",drv->name); memset(dev,0,sizeof(*dev)); dev->type = NG_DEV_DSP; dev->a = drv; dev->handle = handle; dev->device = dev->a->devname(dev->handle); //dev->flags = dev->a->capabilities(dev->handle); INIT_LIST_HEAD(&dev->attrs); return 0; } int ng_mix_init(struct ng_devstate *dev, char *device, char *control) { struct list_head *item; struct ng_mix_driver *drv; struct ng_attribute *attr; void *handle; int i, err = ENODEV; /* check all dsp drivers */ list_for_each(item,&ng_mix_drivers) { drv = list_entry(item, struct ng_mix_driver, list); if (ng_debug) fprintf(stderr, "mix-open: trying: %s... \n", drv->name); if (NULL != (handle = drv->init(device, control))) break; if (errno) err = errno; if (ng_debug) fprintf(stderr,"mix-open: failed: %s\n", drv->name); } if (item == &ng_mix_drivers) return err; if (ng_debug) fprintf(stderr,"mix-open: ok: %s\n",drv->name); memset(dev,0,sizeof(*dev)); dev->type = NG_DEV_MIX; dev->m = drv; dev->handle = handle; dev->device = dev->m->devname(dev->handle); INIT_LIST_HEAD(&dev->attrs); attr = dev->m->list_attrs(dev->handle); for (i = 0; attr && attr[i].name; i++) { attr[i].dev = dev; attr[i].group = dev->device; list_add_tail(&attr[i].device_list,&dev->attrs); } return 0; } int ng_dev_fini(struct ng_devstate *dev) { switch (dev->type) { case NG_DEV_NONE: /* nothing */ break; case NG_DEV_VIDEO: dev->v->fini(dev->handle); break; case NG_DEV_DSP: dev->a->fini(dev->handle); break; case NG_DEV_MIX: dev->m->fini(dev->handle); break; } memset(dev,0,sizeof(*dev)); return 0; } int ng_dev_open(struct ng_devstate *dev) { int rc = 0; if (0 == dev->refcount) { switch (dev->type) { case NG_DEV_NONE: BUG_ON(1,"dev type NONE"); break; case NG_DEV_VIDEO: rc = dev->v->open(dev->handle); break; case NG_DEV_DSP: rc = dev->a->open(dev->handle); break; case NG_DEV_MIX: rc = dev->m->open(dev->handle); break; } } if (0 == rc) { dev->refcount++; if (ng_debug) fprintf(stderr,"%s: opened %s [refcount %d]\n", __FUNCTION__, dev->device, dev->refcount); } return rc; } int ng_dev_close(struct ng_devstate *dev) { dev->refcount--; BUG_ON(dev->refcount < 0, "refcount below 0"); if (0 == dev->refcount) { switch (dev->type) { case NG_DEV_NONE: BUG_ON(1,"dev type NONE"); break; case NG_DEV_VIDEO: dev->v->close(dev->handle); break; case NG_DEV_DSP: dev->a->close(dev->handle); break; case NG_DEV_MIX: dev->m->close(dev->handle); break; } } if (ng_debug) fprintf(stderr,"%s: closed %s [refcount %d]\n", __FUNCTION__, dev->device, dev->refcount); return 0; } int ng_dev_users(struct ng_devstate *dev) { return dev->refcount; } int ng_chardev_open(char *device, int flags, int major, int complain, int is_v4l2) { struct stat st; int fd = -1; if (strncmp(device, "/dev/", 5)) { if (complain) fprintf(stderr,"%s: not below /dev\n",device); goto err; } if (1 == is_v4l2) { if (-1 == (fd = v4l2_open(device, flags))) { if (complain) fprintf(stderr,"open(%s): %s\n",device,strerror(errno)); goto err; } } else { if (-1 == (fd = open(device, flags))) { if (complain) fprintf(stderr,"open(%s): %s\n",device,strerror(errno)); goto err; } } if (-1 == fstat(fd,&st)) { if (complain) fprintf(stderr,"fstat(%s): %s\n",device,strerror(errno)); goto err; } if (!S_ISCHR(st.st_mode)) { if (complain) fprintf(stderr,"%s: not a charcter device\n",device); goto err; } if (major(st.st_rdev) != major) { if (complain) fprintf(stderr,"%s: wrong major number (expected %d, got %d)\n", device, major, major(st.st_rdev)); goto err; } fcntl(fd,F_SETFD,FD_CLOEXEC); return fd; err: if (-1 != fd) if (1 == is_v4l2) v4l2_close(fd); else close(fd); return -1; } /* --------------------------------------------------------------------- */ struct ng_reader* ng_find_reader_magic(char *filename) { struct list_head *item; struct ng_reader *reader; char blk[512]; FILE *fp; int m; if (NULL == (fp = fopen(filename, "r"))) { fprintf(stderr,"open %s: %s\n",filename,strerror(errno)); return NULL; } memset(blk,0,sizeof(blk)); fread(blk,1,sizeof(blk),fp); fclose(fp); list_for_each(item,&ng_readers) { reader = list_entry(item, struct ng_reader, list); for (m = 0; m < 8 && reader->mlen[m] > 0; m++) { if (0 == memcmp(blk+reader->moff[m],reader->magic[m], reader->mlen[m])) return reader; } } if (ng_debug) fprintf(stderr,"%s: no reader found [magic]\n",filename); return NULL; } struct ng_reader* ng_find_reader_name(char *name) { struct list_head *item; struct ng_reader *reader; list_for_each(item,&ng_readers) { reader = list_entry(item, struct ng_reader, list); if (0 == strcasecmp(reader->name,name)) return reader; } if (ng_debug) fprintf(stderr,"%s: no reader found [name]\n",name); return NULL; } struct ng_writer* ng_find_writer_name(char *name) { struct list_head *item; struct ng_writer *writer; list_for_each(item,&ng_writers) { writer = list_entry(item, struct ng_writer, list); if (0 == strcasecmp(writer->name,name)) return writer; } if (ng_debug) fprintf(stderr,"%s: no writer found [name]\n",name); return NULL; } int64_t ng_tofday_to_timestamp(struct timeval *tv) { long long ts; ts = tv->tv_sec; ts *= 1000000; ts += tv->tv_usec; ts *= 1000; return ts; } int64_t ng_get_timestamp() { struct timeval tv; gettimeofday(&tv,NULL); return ng_tofday_to_timestamp(&tv); } struct ng_video_buf* ng_filter_single(struct ng_video_filter *filter, struct ng_video_buf *in) { struct ng_video_buf *out = in; void *handle; if (NULL != filter && filter->fmts & (1 << in->fmt.fmtid)) { handle = filter->init(&in->fmt); #if 0 BUG_ON(1,"not fixed yet"); out = filter->frame(handle,in); filter->fini(handle); #endif } return out; } /* --------------------------------------------------------------------- */ static void clip_dump(char *state, struct OVERLAY_CLIP *oc, int count) { int i; fprintf(stderr,"clip: %s - %d clips\n",state,count); for (i = 0; i < count; i++) fprintf(stderr,"clip: %d: %dx%d+%d+%d\n",i, oc[i].x2 - oc[i].x1, oc[i].y2 - oc[i].y1, oc[i].x1, oc[i].y1); } static void clip_drop(struct OVERLAY_CLIP *oc, int n, int *count) { (*count)--; memmove(oc+n, oc+n+1, sizeof(struct OVERLAY_CLIP) * (*count-n)); } void ng_check_clipping(int width, int height, int xadjust, int yadjust, struct OVERLAY_CLIP *oc, int *count) { int i,j; if (ng_debug > 1) { fprintf(stderr,"clip: win=%dx%d xa=%d ya=%d\n", width,height,xadjust,yadjust); clip_dump("init",oc,*count); } for (i = 0; i < *count; i++) { /* fixup coordinates */ oc[i].x1 += xadjust; oc[i].x2 += xadjust; oc[i].y1 += yadjust; oc[i].y2 += yadjust; } if (ng_debug > 1) clip_dump("fixup adjust",oc,*count); for (i = 0; i < *count; i++) { /* fixup borders */ if (oc[i].x1 < 0) oc[i].x1 = 0; if (oc[i].x2 < 0) oc[i].x2 = 0; if (oc[i].x1 > width) oc[i].x1 = width; if (oc[i].x2 > width) oc[i].x2 = width; if (oc[i].y1 < 0) oc[i].y1 = 0; if (oc[i].y2 < 0) oc[i].y2 = 0; if (oc[i].y1 > height) oc[i].y1 = height; if (oc[i].y2 > height) oc[i].y2 = height; } if (ng_debug > 1) clip_dump("fixup range",oc,*count); /* drop zero-sized clips */ for (i = 0; i < *count;) { if (oc[i].x1 == oc[i].x2 || oc[i].y1 == oc[i].y2) { clip_drop(oc,i,count); continue; } i++; } if (ng_debug > 1) clip_dump("zerosize done",oc,*count); /* try to merge clips */ restart_merge: for (j = *count - 1; j >= 0; j--) { for (i = 0; i < *count; i++) { if (i == j) continue; if (oc[i].x1 == oc[j].x1 && oc[i].x2 == oc[j].x2 && oc[i].y1 <= oc[j].y1 && oc[i].y2 >= oc[j].y1) { if (ng_debug > 1) fprintf(stderr,"clip: merge y %d,%d\n",i,j); if (oc[i].y2 < oc[j].y2) oc[i].y2 = oc[j].y2; clip_drop(oc,j,count); if (ng_debug > 1) clip_dump("merge y done",oc,*count); goto restart_merge; } if (oc[i].y1 == oc[j].y1 && oc[i].y2 == oc[j].y2 && oc[i].x1 <= oc[j].x1 && oc[i].x2 >= oc[j].x1) { if (ng_debug > 1) fprintf(stderr,"clip: merge x %d,%d\n",i,j); if (oc[i].x2 < oc[j].x2) oc[i].x2 = oc[j].x2; clip_drop(oc,j,count); if (ng_debug > 1) clip_dump("merge x done",oc,*count); goto restart_merge; } } } if (ng_debug) clip_dump("final",oc,*count); } /* --------------------------------------------------------------------- */ #if 0 void ng_print_stacktrace(void) { void *array[16]; size_t size; char **strings; size_t i; size = backtrace(array, DIMOF(array)); strings = backtrace_symbols(array, size); for (i = 0; i < size; i++) fprintf(stderr, "\t%s\n", strings[i]); free(strings); } #endif static int ng_plugins(char *dirname) { struct dirent **list; char filename[1024]; void *plugin; #if 1 void (*initcall)(void); #endif int i,n = 0,l = 0; n = scandir(dirname,&list,NULL,alphasort); if (n <= 0) return 0; for (i = 0; i < n; i++) { if (0 != fnmatch("*.so",list[i]->d_name,0)) continue; sprintf(filename,"%s/%s",dirname,list[i]->d_name); if (NULL == (plugin = dlopen(filename,RTLD_NOW))) { fprintf(stderr,"dlopen: %s\n",dlerror()); continue; } if (NULL == (initcall = dlsym(plugin,"ng_plugin_init"))) { if (NULL == (initcall = dlsym(plugin,"_ng_plugin_init"))) { continue; } } #if 0 initcall(); #endif l++; } for (i = 0; i < n; i++) free(list[i]); free(list); return l; } void ng_init(void) { static int once=0; int count=0; if (once++) { fprintf(stderr,"panic: ng_init called twice\n"); return; } yuv2rgb_init(); packed_init(); /* dirty hack: touch ng_dev to make ld _not_ drop devices.o, it is * needed by various plugins */ if (!ng_dev.video[0]) return; #ifdef LIBDIR count += ng_plugins(LIBDIR); #endif count += ng_plugins("./libng/plugins"); count += ng_plugins("./libng/contrib-plugins"); count += ng_plugins("../libng/plugins"); count += ng_plugins("../libng/contrib-plugins"); count += ng_plugins("./utils/linux/capture/libng/plugins"); count += ng_plugins("./utils/linux/capture/libng/contrib-plugins"); /* if (0 == count) fprintf(stderr,"WARNING: no plugins found [%s]\n",LIBDIR); */ } amsn-0.98.9/utils/linux/capture/libng/README0000644000175000017500000000112510246003435020302 0ustar billiobbilliob WARNING: This is work-in-progress. In the long run I plan to turn this into a v4l capture library. But that isn't finished yet and probably will not for some time. Some documentation can be found in OVERVIEW. Complete reference is not available. I don't care (yet) about backward compatibility. I neither can nor will stop you from using the code. But if you do don't complain if I break your applications with incompatible changes. You have been warned. Please don't distribute this code as shared library. This is just asking for trouble. Gerd -- Gerd Knorr amsn-0.98.9/utils/linux/capture/libng/videodev.h0000644000175000017500000002705510246003435021412 0ustar billiobbilliob#ifndef __LINUX_VIDEODEV_H #define __LINUX_VIDEODEV_H #include #define VID_TYPE_CAPTURE 1 /* Can capture */ #define VID_TYPE_TUNER 2 /* Can tune */ #define VID_TYPE_TELETEXT 4 /* Does teletext */ #define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */ #define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */ #define VID_TYPE_CLIPPING 32 /* Can clip */ #define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */ #define VID_TYPE_SCALES 128 /* Scalable */ #define VID_TYPE_MONOCHROME 256 /* Monochrome only */ #define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */ #define VID_TYPE_MPEG_DECODER 1024 /* Can decode MPEG streams */ #define VID_TYPE_MPEG_ENCODER 2048 /* Can encode MPEG streams */ #define VID_TYPE_MJPEG_DECODER 4096 /* Can decode MJPEG streams */ #define VID_TYPE_MJPEG_ENCODER 8192 /* Can encode MJPEG streams */ struct video_capability { char name[32]; unsigned int type; unsigned int channels; /* Num channels */ unsigned int audios; /* Num audio devices */ unsigned int maxwidth; /* Supported width */ unsigned int maxheight; /* And height */ unsigned int minwidth; /* Supported width */ unsigned int minheight; /* And height */ }; struct video_channel { int channel; char name[32]; int tuners; __u32 flags; #define VIDEO_VC_TUNER 1 /* Channel has a tuner */ #define VIDEO_VC_AUDIO 2 /* Channel has audio */ __u16 type; #define VIDEO_TYPE_TV 1 #define VIDEO_TYPE_CAMERA 2 __u16 norm; /* Norm set by channel */ }; struct video_tuner { int tuner; char name[32]; unsigned long rangelow, rangehigh; /* Tuner range */ __u32 flags; #define VIDEO_TUNER_PAL 1 #define VIDEO_TUNER_NTSC 2 #define VIDEO_TUNER_SECAM 4 #define VIDEO_TUNER_LOW 8 /* Uses KHz not MHz */ #define VIDEO_TUNER_NORM 16 /* Tuner can set norm */ #define VIDEO_TUNER_STEREO_ON 128 /* Tuner is seeing stereo */ #define VIDEO_TUNER_RDS_ON 256 /* Tuner is seeing an RDS datastream */ #define VIDEO_TUNER_MBS_ON 512 /* Tuner is seeing an MBS datastream */ __u16 mode; /* PAL/NTSC/SECAM/OTHER */ #define VIDEO_MODE_PAL 0 #define VIDEO_MODE_NTSC 1 #define VIDEO_MODE_SECAM 2 #define VIDEO_MODE_AUTO 3 __u16 signal; /* Signal strength 16bit scale */ }; struct video_picture { __u16 brightness; __u16 hue; __u16 colour; __u16 contrast; __u16 whiteness; /* Black and white only */ __u16 depth; /* Capture depth */ __u16 palette; /* Palette in use */ #define VIDEO_PALETTE_GREY 1 /* Linear greyscale */ #define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */ #define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */ #define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */ #define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */ #define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */ #define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */ #define VIDEO_PALETTE_YUYV 8 #define VIDEO_PALETTE_UYVY 9 /* The great thing about standards is ... */ #define VIDEO_PALETTE_YUV420 10 #define VIDEO_PALETTE_YUV411 11 /* YUV411 capture */ #define VIDEO_PALETTE_RAW 12 /* RAW capture (BT848) */ #define VIDEO_PALETTE_YUV422P 13 /* YUV 4:2:2 Planar */ #define VIDEO_PALETTE_YUV411P 14 /* YUV 4:1:1 Planar */ #define VIDEO_PALETTE_YUV420P 15 /* YUV 4:2:0 Planar */ #define VIDEO_PALETTE_YUV410P 16 /* YUV 4:1:0 Planar */ #define VIDEO_PALETTE_PLANAR 13 /* start of planar entries */ #define VIDEO_PALETTE_COMPONENT 7 /* start of component entries */ }; struct video_audio { int audio; /* Audio channel */ __u16 volume; /* If settable */ __u16 bass, treble; __u32 flags; #define VIDEO_AUDIO_MUTE 1 #define VIDEO_AUDIO_MUTABLE 2 #define VIDEO_AUDIO_VOLUME 4 #define VIDEO_AUDIO_BASS 8 #define VIDEO_AUDIO_TREBLE 16 #define VIDEO_AUDIO_BALANCE 32 char name[16]; #define VIDEO_SOUND_MONO 1 #define VIDEO_SOUND_STEREO 2 #define VIDEO_SOUND_LANG1 4 #define VIDEO_SOUND_LANG2 8 __u16 mode; __u16 balance; /* Stereo balance */ __u16 step; /* Step actual volume uses */ }; struct video_clip { __s32 x,y; __s32 width, height; struct video_clip *next; /* For user use/driver use only */ }; struct video_window { __u32 x,y; /* Position of window */ __u32 width,height; /* Its size */ __u32 chromakey; __u32 flags; struct video_clip *clips; /* Set only */ int clipcount; #define VIDEO_WINDOW_INTERLACE 1 #define VIDEO_WINDOW_CHROMAKEY 16 /* Overlay by chromakey */ #define VIDEO_CLIP_BITMAP -1 /* bitmap is 1024x625, a '1' bit represents a clipped pixel */ #define VIDEO_CLIPMAP_SIZE (128 * 625) }; struct video_capture { __u32 x,y; /* Offsets into image */ __u32 width, height; /* Area to capture */ __u16 decimation; /* Decimation divider */ __u16 flags; /* Flags for capture */ #define VIDEO_CAPTURE_ODD 0 /* Temporal */ #define VIDEO_CAPTURE_EVEN 1 }; struct video_buffer { void *base; unsigned int height,width; unsigned int depth; unsigned int bytesperline; }; struct video_mmap { unsigned int frame; /* Frame (0 - n) for double buffer */ int height,width; unsigned int format; /* should be VIDEO_PALETTE_* */ }; struct video_key { __u8 key[8]; __u32 flags; }; #define VIDEO_MAX_FRAME 32 struct video_mbuf { int size; /* Total memory to map */ int frames; /* Frames */ int offsets[VIDEO_MAX_FRAME]; }; #define VIDEO_NO_UNIT (-1) struct video_unit { int video; /* Video minor */ int vbi; /* VBI minor */ int radio; /* Radio minor */ int audio; /* Audio minor */ int teletext; /* Teletext minor */ }; struct vbi_format { __u32 sampling_rate; /* in Hz */ __u32 samples_per_line; __u32 sample_format; /* VIDEO_PALETTE_RAW only (1 byte) */ __s32 start[2]; /* starting line for each frame */ __u32 count[2]; /* count of lines for each frame */ __u32 flags; #define VBI_UNSYNC 1 /* can distingues between top/bottom field */ #define VBI_INTERLACED 2 /* lines are interlaced */ }; /* video_info is biased towards hardware mpeg encode/decode */ /* but it could apply generically to any hardware compressor/decompressor */ struct video_info { __u32 frame_count; /* frames output since decode/encode began */ __u32 h_size; /* current unscaled horizontal size */ __u32 v_size; /* current unscaled veritcal size */ __u32 smpte_timecode; /* current SMPTE timecode (for current GOP) */ __u32 picture_type; /* current picture type */ __u32 temporal_reference; /* current temporal reference */ __u8 user_data[256]; /* user data last found in compressed stream */ /* user_data[0] contains user data flags, user_data[1] has count */ }; /* generic structure for setting playback modes */ struct video_play_mode { int mode; int p1; int p2; }; /* for loading microcode / fpga programming */ struct video_code { char loadwhat[16]; /* name or tag of file being passed */ int datasize; __u8 *data; }; #define VIDIOCGCAP _IOR('v',1,struct video_capability) /* Get capabilities */ #define VIDIOCGCHAN _IOWR('v',2,struct video_channel) /* Get channel info (sources) */ #define VIDIOCSCHAN _IOW('v',3,struct video_channel) /* Set channel */ #define VIDIOCGTUNER _IOWR('v',4,struct video_tuner) /* Get tuner abilities */ #define VIDIOCSTUNER _IOW('v',5,struct video_tuner) /* Tune the tuner for the current channel */ #define VIDIOCGPICT _IOR('v',6,struct video_picture) /* Get picture properties */ #define VIDIOCSPICT _IOW('v',7,struct video_picture) /* Set picture properties */ #define VIDIOCCAPTURE _IOW('v',8,int) /* Start, end capture */ #define VIDIOCGWIN _IOR('v',9, struct video_window) /* Get the video overlay window */ #define VIDIOCSWIN _IOW('v',10, struct video_window) /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */ #define VIDIOCGFBUF _IOR('v',11, struct video_buffer) /* Get frame buffer */ #define VIDIOCSFBUF _IOW('v',12, struct video_buffer) /* Set frame buffer - root only */ #define VIDIOCKEY _IOR('v',13, struct video_key) /* Video key event - to dev 255 is to all - cuts capture on all DMA windows with this key (0xFFFFFFFF == all) */ #define VIDIOCGFREQ _IOR('v',14, unsigned long) /* Set tuner */ #define VIDIOCSFREQ _IOW('v',15, unsigned long) /* Set tuner */ #define VIDIOCGAUDIO _IOR('v',16, struct video_audio) /* Get audio info */ #define VIDIOCSAUDIO _IOW('v',17, struct video_audio) /* Audio source, mute etc */ #define VIDIOCSYNC _IOW('v',18, int) /* Sync with mmap grabbing */ #define VIDIOCMCAPTURE _IOW('v',19, struct video_mmap) /* Grab frames */ #define VIDIOCGMBUF _IOR('v',20, struct video_mbuf) /* Memory map buffer info */ #define VIDIOCGUNIT _IOR('v',21, struct video_unit) /* Get attached units */ #define VIDIOCGCAPTURE _IOR('v',22, struct video_capture) /* Get subcapture */ #define VIDIOCSCAPTURE _IOW('v',23, struct video_capture) /* Set subcapture */ #define VIDIOCSPLAYMODE _IOW('v',24, struct video_play_mode) /* Set output video mode/feature */ #define VIDIOCSWRITEMODE _IOW('v',25, int) /* Set write mode */ #define VIDIOCGPLAYINFO _IOR('v',26, struct video_info) /* Get current playback info from hardware */ #define VIDIOCSMICROCODE _IOW('v',27, struct video_code) /* Load microcode into hardware */ #define VIDIOCGVBIFMT _IOR('v',28, struct vbi_format) /* Get VBI information */ #define VIDIOCSVBIFMT _IOW('v',29, struct vbi_format) /* Set VBI information */ #define BASE_VIDIOCPRIVATE 192 /* 192-255 are private */ /* VIDIOCSWRITEMODE */ #define VID_WRITE_MPEG_AUD 0 #define VID_WRITE_MPEG_VID 1 #define VID_WRITE_OSD 2 #define VID_WRITE_TTX 3 #define VID_WRITE_CC 4 #define VID_WRITE_MJPEG 5 /* VIDIOCSPLAYMODE */ #define VID_PLAY_VID_OUT_MODE 0 /* p1: = VIDEO_MODE_PAL, VIDEO_MODE_NTSC, etc ... */ #define VID_PLAY_GENLOCK 1 /* p1: 0 = OFF, 1 = ON */ /* p2: GENLOCK FINE DELAY value */ #define VID_PLAY_NORMAL 2 #define VID_PLAY_PAUSE 3 #define VID_PLAY_SINGLE_FRAME 4 #define VID_PLAY_FAST_FORWARD 5 #define VID_PLAY_SLOW_MOTION 6 #define VID_PLAY_IMMEDIATE_NORMAL 7 #define VID_PLAY_SWITCH_CHANNELS 8 #define VID_PLAY_FREEZE_FRAME 9 #define VID_PLAY_STILL_MODE 10 #define VID_PLAY_MASTER_MODE 11 /* p1: see below */ #define VID_PLAY_MASTER_NONE 1 #define VID_PLAY_MASTER_VIDEO 2 #define VID_PLAY_MASTER_AUDIO 3 #define VID_PLAY_ACTIVE_SCANLINES 12 /* p1 = first active; p2 = last active */ #define VID_PLAY_RESET 13 #define VID_PLAY_END_MARK 14 #define VID_HARDWARE_BT848 1 #define VID_HARDWARE_QCAM_BW 2 #define VID_HARDWARE_PMS 3 #define VID_HARDWARE_QCAM_C 4 #define VID_HARDWARE_PSEUDO 5 #define VID_HARDWARE_SAA5249 6 #define VID_HARDWARE_AZTECH 7 #define VID_HARDWARE_SF16MI 8 #define VID_HARDWARE_RTRACK 9 #define VID_HARDWARE_ZOLTRIX 10 #define VID_HARDWARE_SAA7146 11 #define VID_HARDWARE_VIDEUM 12 /* Reserved for Winnov videum */ #define VID_HARDWARE_RTRACK2 13 #define VID_HARDWARE_PERMEDIA2 14 /* Reserved for Permedia2 */ #define VID_HARDWARE_RIVA128 15 /* Reserved for RIVA 128 */ #define VID_HARDWARE_PLANB 16 /* PowerMac motherboard video-in */ #define VID_HARDWARE_BROADWAY 17 /* Broadway project */ #define VID_HARDWARE_GEMTEK 18 #define VID_HARDWARE_TYPHOON 19 #define VID_HARDWARE_VINO 20 /* SGI Indy Vino */ #define VID_HARDWARE_CADET 21 /* Cadet radio */ #define VID_HARDWARE_TRUST 22 /* Trust FM Radio */ #define VID_HARDWARE_TERRATEC 23 /* TerraTec ActiveRadio */ #define VID_HARDWARE_CPIA 24 #define VID_HARDWARE_ZR36120 25 /* Zoran ZR36120/ZR36125 */ #define VID_HARDWARE_ZR36067 26 /* Zoran ZR36067/36060 */ #define VID_HARDWARE_OV511 27 #define VID_HARDWARE_ZR356700 28 /* Zoran 36700 series */ #define VID_HARDWARE_W9966 29 #define VID_HARDWARE_SE401 30 /* SE401 USB webcams */ #define VID_HARDWARE_PWC 31 /* Philips webcams */ #define VID_HARDWARE_MEYE 32 /* Sony Vaio MotionEye cameras */ #define VID_HARDWARE_CPIA2 33 #define VID_HARDWARE_VICAM 34 #endif /* __LINUX_VIDEODEV_H */ /* * Local variables: * c-basic-offset: 8 * End: */ amsn-0.98.9/utils/linux/capture/libng/videodev2-old.h0000644000175000017500000006454010246003435022250 0ustar billiobbilliob#ifndef __LINUX_VIDEODEV2_H #define __LINUX_VIDEODEV2_H /* * Video for Linux Two * * Header file for v4l or V4L2 drivers and applications, for * Linux kernels 2.2.x or 2.4.x. * * See http://www.thedirks.org/v4l2/ for API specs and other * v4l2 documentation. * * Author: Bill Dirks * Justin Schoeman * et al. */ #define V4L2_MAJOR_VERSION 0 #define V4L2_MINOR_VERSION 20 /* * M I S C E L L A N E O U S */ /* Four-character-code (FOURCC) */ #define v4l2_fourcc(a,b,c,d)\ (((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24)) /* Open flag for non-capturing opens on capture devices */ #define O_NONCAP O_TRUNC #define O_NOIO O_TRUNC /* Timestamp data type, 64-bit signed integer, in nanoseconds */ #ifndef STAMP_T #define STAMP_T typedef __s64 stamp_t; #endif /* * D R I V E R C A P A B I L I T I E S */ struct v4l2_capability { char name[32]; /* Descriptive, and unique */ unsigned int type; /* Device type, see below */ unsigned int inputs; /* Num video inputs */ unsigned int outputs; /* Num video outputs */ unsigned int audios; /* Num audio devices */ unsigned int maxwidth; unsigned int maxheight; unsigned int minwidth; unsigned int minheight; unsigned int maxframerate; __u32 flags; /* Feature flags, see below */ __u32 reserved[4]; }; /* Values for 'type' field */ #define V4L2_TYPE_CAPTURE 0 /* Is a video capture device */ #define V4L2_TYPE_CODEC 1 /* Is a CODEC device */ #define V4L2_TYPE_OUTPUT 2 /* Is a video output device */ #define V4L2_TYPE_FX 3 /* Is a video effects device */ #define V4L2_TYPE_VBI 4 /* Is a VBI capture device */ #define V4L2_TYPE_VTR 5 /* Is a tape recorder controller */ #define V4L2_TYPE_VTX 6 /* Is a teletext device */ #define V4L2_TYPE_RADIO 7 /* Is a radio device */ #define V4L2_TYPE_VBI_INPUT 4 /* Is a VBI capture device */ #define V4L2_TYPE_VBI_OUTPUT 9 /* Is a VBI output device */ #define V4L2_TYPE_PRIVATE 1000 /* Start of driver private types */ /* Flags for 'flags' field */ #define V4L2_FLAG_READ 0x00001 /* Can capture via read() call */ #define V4L2_FLAG_WRITE 0x00002 /* Can accept data via write() */ #define V4L2_FLAG_STREAMING 0x00004 /* Can capture streaming video */ #define V4L2_FLAG_PREVIEW 0x00008 /* Can do automatic preview */ #define V4L2_FLAG_SELECT 0x00010 /* Supports the select() call */ #define V4L2_FLAG_TUNER 0x00020 /* Can tune */ #define V4L2_FLAG_MONOCHROME 0x00040 /* Monochrome only */ #define V4L2_FLAG_DATA_SERVICE 0x00080 /* Has a related data service dev. */ /* * V I D E O I M A G E F O R M A T */ struct v4l2_pix_format { __u32 width; __u32 height; __u32 depth; __u32 pixelformat; __u32 flags; __u32 bytesperline; /* only used when there are pad bytes */ __u32 sizeimage; __u32 priv; /* private data, depends on pixelformat */ }; /* Pixel format FOURCC depth Description */ #define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R','G','B','1') /* 8 RGB-3-3-2 */ #define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R','G','B','O') /* 16 RGB-5-5-5 */ #define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R','G','B','P') /* 16 RGB-5-6-5 */ #define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R','G','B','Q') /* 16 RGB-5-5-5 BE */ #define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R','G','B','R') /* 16 RGB-5-6-5 BE */ #define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B','G','R','3') /* 24 BGR-8-8-8 */ #define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R','G','B','3') /* 24 RGB-8-8-8 */ #define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B','G','R','4') /* 32 BGR-8-8-8-8 */ #define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R','G','B','4') /* 32 RGB-8-8-8-8 */ #define V4L2_PIX_FMT_GREY v4l2_fourcc('G','R','E','Y') /* 8 Greyscale */ #define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y','V','U','9') /* 9 YVU 4:1:0 */ #define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y','V','1','2') /* 12 YVU 4:2:0 */ #define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y','U','Y','V') /* 16 YUV 4:2:2 */ #define V4L2_PIX_FMT_UYVY v4l2_fourcc('U','Y','V','Y') /* 16 YUV 4:2:2 */ #if 0 #define V4L2_PIX_FMT_YVU422P v4l2_fourcc('4','2','2','P') /* 16 YVU422 planar */ #define V4L2_PIX_FMT_YVU411P v4l2_fourcc('4','1','1','P') /* 16 YVU411 planar */ #endif #define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4','2','2','P') /* 16 YVU422 planar */ #define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4','1','1','P') /* 16 YVU411 planar */ #define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y','4','1','P') /* 12 YUV 4:1:1 */ /* two planes -- one Y, one Cr + Cb interleaved */ #define V4L2_PIX_FMT_NV12 v4l2_fourcc('N','V','1','2') /* 12 Y/CbCr 4:2:0 */ #define V4L2_PIX_FMT_NV21 v4l2_fourcc('N','V','2','1') /* 12 Y/CrCb 4:2:0 */ /* The following formats are not defined in the V4L2 specification */ #define V4L2_PIX_FMT_YUV410 v4l2_fourcc('Y','U','V','9') /* 9 YUV 4:1:0 */ #define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y','U','1','2') /* 12 YUV 4:2:0 */ #define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y','Y','U','V') /* 16 YUV 4:2:2 */ #define V4L2_PIX_FMT_HI240 v4l2_fourcc('H','I','2','4') /* 8 8-bit color */ /* Vendor-specific formats */ #define V4L2_PIX_FMT_WNVA v4l2_fourcc('W','N','V','A') /* Winnov hw compres */ /* Flags */ #define V4L2_FMT_FLAG_COMPRESSED 0x0001 /* Compressed format */ #define V4L2_FMT_FLAG_BYTESPERLINE 0x0002 /* bytesperline field valid */ #define V4L2_FMT_FLAG_NOT_INTERLACED 0x0000 #define V4L2_FMT_FLAG_INTERLACED 0x0004 /* Image is interlaced */ #define V4L2_FMT_FLAG_TOPFIELD 0x0008 /* is a top field only */ #define V4L2_FMT_FLAG_BOTFIELD 0x0010 /* is a bottom field only */ #define V4L2_FMT_FLAG_ODDFIELD V4L2_FMT_FLAG_TOPFIELD #define V4L2_FMT_FLAG_EVENFIELD V4L2_FMT_FLAG_BOTFIELD #define V4L2_FMT_FLAG_COMBINED V4L2_FMT_FLAG_INTERLACED #define V4L2_FMT_FLAG_FIELD_field 0x001C #define V4L2_FMT_CS_field 0xF000 /* Color space field mask */ #define V4L2_FMT_CS_601YUV 0x1000 /* ITU YCrCb color space */ #define V4L2_FMT_FLAG_SWCONVERSION 0x0800 /* used only in format enum. */ /* SWCONVERSION indicates the format is not natively supported by the */ /* driver and the driver uses software conversion to support it */ /* * F O R M A T E N U M E R A T I O N */ struct v4l2_fmtdesc { int index; /* Format number */ char description[32]; /* Description string */ __u32 pixelformat; /* Format fourcc */ __u32 flags; /* Format flags */ __u32 depth; /* Bits per pixel */ __u32 reserved[2]; }; struct v4l2_cvtdesc { int index; struct { __u32 pixelformat; __u32 flags; __u32 depth; __u32 reserved[2]; } in, out; }; struct v4l2_fxdesc { int index; char name[32]; __u32 flags; __u32 inputs; __u32 controls; __u32 reserved[2]; }; /* * T I M E C O D E */ struct v4l2_timecode { __u8 frames; __u8 seconds; __u8 minutes; __u8 hours; __u8 userbits[4]; __u32 flags; __u32 type; }; /* Type */ #define V4L2_TC_TYPE_24FPS 1 #define V4L2_TC_TYPE_25FPS 2 #define V4L2_TC_TYPE_30FPS 3 #define V4L2_TC_TYPE_50FPS 4 #define V4L2_TC_TYPE_60FPS 5 /* Flags */ #define V4L2_TC_FLAG_DROPFRAME 0x0001 /* "drop-frame" mode */ #define V4L2_TC_FLAG_COLORFRAME 0x0002 #define V4L2_TC_USERBITS_field 0x000C #define V4L2_TC_USERBITS_USERDEFINED 0x0000 #define V4L2_TC_USERBITS_8BITCHARS 0x0008 /* The above is based on SMPTE timecodes */ /* * C O M P R E S S I O N P A R A M E T E R S */ struct v4l2_compression { int quality; int keyframerate; int pframerate; __u32 reserved[5]; }; /* * M E M O R Y - M A P P I N G B U F F E R S */ struct v4l2_requestbuffers { int count; __u32 type; __u32 reserved[2]; }; struct v4l2_buffer { int index; __u32 type; __u32 offset; __u32 length; __u32 bytesused; __u32 flags; stamp_t timestamp; struct v4l2_timecode timecode; __u32 sequence; __u32 reserved[3]; }; /* Buffer type codes and flags for 'type' field */ #define V4L2_BUF_TYPE_field 0x00001FFF /* Type field mask */ #define V4L2_BUF_TYPE_CAPTURE 0x00000001 #define V4L2_BUF_TYPE_CODECIN 0x00000002 #define V4L2_BUF_TYPE_CODECOUT 0x00000003 #define V4L2_BUF_TYPE_EFFECTSIN 0x00000004 #define V4L2_BUF_TYPE_EFFECTSIN2 0x00000005 #define V4L2_BUF_TYPE_EFFECTSOUT 0x00000006 #define V4L2_BUF_TYPE_VIDEOOUT 0x00000007 #define V4L2_BUF_TYPE_FXCONTROL 0x00000008 #define V4L2_BUF_TYPE_VBI 0x00000009 /* Starting value of driver private buffer types */ #define V4L2_BUF_TYPE_PRIVATE 0x00001000 #define V4L2_BUF_ATTR_DEVICEMEM 0x00010000 /* Buffer is on device (flag) */ /* Flags used only in VIDIOC_REQBUFS */ #define V4L2_BUF_REQ_field 0xF0000000 #define V4L2_BUF_REQ_CONTIG 0x10000000 /* Map all buffers in one contiguous mmap(). This flag only used in VIDIOC_REQBUFS */ /* Flags for 'flags' field */ #define V4L2_BUF_FLAG_MAPPED 0x0001 /* Buffer is mapped (flag) */ #define V4L2_BUF_FLAG_QUEUED 0x0002 /* Buffer is queued for processing */ #define V4L2_BUF_FLAG_DONE 0x0004 /* Buffer is ready */ #define V4L2_BUF_FLAG_KEYFRAME 0x0008 /* Image is a keyframe (I-frame) */ #define V4L2_BUF_FLAG_PFRAME 0x0010 /* Image is a P-frame */ #define V4L2_BUF_FLAG_BFRAME 0x0020 /* Image is a B-frame */ #define V4L2_BUF_FLAG_TOPFIELD 0x0040 /* Image is a top field only */ #define V4L2_BUF_FLAG_BOTFIELD 0x0080 /* Image is a bottom field only */ #define V4L2_BUF_FLAG_ODDFIELD V4L2_BUF_FLAG_TOPFIELD #define V4L2_BUF_FLAG_EVENFIELD V4L2_BUF_FLAG_BOTFIELD #define V4L2_BUF_FLAG_TIMECODE 0x0100 /* timecode field is valid */ /* * O V E R L A Y P R E V I E W */ struct v4l2_framebuffer { __u32 capability; __u32 flags; void *base[3]; struct v4l2_pix_format fmt; }; /* Flags for the 'capability' field. Read only */ #define V4L2_FBUF_CAP_EXTERNOVERLAY 0x0001 #define V4L2_FBUF_CAP_CHROMAKEY 0x0002 #define V4L2_FBUF_CAP_CLIPPING 0x0004 #define V4L2_FBUF_CAP_SCALEUP 0x0008 #define V4L2_FBUF_CAP_SCALEDOWN 0x0010 #define V4L2_FBUF_CAP_BITMAP_CLIPPING 0x0020 /* Flags for the 'flags' field. */ #define V4L2_FBUF_FLAG_PRIMARY 0x0001 #define V4L2_FBUF_FLAG_OVERLAY 0x0002 #define V4L2_FBUF_FLAG_CHROMAKEY 0x0004 struct v4l2_clip { int x; int y; int width; int height; struct v4l2_clip *next; }; struct v4l2_window { int x; int y; unsigned int width; unsigned int height; __u32 chromakey; struct v4l2_clip *clips; int clipcount; void *bitmap; }; /* * D E V I C E P E R F O R M A N C E */ struct v4l2_performance { int frames; int framesdropped; __u64 bytesin; __u64 bytesout; __u32 reserved[4]; }; /* * C A P T U R E P A R A M E T E R S */ struct v4l2_captureparm { __u32 capability; /* Supported modes */ __u32 capturemode; /* Current mode */ unsigned long timeperframe; /* Time per frame in .1us units */ __u32 extendedmode; /* Driver-specific extensions */ __u32 reserved[4]; }; /* Flags for 'capability' and 'capturemode' fields */ #define V4L2_MODE_HIGHQUALITY 0x0001 /* High quality imaging mode */ //#define V4L2_MODE_VFLIP 0x0002 /* Flip image vertically */ //#define V4L2_MODE_HFLIP 0x0004 /* Flip image horizontally */ #define V4L2_CAP_TIMEPERFRAME 0x1000 /* timeperframe field is supported */ struct v4l2_outputparm { __u32 capability; /* Supported modes */ __u32 outputmode; /* Current mode */ unsigned long timeperframe; /* Time per frame in .1us units */ __u32 extendedmode; /* Driver-specific extensions */ __u32 reserved[4]; }; /* * I N P U T I M A G E C R O P P I N G */ struct v4l2_cropcap { __u32 capability; int min_x; int min_y; int max_x; int max_y; int default_left; int default_top; int default_right; int default_bottom; __u32 reserved[2]; }; struct v4l2_crop { int left; int top; int right; int bottom; __u32 reserved; }; /* * D I G I T A L Z O O M */ struct v4l2_zoomcap { __u32 capability; __u32 maxwidth; __u32 maxheight; __u32 minwidth; __u32 minheight; __u32 reserved[2]; }; /* Flags for the capability field */ #define V4L2_ZOOM_NONCAP 0x0001 #define V4L2_ZOOM_WHILESTREAMING 0x0002 struct v4l2_zoom { __u32 x; __u32 y; __u32 width; __u32 height; __u32 reserved; }; /* * A N A L O G V I D E O S T A N D A R D */ struct v4l2_standard { __u8 name[24]; struct { __u32 numerator; __u32 denominator; /* >= 1 */ } framerate; /* Frames, not fields */ __u32 framelines; __u32 reserved1; __u32 colorstandard; union { struct { __u32 colorsubcarrier; /* Hz */ } pal; struct { __u32 colorsubcarrier; /* Hz */ } ntsc; struct { __u32 f0b; /* Hz (blue) */ __u32 f0r; /* Hz (red) */ } secam; __u8 reserved[12]; } colorstandard_data; __u32 transmission; /* Bit field. Must be zero for non-modulators/demodulators. */ __u32 reserved2; /* Must be set to zero */ }; /* Values for the 'colorstandard' field */ #define V4L2_COLOR_STD_PAL 1 #define V4L2_COLOR_STD_NTSC 2 #define V4L2_COLOR_STD_SECAM 3 /* Values for the color subcarrier fields */ #define V4L2_COLOR_SUBC_PAL 4433619 /* PAL BGHI, NTSC-44 */ #define V4L2_COLOR_SUBC_PAL_M 3575611 /* PAL M (Brazil) */ #define V4L2_COLOR_SUBC_PAL_N 3582056 /* PAL N */ #define V4L2_COLOR_SUBC_NTSC 3579545 /* NTSC M, NTSC-Japan */ #define V4L2_COLOR_SUBC_SECAMB 4250000 /* SECAM B - Y carrier */ #define V4L2_COLOR_SUBC_SECAMR 4406250 /* SECAM R - Y carrier */ /* Flags for the 'transmission' field */ #define V4L2_TRANSM_STD_B (1<<1) #define V4L2_TRANSM_STD_D (1<<3) #define V4L2_TRANSM_STD_G (1<<6) #define V4L2_TRANSM_STD_H (1<<7) #define V4L2_TRANSM_STD_I (1<<8) #define V4L2_TRANSM_STD_K (1<<10) #define V4L2_TRANSM_STD_K1 (1<<11) #define V4L2_TRANSM_STD_L (1<<12) #define V4L2_TRANSM_STD_M (1<<13) #define V4L2_TRANSM_STD_N (1<<14) /* Used in the VIDIOC_ENUMSTD ioctl for querying supported standards */ struct v4l2_enumstd { int index; struct v4l2_standard std; __u32 inputs; /* set of inputs that */ /* support this standard */ __u32 outputs; /* set of outputs that */ /* support this standard */ __u32 reserved[2]; }; /* * V I D E O I N P U T S */ struct v4l2_input { int index; /* Which input */ char name[32]; /* Label */ int type; /* Type of input */ __u32 capability; /* Capability flags */ int assoc_audio; /* Associated audio input */ __u32 reserved[4]; }; /* Values for the 'type' field */ #define V4L2_INPUT_TYPE_TUNER 1 #define V4L2_INPUT_TYPE_CAMERA 2 /* Flags for the 'capability' field */ #define V4L2_INPUT_CAP_AUDIO 0x0001 /* assoc_audio */ /* * V I D E O O U T P U T S */ struct v4l2_output { int index; /* Which output */ char name[32]; /* Label */ int type; /* Type of output */ __u32 capability; /* Capability flags */ int assoc_audio; /* Associated audio */ __u32 reserved[4]; }; /* Values for the 'type' field */ #define V4L2_OUTPUT_TYPE_MODULATOR 1 #define V4L2_OUTPUT_TYPE_ANALOG 2 #define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY 3 /* Flags for the 'capability' field */ #define V4L2_OUTPUT_CAP_AUDIO 0x0001 /* assoc_audio */ /* * C O N T R O L S */ struct v4l2_control { __u32 id; int value; }; /* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */ struct v4l2_queryctrl { __u32 id; __u8 name[32]; /* Whatever */ int minimum; /* Note signedness */ int maximum; unsigned int step; int default_value; __u32 type; __u32 flags; __u32 category; /* Automatically filled in by V4L2 */ __u8 group[32]; /* for pre-defined controls */ __u32 reserved[2]; }; /* Used in the VIDIOC_QUERYMENU ioctl for querying menu items */ struct v4l2_querymenu { __u32 id; int index; __u8 name[32]; /* Whatever */ int reserved; }; /* Used in V4L2_BUF_TYPE_FXCONTROL buffers */ struct v4l2_fxcontrol { __u32 id; __u32 value; }; /* Control types */ #define V4L2_CTRL_TYPE_INTEGER 0 #define V4L2_CTRL_TYPE_BOOLEAN 1 #define V4L2_CTRL_TYPE_MENU 2 #define V4L2_CTRL_TYPE_BUTTON 3 /* Control flags */ #define V4L2_CTRL_FLAG_DISABLED 0x0001 #define V4L2_CTRL_FLAG_GRABBED 0x0002 /* Control categories */ #define V4L2_CTRL_CAT_VIDEO 1 /* "Video" */ #define V4L2_CTRL_CAT_AUDIO 2 /* "Audio" */ #define V4L2_CTRL_CAT_EFFECT 3 /* "Effect" */ /* Control IDs defined by V4L2 */ #define V4L2_CID_BASE 0x00980900 /* IDs reserved for driver specific controls */ #define V4L2_CID_PRIVATE_BASE 0x08000000 /* IDs reserved for effect-specific controls on effects devices */ #define V4L2_CID_EFFECT_BASE 0x0A00B000 #define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE+0) #define V4L2_CID_CONTRAST (V4L2_CID_BASE+1) #define V4L2_CID_SATURATION (V4L2_CID_BASE+2) #define V4L2_CID_HUE (V4L2_CID_BASE+3) #define V4L2_CID_AUDIO_VOLUME (V4L2_CID_BASE+5) #define V4L2_CID_AUDIO_BALANCE (V4L2_CID_BASE+6) #define V4L2_CID_AUDIO_BASS (V4L2_CID_BASE+7) #define V4L2_CID_AUDIO_TREBLE (V4L2_CID_BASE+8) #define V4L2_CID_AUDIO_MUTE (V4L2_CID_BASE+9) #define V4L2_CID_AUDIO_LOUDNESS (V4L2_CID_BASE+10) #define V4L2_CID_BLACK_LEVEL (V4L2_CID_BASE+11) #define V4L2_CID_AUTO_WHITE_BALANCE (V4L2_CID_BASE+12) #define V4L2_CID_DO_WHITE_BALANCE (V4L2_CID_BASE+13) #define V4L2_CID_RED_BALANCE (V4L2_CID_BASE+14) #define V4L2_CID_BLUE_BALANCE (V4L2_CID_BASE+15) #define V4L2_CID_GAMMA (V4L2_CID_BASE+16) #define V4L2_CID_WHITENESS (V4L2_CID_GAMMA) /* ? Not sure */ #define V4L2_CID_EXPOSURE (V4L2_CID_BASE+17) #define V4L2_CID_AUTOGAIN (V4L2_CID_BASE+18) #define V4L2_CID_GAIN (V4L2_CID_BASE+19) #define V4L2_CID_HFLIP (V4L2_CID_BASE+20) #define V4L2_CID_VFLIP (V4L2_CID_BASE+21) #define V4L2_CID_HCENTER (V4L2_CID_BASE+22) #define V4L2_CID_VCENTER (V4L2_CID_BASE+23) #define V4L2_CID_LASTP1 (V4L2_CID_BASE+24) /* last CID + 1 */ /* Remember to change fill_ctrl_category() in videodev.c */ /* * T U N I N G */ struct v4l2_tuner { int input; char name[32]; struct v4l2_standard std; __u32 capability; __u32 rangelow; __u32 rangehigh; __u32 rxsubchans; __u32 audmode; int signal; int afc; __u32 reserved[4]; }; struct v4l2_modulator { int output; char name[32]; struct v4l2_standard std; __u32 capability; __u32 rangelow; __u32 rangehigh; __u32 txsubchans; __u32 reserved[4]; }; /* Flags for the 'capability' field */ #define V4L2_TUNER_CAP_LOW 0x0001 #define V4L2_TUNER_CAP_NORM 0x0002 #define V4L2_TUNER_CAP_STEREO 0x0010 #define V4L2_TUNER_CAP_LANG2 0x0020 #define V4L2_TUNER_CAP_SAP 0x0020 #define V4L2_TUNER_CAP_LANG1 0x0040 /* Flags for the 'rxsubchans' field */ #define V4L2_TUNER_SUB_MONO 0x0001 #define V4L2_TUNER_SUB_STEREO 0x0002 #define V4L2_TUNER_SUB_LANG2 0x0004 #define V4L2_TUNER_SUB_SAP 0x0004 #define V4L2_TUNER_SUB_LANG1 0x0008 /* Values for the 'audmode' field */ #define V4L2_TUNER_MODE_MONO 0x0000 #define V4L2_TUNER_MODE_STEREO 0x0001 #define V4L2_TUNER_MODE_LANG2 0x0002 #define V4L2_TUNER_MODE_SAP 0x0002 #define V4L2_TUNER_MODE_LANG1 0x0003 struct v4l2_frequency { int input; __u32 frequency; __u32 reserved[2]; }; /* * A U D I O */ struct v4l2_audio { int audio; char name[32]; __u32 capability; __u32 mode; __u32 reserved[2]; }; /* Flags for the 'capability' field */ #define V4L2_AUDCAP_EFFECTS 0x0020 #define V4L2_AUDCAP_LOUDNESS 0x0040 #define V4L2_AUDCAP_AVL 0x0080 /* Flags for the 'mode' field */ #define V4L2_AUDMODE_LOUDNESS 0x00002 #define V4L2_AUDMODE_AVL 0x00004 #define V4L2_AUDMODE_STEREO_field 0x0FF00 #define V4L2_AUDMODE_STEREO_LINEAR 0x00100 #define V4L2_AUDMODE_STEREO_PSEUDO 0x00200 #define V4L2_AUDMODE_STEREO_SPATIAL30 0x00300 #define V4L2_AUDMODE_STEREO_SPATIAL50 0x00400 struct v4l2_audioout { int audio; char name[32]; __u32 capability; __u32 mode; __u32 reserved[2]; }; /* * D A T A S E R V I C E S ( V B I ) * * Data services API by Michael Schimek */ struct v4l2_vbi_format { __u32 sampling_rate; /* in 1 Hz */ __u32 offset; __u32 samples_per_line; __u32 sample_format; /* V4L2_VBI_SF_* */ __s32 start[2]; __u32 count[2]; __u32 flags; /* V4L2_VBI_* */ __u32 reserved2; /* must be zero */ }; /* VBI sampling formats */ #define V4L2_VBI_SF_UBYTE 1 /* VBI flags */ #define V4L2_VBI_UNSYNC (1<< 0) #define V4L2_VBI_INTERLACED (1<< 1) /* * A G G R E G A T E S T R U C T U R E S */ /* Stream data format */ struct v4l2_format { __u32 type; union { struct v4l2_pix_format pix; /* image format */ struct v4l2_vbi_format vbi; /* VBI data */ /* add more */ __u8 raw_data[200]; /* user-defined */ } fmt; }; /* Stream type-dependent parameters */ struct v4l2_streamparm { __u32 type; union { struct v4l2_captureparm capture; struct v4l2_outputparm output; /* add more */ __u8 raw_data[200]; /* user-defined */ } parm; }; /* * I O C T L C O D E S F O R V I D E O D E V I C E S * */ #define VIDIOC_QUERYCAP _IOR ('V', 0, struct v4l2_capability) #define VIDIOC_RESERVED _IO ('V', 1) #define VIDIOC_ENUM_PIXFMT _IOWR ('V', 2, struct v4l2_fmtdesc) #define VIDIOC_ENUM_FBUFFMT _IOWR ('V', 3, struct v4l2_fmtdesc) #define VIDIOC_G_FMT _IOWR ('V', 4, struct v4l2_format) #define VIDIOC_S_FMT _IOWR ('V', 5, struct v4l2_format) #define VIDIOC_G_COMP _IOR ('V', 6, struct v4l2_compression) #define VIDIOC_S_COMP _IOW ('V', 7, struct v4l2_compression) #define VIDIOC_REQBUFS _IOWR ('V', 8, struct v4l2_requestbuffers) #define VIDIOC_QUERYBUF _IOWR ('V', 9, struct v4l2_buffer) #define VIDIOC_G_FBUF _IOR ('V', 10, struct v4l2_framebuffer) #define VIDIOC_S_FBUF _IOW ('V', 11, struct v4l2_framebuffer) #define VIDIOC_G_WIN _IOR ('V', 12, struct v4l2_window) #define VIDIOC_S_WIN _IOW ('V', 13, struct v4l2_window) #define VIDIOC_PREVIEW _IOWR ('V', 14, int) #define VIDIOC_QBUF _IOWR ('V', 15, struct v4l2_buffer) #define VIDIOC_DQBUF _IOWR ('V', 17, struct v4l2_buffer) #define VIDIOC_STREAMON _IOW ('V', 18, int) #define VIDIOC_STREAMOFF _IOW ('V', 19, int) #define VIDIOC_G_PERF _IOR ('V', 20, struct v4l2_performance) #define VIDIOC_G_PARM _IOWR ('V', 21, struct v4l2_streamparm) #define VIDIOC_S_PARM _IOW ('V', 22, struct v4l2_streamparm) #define VIDIOC_G_STD _IOR ('V', 23, struct v4l2_standard) #define VIDIOC_S_STD _IOW ('V', 24, struct v4l2_standard) #define VIDIOC_ENUMSTD _IOWR ('V', 25, struct v4l2_enumstd) #define VIDIOC_ENUMINPUT _IOWR ('V', 26, struct v4l2_input) #define VIDIOC_G_CTRL _IOWR ('V', 27, struct v4l2_control) #define VIDIOC_S_CTRL _IOW ('V', 28, struct v4l2_control) #define VIDIOC_G_TUNER _IOWR ('V', 29, struct v4l2_tuner) #define VIDIOC_S_TUNER _IOW ('V', 30, struct v4l2_tuner) #define VIDIOC_G_FREQ _IOR ('V', 31, int) #define VIDIOC_S_FREQ _IOWR ('V', 32, int) #define VIDIOC_G_AUDIO _IOWR ('V', 33, struct v4l2_audio) #define VIDIOC_S_AUDIO _IOW ('V', 34, struct v4l2_audio) #define VIDIOC_QUERYCTRL _IOWR ('V', 36, struct v4l2_queryctrl) #define VIDIOC_QUERYMENU _IOWR ('V', 37, struct v4l2_querymenu) #define VIDIOC_G_INPUT _IOR ('V', 38, int) #define VIDIOC_S_INPUT _IOWR ('V', 39, int) #define VIDIOC_ENUMCVT _IOWR ('V', 40, struct v4l2_cvtdesc) #define VIDIOC_G_OUTPUT _IOR ('V', 46, int) #define VIDIOC_S_OUTPUT _IOWR ('V', 47, int) #define VIDIOC_ENUMOUTPUT _IOWR ('V', 48, struct v4l2_output) #define VIDIOC_G_AUDOUT _IOWR ('V', 49, struct v4l2_audioout) #define VIDIOC_S_AUDOUT _IOW ('V', 50, struct v4l2_audioout) #define VIDIOC_ENUMFX _IOWR ('V', 51, struct v4l2_fxdesc) #define VIDIOC_G_EFFECT _IOR ('V', 52, int) #define VIDIOC_S_EFFECT _IOWR ('V', 53, int) #define VIDIOC_G_MODULATOR _IOWR ('V', 54, struct v4l2_modulator) #define VIDIOC_S_MODULATOR _IOW ('V', 55, struct v4l2_modulator) #define VIDIOC_G_FREQUENCY _IOWR ('V', 56, struct v4l2_frequency) #define VIDIOC_S_FREQUENCY _IOW ('V', 57, struct v4l2_frequency) #define VIDIOC_ENUM_CAPFMT VIDIOC_ENUM_PIXFMT #define VIDIOC_ENUM_OUTFMT VIDIOC_ENUM_PIXFMT #define VIDIOC_ENUM_SRCFMT VIDIOC_ENUM_PIXFMT #define VIDIOC_ENUMFMT VIDIOC_ENUM_PIXFMT #define BASE_VIDIOC_PRIVATE 192 /* 192-255 are private */ #ifdef __KERNEL__ /* * * V 4 L 2 D R I V E R H E L P E R A P I * * Some commonly needed functions for drivers. */ extern void v4l2_version(int *major, int *minor); extern int v4l2_major_number(void); extern void v4l2_fill_ctrl_category(struct v4l2_queryctrl *qc); /* Memory management */ extern unsigned long v4l2_vmalloc_to_bus(void *virt); extern struct page *v4l2_vmalloc_to_page(void *virt); /* Simple queue management */ struct v4l2_q_node { struct v4l2_q_node *forw, *back; }; struct v4l2_queue { struct v4l2_q_node *forw, *back; rwlock_t qlock; }; extern void v4l2_q_init(struct v4l2_queue *q); extern void v4l2_q_add_head(struct v4l2_queue *q, struct v4l2_q_node *node); extern void v4l2_q_add_tail(struct v4l2_queue *q, struct v4l2_q_node *node); extern void *v4l2_q_del_head(struct v4l2_queue *q); extern void *v4l2_q_del_tail(struct v4l2_queue *q); extern void *v4l2_q_peek_head(struct v4l2_queue *q); extern void *v4l2_q_peek_tail(struct v4l2_queue *q); extern void *v4l2_q_yank_node(struct v4l2_queue *q, struct v4l2_q_node *node); extern int v4l2_q_last(struct v4l2_queue *q); /* Math functions */ extern u32 v4l2_math_div6432(u64 a, u32 d, u32 *r); /* Time functions */ extern unsigned long v4l2_timestamp_divide(stamp_t t, unsigned long p_100ns); extern unsigned long v4l2_timestamp_correct(stamp_t *t, unsigned long p_100ns); /* Master Clock functions */ struct v4l2_clock { void (*gettime)(stamp_t *); }; extern int v4l2_masterclock_register(struct v4l2_clock *clock); extern void v4l2_masterclock_unregister(struct v4l2_clock *clock); extern void v4l2_masterclock_gettime(stamp_t *curr); /* Video standard functions */ extern unsigned int v4l2_video_std_fps(struct v4l2_standard *vs); extern unsigned long v4l2_video_std_tpf(struct v4l2_standard *vs); extern int v4l2_video_std_confirm(struct v4l2_standard *vs); extern int v4l2_video_std_construct(struct v4l2_standard *vs, int id, __u32 transmission); #define V4L2_STD_PAL 1 /* PAL B, G, H, I (...) */ #define V4L2_STD_PAL_M 5 /* (Brazil) */ #define V4L2_STD_PAL_N 6 /* (Argentina, Paraguay, Uruguay) */ #define V4L2_STD_PAL_60 10 /* PAL/NTSC hybrid */ #define V4L2_STD_NTSC 11 /* NTSC M (USA, ...) */ #define V4L2_STD_NTSC_N 12 /* (Barbados, Bolivia, Colombia, S. Korea) */ #define V4L2_STD_NTSC_44 15 /* PAL/NTSC hybrid */ #define V4L2_STD_SECAM 21 /* SECAM B, D, G, K, K1 (...) */ //#define V4L2_STD_SECAM_H 27 /* (Greece, Iran, Morocco) */ //#define V4L2_STD_SECAM_L 28 /* (France, Luxembourg, Monaco) */ //#define V4L2_STD_SECAM_M 29 /* (Jamaica) */ /* Size of kernel ioctl arg buffer used in ioctl handler */ #define V4L2_MAX_IOCTL_SIZE 256 /* Compatibility layer interface */ typedef int (*v4l2_ioctl_compat)(struct inode *inode, struct file *file, int cmd, void *arg); int v4l2_compat_register(v4l2_ioctl_compat hook); void v4l2_compat_unregister(v4l2_ioctl_compat hook); #endif /* __KERNEL__ */ #endif /* __LINUX_VIDEODEV2_H */ amsn-0.98.9/utils/linux/capture/libng/parse-mpeg.h0000644000175000017500000001360710246003435021643 0ustar billiobbilliob/* * MPEG1/2 transport and program stream parser and demuxer code. * * (c) 2003 Gerd Knorr * */ #include #define TS_SIZE 188 extern int mpeg_rate_n[16]; extern int mpeg_rate_d[16]; extern const char *mpeg_frame_s[]; extern char *psi_charset[0x20]; char *psi_service_type[0x100]; /* ----------------------------------------------------------------------- */ #define PSI_NEW 42 // initial version, valid range is 0 ... 32 #define PSI_STR_MAX 64 struct psi_stream { struct list_head next; int tsid; /* network */ int netid; char net[PSI_STR_MAX]; int frequency; int symbol_rate; char *bandwidth; char *constellation; char *hierarchy; char *code_rate_hp; char *code_rate_lp; char *fec_inner; char *guard; char *transmission; char *polarization; /* status info */ int updated; }; struct psi_program { struct list_head next; int tsid; int pnr; int version; int running; int ca; /* program data */ int type; int p_pid; // program int v_pid; // video int a_pid; // audio int t_pid; // teletext char audio[PSI_STR_MAX]; char net[PSI_STR_MAX]; char name[PSI_STR_MAX]; /* status info */ int updated; int seen; /* hmm ... */ int fd; }; struct psi_info { int tsid; struct list_head streams; struct list_head programs; /* status info */ int pat_updated; /* hmm ... */ struct psi_program *pr; int pat_version; int sdt_version; int nit_version; }; /* ----------------------------------------------------------------------- */ struct ts_packet { unsigned int pid; unsigned int cont; unsigned int tei :1; unsigned int payload :1; unsigned int scramble :2; unsigned int adapt :2; unsigned char *data; unsigned int size; }; struct psc_info { int temp_ref; enum ng_video_frame frame; uint64_t pts; int gop_seen; int dec_seq; int play_seq; }; struct mpeg_handle { int fd; /* file buffer */ int pgsize; unsigned char *buffer; off_t boff; size_t bsize; size_t balloc; int beof; int slowdown; /* error stats */ int errors; int error_out; /* libng format info */ struct ng_video_fmt vfmt; struct ng_audio_fmt afmt; int rate, ratio; /* video frame fifo */ struct list_head vfifo; struct ng_video_buf *vbuf; /* TS packet / PIDs */ struct ts_packet ts; int p_pid; int v_pid; int a_pid; /* parser state */ int init; uint64_t video_pts; uint64_t video_pts_last; uint64_t audio_pts; uint64_t audio_pts_last; off_t video_offset; off_t audio_offset; off_t init_offset; int frames; int gop_seen; int psc_seen; struct psc_info psc; /* current picture */ struct psc_info pts_ref; struct psc_info gop_ref; }; /* ----------------------------------------------------------------------- */ /* handle psi_* */ struct psi_info* psi_info_alloc(void); void psi_info_free(struct psi_info *info); struct psi_stream* psi_stream_get(struct psi_info *info, int tsid, int alloc); struct psi_program* psi_program_get(struct psi_info *info, int tsid, int pnr, int alloc); /* misc */ void hexdump(char *prefix, unsigned char *data, size_t size); void mpeg_dump_desc(unsigned char *desc, int dlen); /* common */ unsigned int mpeg_getbits(unsigned char *buf, int start, int count); struct mpeg_handle* mpeg_init(void); void mpeg_fini(struct mpeg_handle *h); unsigned char* mpeg_get_data(struct mpeg_handle *h, off_t pos, size_t size); size_t mpeg_parse_pes_packet(struct mpeg_handle *h, unsigned char *packet, uint64_t *ts, int *al); int mpeg_get_audio_rate(unsigned char *header); int mpeg_get_video_fmt(struct mpeg_handle *h, unsigned char *header); int mpeg_check_video_fmt(struct mpeg_handle *h, unsigned char *header); unsigned char* mpeg_find_audio_hdr(unsigned char *buf, int off, int size); /* program stream */ size_t mpeg_find_ps_packet(struct mpeg_handle *h, int packet, int mask, off_t *pos); /* transport stream */ void mpeg_parse_psi_string(unsigned char *src, int slen, unsigned char *dest, int dlen); int mpeg_parse_psi_pat(struct psi_info *info, unsigned char *data, int verbose); int mpeg_parse_psi_pmt(struct psi_program *program, unsigned char *data, int verbose); int mpeg_parse_psi(struct psi_info *info, struct mpeg_handle *h, int verbose); int mpeg_find_ts_packet(struct mpeg_handle *h, int wanted, off_t *pos); /* DVB stuff */ int mpeg_parse_psi_sdt(struct psi_info *info, unsigned char *data, int verbose); int mpeg_parse_psi_nit(struct psi_info *info, unsigned char *data, int verbose); amsn-0.98.9/utils/linux/capture/libng/byteswap.h0000644000175000017500000000114110733772533021444 0ustar billiobbilliob#ifndef BYTEORDER_H #define BYTEORDER_H #include #ifdef __sun #include #define BIG_ENDIAN 4321 #define LITTLE_ENDIAN 1234 #ifdef _BIG_ENDIAN #define BYTE_ORDER BIG_ENDIAN #else #define BYTE_ORDER LITTLE_ENDIAN #endif #endif #ifndef BYTE_ORDER # error "Aiee: BYTE_ORDER not defined\n"; #endif #define SWAP2(x) (((x>>8) & 0x00ff) |\ ((x<<8) & 0xff00)) #define SWAP4(x) (((x>>24) & 0x000000ff) |\ ((x>>8) & 0x0000ff00) |\ ((x<<8) & 0x00ff0000) |\ ((x<<24) & 0xff000000)) #endif /* BYTEORDER_H */ amsn-0.98.9/utils/linux/capture/libng/color_lut.c0000644000175000017500000001530210246003435021572 0ustar billiobbilliob/* * colorspace conversion functions * -- translate RGB using lookup tables * * (c) 1998-2001 Gerd Knorr * */ #define NG_PRIVATE #include "config.h" #include #include #include #include #include #include #include #include "grab-ng.h" #include "byteswap.h" int32_t ng_lut_red[256]; int32_t ng_lut_green[256]; int32_t ng_lut_blue[256]; /* ------------------------------------------------------------------- */ void ng_rgb24_to_lut2(unsigned char* restrict dest, unsigned char* restrict src, int p) { uint16_t* restrict d = (uint16_t*)dest; while (p-- > 0) { *(d++) = ng_lut_red[src[0]] | ng_lut_green[src[1]] | ng_lut_blue[src[2]]; src += 3; } } static void bgr24_to_lut2(unsigned char* restrict dest, unsigned char* restrict src, int p) { uint16_t* restrict d = (uint16_t*)dest; while (p-- > 0) { *(d++) = ng_lut_red[src[2]] | ng_lut_green[src[1]] | ng_lut_blue[src[0]]; src += 3; } } static void rgb32_to_lut2(unsigned char* restrict dest, unsigned char* restrict src, int p) { uint16_t* restrict d = (uint16_t*)dest; while (p-- > 0) { *(d++) = ng_lut_red[src[1]] | ng_lut_green[src[2]] | ng_lut_blue[src[3]]; src += 4; } } static void bgr32_to_lut2(unsigned char* restrict dest, unsigned char* restrict src, int p) { uint16_t* restrict d = (uint16_t*)dest; while (p-- > 0) { *(d++) = ng_lut_red[src[2]] | ng_lut_green[src[1]] | ng_lut_blue[src[0]]; src += 4; } } static void gray_to_lut2(unsigned char* restrict dest, unsigned char* restrict src, int p) { uint16_t* restrict d = (uint16_t*)dest; while (p-- > 0) { *(d++) = ng_lut_red[*src] | ng_lut_green[*src] | ng_lut_blue[*src]; src++; } } /* ------------------------------------------------------------------- */ void ng_rgb24_to_lut4(unsigned char* restrict dest, unsigned char* restrict src, int p) { unsigned int* restrict d = (unsigned int*)dest; while (p-- > 0) { *(d++) = ng_lut_red[src[0]] | ng_lut_green[src[1]] | ng_lut_blue[src[2]]; src += 3; } } static void bgr24_to_lut4(unsigned char* restrict dest, unsigned char* restrict src, int p) { unsigned int* restrict d = (unsigned int*)dest; while (p-- > 0) { *(d++) = ng_lut_red[src[2]] | ng_lut_green[src[1]] | ng_lut_blue[src[0]]; src += 3; } } static void rgb32_to_lut4(unsigned char* restrict dest, unsigned char* restrict src, int p) { unsigned int* restrict d = (unsigned int*)dest; while (p-- > 0) { *(d++) = ng_lut_red[src[1]] | ng_lut_green[src[2]] | ng_lut_blue[src[3]]; src += 4; } } static void bgr32_to_lut4(unsigned char* restrict dest, unsigned char* restrict src, int p) { unsigned int* restrict d = (unsigned int*)dest; while (p-- > 0) { *(d++) = ng_lut_red[src[2]] | ng_lut_green[src[1]] | ng_lut_blue[src[0]]; src += 4; } } static void gray_to_lut4(unsigned char* restrict dest, unsigned char* restrict src, int p) { unsigned int* restrict d = (unsigned int*)dest; while (p-- > 0) { *(d++) = ng_lut_red[*src] | ng_lut_green[*src] | ng_lut_blue[*src]; src++; } } /* ------------------------------------------------------------------- */ static struct ng_video_conv lut2_list[] = { { NG_GENERIC_PACKED, .fmtid_in = VIDEO_RGB24, .priv = ng_rgb24_to_lut2, }, { NG_GENERIC_PACKED, .fmtid_in = VIDEO_BGR24, .priv = bgr24_to_lut2, }, { NG_GENERIC_PACKED, .fmtid_in = VIDEO_RGB32, .priv = rgb32_to_lut2, }, { NG_GENERIC_PACKED, .fmtid_in = VIDEO_BGR32, .priv = bgr32_to_lut2, }, { NG_GENERIC_PACKED, .fmtid_in = VIDEO_GRAY, .priv = gray_to_lut2, }, { NG_GENERIC_PACKED, .fmtid_in = VIDEO_YUYV, .priv = ng_yuv422_to_lut2, },{ .init = ng_conv_nop_init, .p.mode = NG_MODE_TRIVIAL, .p.fini = ng_conv_nop_fini, .p.frame = ng_yuv422p_to_lut2, .fmtid_in = VIDEO_YUV422P, },{ .init = ng_conv_nop_init, .p.mode = NG_MODE_TRIVIAL, .p.fini = ng_conv_nop_fini, .p.frame = ng_yuv420p_to_lut2, .fmtid_in = VIDEO_YUV420P, } }; static struct ng_video_conv lut4_list[] = { { NG_GENERIC_PACKED, .fmtid_in = VIDEO_RGB24, .priv = ng_rgb24_to_lut4, }, { NG_GENERIC_PACKED, .fmtid_in = VIDEO_BGR24, .priv = bgr24_to_lut4, }, { NG_GENERIC_PACKED, .fmtid_in = VIDEO_RGB32, .priv = rgb32_to_lut4, }, { NG_GENERIC_PACKED, .fmtid_in = VIDEO_BGR32, .priv = bgr32_to_lut4, }, { NG_GENERIC_PACKED, .fmtid_in = VIDEO_GRAY, .priv = gray_to_lut4, }, { NG_GENERIC_PACKED, .fmtid_in = VIDEO_YUYV, .priv = ng_yuv422_to_lut4, },{ .init = ng_conv_nop_init, .p.mode = NG_MODE_TRIVIAL, .p.fini = ng_conv_nop_fini, .p.frame = ng_yuv422p_to_lut4, .fmtid_in = VIDEO_YUV422P, },{ .init = ng_conv_nop_init, .p.mode = NG_MODE_TRIVIAL, .p.fini = ng_conv_nop_fini, .p.frame = ng_yuv420p_to_lut4, .fmtid_in = VIDEO_YUV420P, } }; static const unsigned int nconv2 = sizeof(lut2_list)/sizeof(lut2_list[0]); static const unsigned int nconv4 = sizeof(lut4_list)/sizeof(lut4_list[0]); static void init_one(int32_t *lut, int32_t mask) { int bits = 0; int shift = 0; int i; for (i = 0; i < 32; i++) { if (mask & ((int32_t)1 << i)) bits++; else if (!bits) shift++; } if (bits > 8) for (i = 0; i < 256; i++) lut[i] = (i << (bits + shift - 8)); else for (i = 0; i < 256; i++) lut[i] = (i >> (8 - bits)) << shift; } void ng_lut_init(unsigned long red_mask, unsigned long green_mask, unsigned long blue_mask, unsigned int fmtid, int swap) { static int once=0; unsigned int i; if (once++) { fprintf(stderr,"panic: ng_lut_init called twice\n"); return; } init_one(ng_lut_red, red_mask); init_one(ng_lut_green, green_mask); init_one(ng_lut_blue, blue_mask); switch (ng_vfmt_to_depth[fmtid]) { case 16: if (swap) { for (i = 0; i < 256; i++) { ng_lut_red[i] = SWAP2(ng_lut_red[i]); ng_lut_green[i] = SWAP2(ng_lut_green[i]); ng_lut_blue[i] = SWAP2(ng_lut_blue[i]); } } for (i = 0; i < nconv2; i++) lut2_list[i].fmtid_out = fmtid; ng_conv_register(NG_PLUGIN_MAGIC,"built-in",lut2_list,nconv2); break; case 32: if (swap) { for (i = 0; i < 256; i++) { ng_lut_red[i] = SWAP4(ng_lut_red[i]); ng_lut_green[i] = SWAP4(ng_lut_green[i]); ng_lut_blue[i] = SWAP4(ng_lut_blue[i]); } } for (i = 0; i < nconv4; i++) lut4_list[i].fmtid_out = fmtid; ng_conv_register(NG_PLUGIN_MAGIC,"built-in",lut4_list,nconv4); break; } } amsn-0.98.9/utils/linux/capture/libng/color_unused.c0000644000175000017500000000217510246003435022275 0ustar billiobbilliob/* ------------------------------------------------------------------- */ /* YUV conversions */ int packed422_to_planar422(unsigned char *d, unsigned char *s, int p) { int i; unsigned char *y,*u,*v; i = p/2; y = d; u = y + p; v = u + p / 2; while (--i) { *(y++) = *(s++); *(u++) = *(s++); *(y++) = *(s++); *(v++) = *(s++); } return p*2; } /* y only, no chroma */ int packed422_to_planar420(unsigned char *d, unsigned char *s, int p) { int i; unsigned char *y; i = p/2; y = d; while (--i) { *(y++) = *(s++); s++; *(y++) = *(s++); s++; } return p*3/2; } #if 0 void x_packed422_to_planar420(unsigned char *d, unsigned char *s, int w, int h) { int a,b; unsigned char *y,*u,*v; y = d; u = y + w * h; v = u + w * h / 4; for (a = h; a > 0; a -= 2) { for (b = w; b > 0; b -= 2) { *(y++) = *(s++); *(u++) = *(s++); *(y++) = *(s++); *(v++) = *(s++); } for (b = w; b > 0; b -= 2) { *(y++) = *(s++); s++; *(y++) = *(s++); s++; } } } #endif amsn-0.98.9/utils/linux/capture/libng/misc.h0000644000175000017500000000055610246003435020535 0ustar billiobbilliob/* --------------------------------------------------------------------- */ /* misc stuff some libc versions have and some don't ... */ #ifndef HAVE_STRCASESTR char* strcasestr(char *haystack, char *needle); #endif #ifndef HAVE_MEMMEM void *memmem(unsigned char *haystack, size_t haystacklen, unsigned char *needle, size_t needlelen); #endif amsn-0.98.9/utils/linux/capture/libng/parse-mpeg.c0000644000175000017500000006370210246003435021637 0ustar billiobbilliob/* * parse mpeg program + transport streams. * */ #include #include #include #include #include #include #include #include #include "grab-ng.h" #include "parse-mpeg.h" #define FILE_BUF_MIN (512*1024) #define FILE_BUF_MAX (8*1024*1024) #define FILE_BLKSIZE (16*1024) #ifndef PRId64 # warning Hmm, your C99 support is incomplete, will guess (should be ok for 32bit archs) # define PRId64 "lld" # define PRIx64 "llx" # define PRIu64 "llu" #endif int ng_mpeg_vpid = 0; int ng_mpeg_apid = 0; int ng_read_timeout = 3; /* seconds */ /* ----------------------------------------------------------------------- */ /* static data */ int mpeg_rate_n[16] = { [ 1 ] = 24000, [ 2 ] = 24000, [ 3 ] = 25000, [ 4 ] = 30000, [ 5 ] = 30000, [ 6 ] = 50000, [ 7 ] = 60000, [ 8 ] = 60000, }; int mpeg_rate_d[16] = { [ 1 ] = 1001, [ 2 ] = 1000, [ 3 ] = 1000, [ 4 ] = 1001, [ 5 ] = 1000, [ 6 ] = 1000, [ 7 ] = 1001, [ 8 ] = 1000, }; static char *rate_s[16] = { [ 0 ] = "illegal", [ 1 ] = "24000/1001", [ 2 ] = "24", [ 3 ] = "25", [ 4 ] = "30000/1001", [ 5 ] = "30", [ 6 ] = "50", [ 7 ] = "60000/1001", [ 8 ] = "60", [ 9 ... 15 ] = "reserved", }; static char *ratio_s[] = { [ 0 ] = "illegal", [ 1 ] = "square sample", [ 2 ] = "3:4", [ 3 ] = "9:16", [ 4 ] = "1:2,21", [ 5 ... 15 ] = "reserved", }; const char *mpeg_frame_s[] = { [ NG_FRAME_UNKNOWN ] = "unknown", [ NG_FRAME_I_FRAME ] = "I frame", [ NG_FRAME_P_FRAME ] = "P frame", [ NG_FRAME_B_FRAME ] = "B frame", }; static const char *pes_s[] = { [ 0x00 ... 0xff ] = "*UNKNOWN* stream", [ 0xbc ] = "program stream map", [ 0xbd ] = "private stream 1", [ 0xbe ] = "padding stream", [ 0xbf ] = "private stream 2", [ 0xc0 ... 0xdf ] = "audio stream", [ 0xe0 ... 0xef ] = "video stream", [ 0xf0 ] = "ECM stream", [ 0xf1 ] = "EMM stream", [ 0xf2 ] = "DSMCC stream", [ 0xf3 ] = "13522 stream", [ 0xf4 ] = "H.222.1 type A", [ 0xf5 ] = "H.222.1 type B", [ 0xf6 ] = "H.222.1 type C", [ 0xf7 ] = "H.222.1 type D", [ 0xf8 ] = "H.222.1 type E", [ 0xf9 ] = "ancillary stream", [ 0xfa ... 0xfe ] = "reserved data stream", [ 0xff ] = "program stream directory", }; static const char *stream_type_s[] = { [ 0x00 ] = "reserved", [ 0x01 ] = "ISO 11172 Video", [ 0x02 ] = "ISO 13818-2 Video", [ 0x03 ] = "ISO 11172 Audio", [ 0x04 ] = "ISO 13818-3 Audio", [ 0x05 ] = "ISO 13818-1 private sections", [ 0x06 ] = "ISO 13818-1 private data", [ 0x07 ] = "ISO 13522 MHEG", [ 0x08 ] = "ISO 13818-1 Annex A DSS CC", [ 0x09 ] = "ITU-T H.222.1", [ 0x0a ] = "ISO 13818-6 type A", [ 0x0b ] = "ISO 13818-6 type B", [ 0x0c ] = "ISO 13818-6 type C", [ 0x0d ] = "ISO 13818-6 type D", [ 0x0e ] = "ISO 13818-6 auxiliary", [ 0x0f ... 0x7f ] = "reserved", [ 0x80 ... 0xff ] = "user private", }; /* ----------------------------------------------------------------------- */ char *psi_charset[0x20] = { [ 0x00 ... 0x1f ] = "reserved", [ 0x00 ] = "ISO-8859-1", [ 0x01 ] = "ISO-8859-5", [ 0x02 ] = "ISO-8859-6", [ 0x03 ] = "ISO-8859-7", [ 0x04 ] = "ISO-8859-8", [ 0x05 ] = "ISO-8859-9", [ 0x06 ] = "ISO-8859-10", [ 0x07 ] = "ISO-8859-11", [ 0x08 ] = "ISO-8859-12", [ 0x09 ] = "ISO-8859-13", [ 0x0a ] = "ISO-8859-14", [ 0x0b ] = "ISO-8859-15", [ 0x10 ] = "fixme", [ 0x11 ] = "UCS-2BE", // correct? [ 0x12 ] = "EUC-KR", [ 0x13 ] = "GB2312", [ 0x14 ] = "BIG5" }; char *psi_service_type[0x100] = { [ 0x00 ... 0xff ] = "reserved", [ 0x80 ... 0xfe ] = "user defined", [ 0x01 ] = "digital television service", [ 0x02 ] = "digital radio sound service", [ 0x03 ] = "teletext service", [ 0x04 ] = "NVOD reference service", [ 0x05 ] = "NVOD time-shifted service", [ 0x06 ] = "mosaic service", [ 0x07 ] = "PAL coded signal", [ 0x08 ] = "SECAM coded signal", [ 0x09 ] = "D/D2-MAC", [ 0x0a ] = "FM Radio", [ 0x0b ] = "NTSC coded signal", [ 0x0c ] = "data broadcast service", [ 0x0d ] = "reserved for CI", [ 0x0e ] = "RCS Map", [ 0x0f ] = "RCS FLS", [ 0x10 ] = "DVB MHP service", }; /* ----------------------------------------------------------------------- */ /* handle psi_ structs */ struct psi_info* psi_info_alloc(void) { struct psi_info *info; info = malloc(sizeof(*info)); memset(info,0,sizeof(*info)); INIT_LIST_HEAD(&info->streams); INIT_LIST_HEAD(&info->programs); info->pat_version = PSI_NEW; info->sdt_version = PSI_NEW; info->nit_version = PSI_NEW; return info; } void psi_info_free(struct psi_info *info) { struct psi_program *program; struct psi_stream *stream; struct list_head *item,*safe; list_for_each_safe(item,safe,&info->streams) { stream = list_entry(item, struct psi_stream, next); list_del(&stream->next); free(stream); } list_for_each_safe(item,safe,&info->programs) { program = list_entry(item, struct psi_program, next); list_del(&program->next); free(program); } free(info); } struct psi_stream* psi_stream_get(struct psi_info *info, int tsid, int alloc) { struct psi_stream *stream; struct list_head *item; list_for_each(item,&info->streams) { stream = list_entry(item, struct psi_stream, next); if (stream->tsid == tsid) return stream; } if (!alloc) return NULL; stream = malloc(sizeof(*stream)); memset(stream,0,sizeof(*stream)); stream->tsid = tsid; stream->updated = 1; list_add_tail(&stream->next,&info->streams); return stream; } struct psi_program* psi_program_get(struct psi_info *info, int tsid, int pnr, int alloc) { struct psi_program *program; struct list_head *item; list_for_each(item,&info->programs) { program = list_entry(item, struct psi_program, next); if (program->tsid == tsid && program->pnr == pnr) return program; } if (!alloc) return NULL; program = malloc(sizeof(*program)); memset(program,0,sizeof(*program)); program->tsid = tsid; program->pnr = pnr; program->version = PSI_NEW; program->updated = 1; list_add_tail(&program->next,&info->programs); return program; } /* ----------------------------------------------------------------------- */ /* bit fiddeling */ unsigned int mpeg_getbits(unsigned char *buf, int start, int count) { unsigned int result = 0; unsigned char bit; while (count) { result <<= 1; bit = 1 << (7 - (start % 8)); result |= (buf[start/8] & bit) ? 1 : 0; start++; count--; } return result; } void hexdump(char *prefix, unsigned char *data, size_t size) { char ascii[17]; int i; for (i = 0; i < size; i++) { if (0 == (i%16)) { fprintf(stderr,"%s%s%04x:", prefix ? prefix : "", prefix ? ": " : "", i); memset(ascii,0,sizeof(ascii)); } if (0 == (i%4)) fprintf(stderr," "); fprintf(stderr," %02x",data[i]); ascii[i%16] = isprint(data[i]) ? data[i] : '.'; if (15 == (i%16)) fprintf(stderr," %s\n",ascii); } if (0 != (i%16)) { while (0 != (i%16)) { if (0 == (i%4)) fprintf(stderr," "); fprintf(stderr," "); i++; }; fprintf(stderr," %s\n",ascii); } } /* ----------------------------------------------------------------------- */ /* common code */ struct mpeg_handle* mpeg_init(void) { struct mpeg_handle *h; h = malloc(sizeof(*h)); if (NULL == h) return NULL; memset(h,0,sizeof(*h)); h->fd = -1; h->pgsize = getpagesize(); h->init = 1; return h; } void mpeg_fini(struct mpeg_handle *h) { if (h->vbuf) ng_release_video_buf(h->vbuf); if (-1 != h->fd) close(h->fd); if (h->buffer) free(h->buffer); free(h); } unsigned char* mpeg_get_data(struct mpeg_handle *h, off_t pos, size_t size) { fd_set set; struct timeval tv; off_t low; size_t rdbytes; int rc; if (pos < h->boff) { /* shouldn't happen */ fprintf(stderr,"mpeg: panic: seek backwards [pos=%ld,boff=%ld]\n", (long)pos,(long)h->boff); exit(1); } low = 0; if (!h->init && pos > h->init_offset*6) { if (h->video_offset > h->init_offset && h->audio_offset > h->init_offset) low = (h->video_offset < h->audio_offset) ? h->video_offset : h->audio_offset; else if (h->audio_offset > h->init_offset) low = h->audio_offset; else if (h->video_offset > h->init_offset) low = h->video_offset; } if (low > h->boff + h->balloc*3/4 && low < h->boff + h->bsize && !h->beof) { /* move data window */ rdbytes = (low - h->boff) & ~(h->pgsize - 1); memmove(h->buffer, h->buffer + rdbytes, h->balloc - rdbytes); h->boff += rdbytes; h->bsize -= rdbytes; if (ng_debug) fprintf(stderr,"mpeg: %dk file buffer shift\n", (int)(rdbytes >> 10)); } while (pos+size + 2*TS_SIZE > h->boff + h->balloc && !h->beof) { /* enlarge buffer */ if (0 == h->bsize) { h->balloc = FILE_BUF_MIN; h->buffer = malloc(h->balloc); } else { h->balloc *= 2; if (h->balloc > FILE_BUF_MAX) { fprintf(stderr,"mpeg: panic: file buffer limit exceeded " "(l=%d,b=%d,v=%d,a=%d)\n", FILE_BUF_MAX,(int)h->balloc, (int)h->video_offset,(int)h->audio_offset); exit(1); } h->buffer = realloc(h->buffer,h->balloc); } if (ng_debug) fprintf(stderr,"mpeg: %dk file buffer\n",(int)(h->balloc >> 10)); } while (pos+size > h->boff + h->bsize) { if (h->beof) return NULL; /* read data */ rdbytes = h->balloc - h->bsize; if (rdbytes > FILE_BLKSIZE) rdbytes = FILE_BLKSIZE; rdbytes -= rdbytes % TS_SIZE; rc = read(h->fd, h->buffer + h->bsize, rdbytes); switch (rc) { case -1: switch (errno) { case EAGAIN: /* must wait for data ... */ if (!h->init) { if (ng_log_resync) fprintf(stderr,"mpeg: sync: must wait for data\n"); h->slowdown++; } FD_ZERO(&set); FD_SET(h->fd,&set); tv.tv_sec = ng_read_timeout; tv.tv_usec = 0; switch (select(h->fd+1,&set,NULL,NULL,&tv)) { case -1: fprintf(stderr,"mpeg: select: %s\n",strerror(errno)); h->beof = 1; break; case 0: fprintf(stderr,"mpeg: select: timeout (%d sec)\n", ng_read_timeout); h->beof = 1; break; } break; case EOVERFLOW: if (ng_log_resync) fprintf(stderr,"mpeg: sync: kernel buffer overflow\n"); break; default: fprintf(stderr,"mpeg: read: %s [%d]\n",strerror(errno),errno); h->beof = 1; break; } break; case 0: if (ng_debug) fprintf(stderr,"mpeg: EOF\n"); h->beof = 1; break; default: h->bsize += rc; break; } } return h->buffer + (pos - h->boff); } size_t mpeg_parse_pes_packet(struct mpeg_handle *h, unsigned char *packet, uint64_t *ts, int *al) { uint64_t pts, dts; int id; size_t size; int i, val; pts = 0; dts = 0; id = 0; *al = 0; for (i = 48; i < 48 + 8*16; i += 8) if (0xff != mpeg_getbits(packet,i,8)) break; if (mpeg_getbits(packet,i,2) == 0x02) { /* MPEG 2 */ id = mpeg_getbits(packet, i-24, 8); *al = mpeg_getbits(packet, i+ 5, 1); size = mpeg_getbits(packet, i+16, 8); size += i/8 + 3; switch (mpeg_getbits(packet, i+8, 2)) { case 3: dts = (uint64_t)mpeg_getbits(packet, i + 68, 3) << 30; dts |= (uint64_t)mpeg_getbits(packet, i + 72, 15) << 15; dts |= (uint64_t)mpeg_getbits(packet, i + 88, 15); /* fall */ case 2: pts = (uint64_t)mpeg_getbits(packet, i + 28, 3) << 30; pts |= (uint64_t)mpeg_getbits(packet, i + 32, 15) << 15; pts |= (uint64_t)mpeg_getbits(packet, i + 48, 15); break; } if (ng_debug > 2) fprintf(stderr,"mpeg2 pes: pl=%d al=%d copy=%d orig=%d ts=%d hl=%d | " " pts=%" PRIx64 " dts=%" PRIx64 " size=%d\n", mpeg_getbits(packet, i - 16, 16), mpeg_getbits(packet, i + 5, 1), mpeg_getbits(packet, i + 6, 1), mpeg_getbits(packet, i + 7, 1), mpeg_getbits(packet, i + 8, 2), mpeg_getbits(packet, i + 16, 8), pts, dts, (int)size); if (ng_debug > 3) { hexdump("mpeg2 pes",packet,32); fprintf(stderr,"--\n"); } } else { /* MPEG 1 */ if (mpeg_getbits(packet,i,2) == 0x01) i += 16; val = mpeg_getbits(packet,i,8); if ((val & 0xf0) == 0x20) { pts = (uint64_t)mpeg_getbits(packet, i + 4, 3) << 30; pts |= (uint64_t)mpeg_getbits(packet, i + 8, 15) << 15; pts |= (uint64_t)mpeg_getbits(packet, i + 24, 15); i += 40; } else if ((val & 0xf0) == 0x30) { pts = (uint64_t)mpeg_getbits(packet, i + 4, 3) << 30; pts |= (uint64_t)mpeg_getbits(packet, i + 8, 15) << 15; pts |= (uint64_t)mpeg_getbits(packet, i + 24, 15); i += 80; } else if (val == 0x0f) i += 8; size = i/8; } if (pts) { if (ng_debug > 1) fprintf(stderr,"pts: %8.3f | id 0x%02x %s\n", pts/90000.0,id,pes_s[id]); if (ts) *ts = pts; } return size; } int mpeg_get_audio_rate(unsigned char *header) { int rate = 44100; if (mpeg_getbits(header,12,1) == 1) { /* MPEG 1.0 */ switch (mpeg_getbits(header,20,2)) { case 0: rate = 44100; break; case 1: rate = 48000; break; case 2: rate = 32000; break; } if (ng_debug) fprintf(stderr,"mpeg: MPEG1 audio, rate %d\n",rate); } else { /* MPEG 2.0 */ switch (mpeg_getbits(header,20,2)) { case 0: rate = 22050; break; case 1: rate = 24000; break; case 2: rate = 16000; break; } if (ng_debug) fprintf(stderr,"mpeg: MPEG2 audio, rate %d\n",rate); } return rate; } unsigned char* mpeg_find_audio_hdr(unsigned char *buf, int off, int size) { int i; for (i = off; i < size-1; i++) { if (0xff != buf[i]) continue; if (0xf0 == (buf[i+1] & 0xf0)) return buf+i; } return NULL; } int mpeg_get_video_fmt(struct mpeg_handle *h, unsigned char *header) { if (header[0] != 0x00 || header[1] != 0x00 || header[2] != 0x01 || header[3] != 0xb3) return -1; h->vfmt.fmtid = VIDEO_MPEG; h->vfmt.width = (mpeg_getbits(header,32,12) + 15) & ~15; h->vfmt.height = (mpeg_getbits(header,44,12) + 15) & ~15; h->ratio = mpeg_getbits(header,56,4); h->rate = mpeg_getbits(header,60,4); if (ng_debug) fprintf(stderr,"mpeg: MPEG video, %dx%d [ratio=%s,rate=%s]\n", h->vfmt.width, h->vfmt.height, ratio_s[h->ratio], rate_s[h->rate]); return 0; } int mpeg_check_video_fmt(struct mpeg_handle *h, unsigned char *header) { int width, height, ratio; int change = 0; if (header[0] != 0x00 || header[1] != 0x00 || header[2] != 0x01 || header[3] != 0xb3) return 0; width = (mpeg_getbits(header,32,12) + 15) & ~15; height = (mpeg_getbits(header,44,12) + 15) & ~15; ratio = mpeg_getbits(header,56,4); if (width != h->vfmt.width || height != h->vfmt.height) { if (ng_debug) fprintf(stderr,"mpeg: size change: %dx%d => %dx%d\n", h->vfmt.width, h->vfmt.height, width, height); change++; } if (ratio != h->ratio) { if (ng_debug) fprintf(stderr,"mpeg: ratio change: %s => %s\n", ratio_s[h->ratio], ratio_s[ratio]); change++; } h->vfmt.height = height; h->vfmt.width = width; h->ratio = ratio; return change; } /* ----------------------------------------------------------------------- */ /* program streams */ size_t mpeg_find_ps_packet(struct mpeg_handle *h, int packet, int mask, off_t *pos) { unsigned char *buf; size_t size; off_t start = *pos; /* read header */ for (;;) { buf = mpeg_get_data(h,*pos,16); if (NULL == buf) return 0; if (buf[0] != 0x00 || buf[1] != 0x00 || buf[2] != 0x01) return 0; size = mpeg_getbits(buf,32,16) + 6; /* handle special cases */ switch (buf[3]) { case 0xba: /* packet start code */ if (0x01 == mpeg_getbits(buf,32,2)) { /* MPEG 2 */ size = 14 + mpeg_getbits(buf,109,3); } else if (0x02 == mpeg_getbits(buf,32,4)) { /* MPEG 1 */ size = 12; } else { /* Huh? */ return 0; } break; case 0xb9: /* mpeg program end code */ return 0; } if (ng_debug > 1) fprintf(stderr,"mpeg: packet 0x%x at 0x%08" PRIx64 "+%d [need 0x%x]\n", (int)buf[3],(int64_t)*pos,(int)size,packet); /* our packet ? */ if ((buf[3] & mask) == packet) return size; *pos += size; /* don't search unlimited ... */ if (*pos - start > FILE_BUF_MIN) return 0; } } /* ----------------------------------------------------------------------- */ /* transport streams */ static void parse_pmt_desc(unsigned char *desc, int dlen, struct psi_program *program, int pid) { int i,t,l; for (i = 0; i < dlen; i += desc[i+1] +2) { t = desc[i]; l = desc[i+1]; switch (t) { case 0x56: if (!program->t_pid) program->t_pid = pid; break; } } } static char* get_lang_tag(unsigned char *desc, int dlen) { int i,t,l; for (i = 0; i < dlen; i += desc[i+1] +2) { t = desc[i]; l = desc[i+1]; if (0x0a == t) return desc+i+2; } return NULL; } static void dump_data(unsigned char *data, int len) { int i; for (i = 0; i < len; i++) { if (isprint(data[i])) fprintf(stderr,"%c", data[i]); else fprintf(stderr,"\\x%02x", (int)data[i]); } } void mpeg_dump_desc(unsigned char *desc, int dlen) { int i,j,t,l,l2,l3; for (i = 0; i < dlen; i += desc[i+1] +2) { t = desc[i]; l = desc[i+1]; switch (t) { case 0x0a: /* ??? (pmt) */ fprintf(stderr," lang=%3.3s",desc+i+2); break; case 0x45: /* vbi data (pmt) */ fprintf(stderr," vbidata="); dump_data(desc+i+2,l); break; case 0x52: /* stream identifier */ fprintf(stderr," sid=%d",(int)desc[i+2]); break; case 0x56: /* teletext (pmt) */ fprintf(stderr," teletext=%3.3s",desc+i+2); break; case 0x59: /* subtitles (pmt) */ fprintf(stderr," subtitles=%3.3s",desc+i+2); break; case 0x6a: /* ac3 (pmt) */ fprintf(stderr," ac3"); break; case 0x40: /* network name (nit) */ fprintf(stderr," name="); dump_data(desc+i+2,l); break; case 0x43: /* satellite delivery system (nit) */ fprintf(stderr," dvb-s"); break; case 0x44: /* cable delivery system (nit) */ fprintf(stderr," dvb-c"); break; case 0x5a: /* terrestrial delivery system (nit) */ fprintf(stderr," dvb-t"); break; case 0x48: /* service (sdt) */ fprintf(stderr," service=%d,",desc[i+2]); l2 = desc[i+3]; dump_data(desc+i+4,desc[i+3]); fprintf(stderr,","); dump_data(desc+i+l2+5,desc[i+l2+4]); break; case 0x4d: /* event (eid) */ fprintf(stderr," short=[%3.3s|",desc+i+2); l2 = desc[i+5]; l3 = desc[i+6+l2]; dump_data(desc+i+6,l2); fprintf(stderr,"|"); dump_data(desc+i+7+l2,l3); fprintf(stderr,"]"); break; case 0x4e: /* event (eid) */ fprintf(stderr," *ext event"); break; case 0x4f: /* event (eid) */ fprintf(stderr," *time shift event"); break; case 0x50: /* event (eid) */ fprintf(stderr," *component"); break; case 0x54: /* event (eid) */ fprintf(stderr," content="); for (j = 0; j < l; j+=2) fprintf(stderr,"%s0x%02x", j ? "," : "", desc[i+j+2]); break; case 0x55: /* event (eid) */ fprintf(stderr," *parental rating"); break; default: fprintf(stderr," %02x[",desc[i]); dump_data(desc+i+2,l); fprintf(stderr,"]"); } } } int mpeg_parse_psi_pat(struct psi_info *info, unsigned char *data, int verbose) { struct list_head *item; struct psi_program *pr; int tsid,pnr,version,current; int j,len,pid; len = mpeg_getbits(data,12,12) + 3 - 4; tsid = mpeg_getbits(data,24,16); version = mpeg_getbits(data,42,5); current = mpeg_getbits(data,47,1); if (!current) return len+4; if (info->tsid == tsid && info->pat_version == version) return len+4; info->tsid = tsid; info->pat_version = version; info->pat_updated = 1; if (verbose) fprintf(stderr, "ts [pat]: tsid %d ver %2d [%d/%d]\n", tsid, version, mpeg_getbits(data,48, 8), mpeg_getbits(data,56, 8)); for (j = 64; j < len*8; j += 32) { pnr = mpeg_getbits(data,j+0,16); pid = mpeg_getbits(data,j+19,13); if (0 == pnr) { /* network */ if (verbose > 1) fprintf(stderr," pid 0x%04x [network]\n", pid); } else { /* program */ pr = psi_program_get(info, tsid, pnr, 1); pr->p_pid = pid; pr->updated = 1; pr->seen = 1; if (NULL == info->pr) info->pr = pr; } } if (verbose > 1) { list_for_each(item,&info->programs) { pr = list_entry(item, struct psi_program, next); if (pr->tsid != tsid) continue; fprintf(stderr," pid 0x%04x => pnr %2d [program map%s]\n", pr->p_pid, pr->pnr, pr->seen ? ",seen" : ""); } fprintf(stderr,"\n"); } return len+4; } int mpeg_parse_psi_pmt(struct psi_program *program, unsigned char *data, int verbose) { int pnr,version,current; int j,len,dlen,type,pid,slen; char *lang; len = mpeg_getbits(data,12,12) + 3 - 4; pnr = mpeg_getbits(data,24,16); version = mpeg_getbits(data,42,5); current = mpeg_getbits(data,47,1); if (!current) return len+4; if (program->pnr == pnr && program->version == version) return len+4; program->version = version; program->updated = 1; dlen = mpeg_getbits(data,84,12); /* TODO: decode descriptor? */ if (verbose) { fprintf(stderr, "ts [pmt]: pnr %d ver %2d [%d/%d] pcr 0x%04x " "pid 0x%04x type %2d #", pnr, version, mpeg_getbits(data,48, 8), mpeg_getbits(data,56, 8), mpeg_getbits(data,69,13), program->p_pid, program->type); mpeg_dump_desc(data + 96/8, dlen); fprintf(stderr,"\n"); } j = 96 + dlen*8; program->v_pid = 0; program->a_pid = 0; program->t_pid = 0; memset(program->audio,0,sizeof(program->audio)); while (j < len*8) { type = mpeg_getbits(data,j,8); pid = mpeg_getbits(data,j+11,13); dlen = mpeg_getbits(data,j+28,12); switch (type) { case 1: case 2: /* video */ if (!program->v_pid) program->v_pid = pid; break; case 3: case 4: /* audio */ if (!program->a_pid) program->a_pid = pid; lang = get_lang_tag(data + (j+40)/8, dlen); slen = strlen(program->audio); snprintf(program->audio + slen, sizeof(program->audio) - slen, "%s%.3s:%d", slen ? " " : "", lang ? lang : "xxx", pid); break; case 6: /* private data */ parse_pmt_desc(data + (j+40)/8, dlen, program, pid); break; } if (verbose > 1) { fprintf(stderr, " pid 0x%04x => %-32s #", pid, stream_type_s[type]); mpeg_dump_desc(data + (j+40)/8, dlen); fprintf(stderr,"\n"); } j += 40 + dlen*8; } if (verbose > 1) fprintf(stderr,"\n"); return len+4; } int mpeg_parse_psi(struct psi_info *info, struct mpeg_handle *h, int verbose) { int i,tid; if (h->ts.payload) { for (i = h->ts.data[0]+1; i < h->ts.size;) { tid = mpeg_getbits(h->ts.data,i*8,8); switch (tid) { case 0: i += mpeg_parse_psi_pat(info, h->ts.data+i, verbose); break; case 1: fprintf(stderr, "ts: conditional access\n"); return 0; case 2: i += mpeg_parse_psi_pmt(info->pr, h->ts.data+i, verbose); break; case 3: fprintf(stderr, "ts: description\n"); return 0; case 0xff: /* end of data */ return 0; default: fprintf(stderr, "ts: unknown table id %d\n",tid); return 0; } } } return 0; } /* ----------------------------------------------------------------------- */ int mpeg_find_ts_packet(struct mpeg_handle *h, int wanted, off_t *pos) { unsigned char *packet; int asize = 0; off_t start; for (start = *pos; *pos - start < FILE_BUF_MIN; *pos += TS_SIZE) { memset(&h->ts, 0, sizeof(h->ts)); packet = mpeg_get_data(h, *pos, TS_SIZE); if (NULL == packet) { fprintf(stderr,"mpeg ts: no more data\n"); return -1; } if (packet[0] != 0x47) { if (ng_log_bad_stream) fprintf(stderr,"mpeg ts: warning %d: packet id mismatch\n", h->errors); h->errors++; continue; } h->ts.tei = mpeg_getbits(packet, 8,1); h->ts.payload = mpeg_getbits(packet, 9,1); h->ts.pid = mpeg_getbits(packet,11,13); h->ts.scramble = mpeg_getbits(packet,24,2); h->ts.adapt = mpeg_getbits(packet,26,2); h->ts.cont = mpeg_getbits(packet,28,4); if (0 == h->ts.adapt) /* reserved -- should discard */ continue; if (0x1fff == h->ts.pid) /* NULL packet -- discard */ continue; if (h->ts.pid != wanted) /* need something else */ continue; switch (h->ts.adapt) { case 3: /* adaptation + payload */ asize = mpeg_getbits(packet,32,8) +1; h->ts.data = packet + (4 + asize); h->ts.size = TS_SIZE - (4 + asize); if (h->ts.size > TS_SIZE) { if (ng_log_bad_stream) fprintf(stderr,"mpeg ts: warning %d: broken adaptation" " size [%lx]\n",h->errors,(unsigned long)(*pos)); h->errors++; continue; } /* fall throuth */ case 2: /* adaptation only */ /* TODO: parse adaptation field */ break; case 1: /* payload only */ h->ts.data = packet + 4; h->ts.size = TS_SIZE - 4; break; } if (ng_debug > 2) fprintf(stderr,"mpeg ts: pl=%d pid=%d adapt=%d cont=%d size=%d [%d]\n", h->ts.payload, h->ts.pid, h->ts.adapt, h->ts.cont, h->ts.size, asize); return 0; } return -1; } amsn-0.98.9/utils/linux/capture/libng/plugins/0000755000175000017500000000000011757711632021121 5ustar billiobbilliobamsn-0.98.9/utils/linux/capture/libng/plugins/drv0-v4l2-old.c0000644000175000017500000010253210246003435023467 0ustar billiobbilliob/* * interface to the v4l2 driver * * (c) 1998-2002 Gerd Knorr * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* XXX glibc */ #include "videodev2-old.h" #include "grab-ng.h" /* ---------------------------------------------------------------------- */ /* open+close */ static void* v4l2_open(char *device); static int v4l2_close(void *handle); /* attributes */ static char* v4l2_devname(void *handle); static int v4l2_flags(void *handle); static struct ng_attribute* v4l2_attrs(void *handle); static int v4l2_read_attr(struct ng_attribute*); static void v4l2_write_attr(struct ng_attribute*, int val); /* overlay */ static int v4l2_setupfb(void *handle, struct ng_video_fmt *fmt, void *base); static int v4l2_overlay(void *handle, struct ng_video_fmt *fmt, int x, int y, struct OVERLAY_CLIP *oc, int count, int aspect); /* capture video */ static int v4l2_setformat(void *handle, struct ng_video_fmt *fmt); static int v4l2_startvideo(void *handle, int fps, unsigned int buffers); static void v4l2_stopvideo(void *handle); static struct ng_video_buf* v4l2_nextframe(void *handle); static struct ng_video_buf* v4l2_getimage(void *handle); /* tuner */ static unsigned long v4l2_getfreq(void *handle); static void v4l2_setfreq(void *handle, unsigned long freq); static int v4l2_tuned(void *handle); /* ---------------------------------------------------------------------- */ #define WANTED_BUFFERS 32 #define MAX_INPUT 16 #define MAX_NORM 16 #define MAX_FORMAT 32 #define MAX_CTRL 32 struct v4l2_handle { int fd; /* device descriptions */ unsigned int ninputs,nstds,nfmts; struct v4l2_capability cap; struct v4l2_streamparm streamparm; struct v4l2_input inp[MAX_INPUT]; struct v4l2_enumstd std[MAX_NORM]; struct v4l2_fmtdesc fmt[MAX_FORMAT]; struct v4l2_queryctrl ctl[MAX_CTRL*2]; /* attributes */ int nattr; struct ng_attribute *attr; /* capture */ int fps,first; long long start; struct v4l2_format fmt_v4l2; struct ng_video_fmt fmt_me; struct v4l2_requestbuffers reqbufs; struct v4l2_buffer buf_v4l2[WANTED_BUFFERS]; struct ng_video_buf buf_me[WANTED_BUFFERS]; int queue,waiton; /* overlay */ struct v4l2_framebuffer ov_fb; struct v4l2_window ov_win; struct v4l2_clip ov_clips[256]; int ov_error; int ov_enabled; int ov_on; }; /* ---------------------------------------------------------------------- */ struct ng_vid_driver v4l2_driver = { name: "v4l2-old", open: v4l2_open, close: v4l2_close, get_devname: v4l2_devname, capabilities: v4l2_flags, list_attrs: v4l2_attrs, setupfb: v4l2_setupfb, overlay: v4l2_overlay, setformat: v4l2_setformat, startvideo: v4l2_startvideo, stopvideo: v4l2_stopvideo, nextframe: v4l2_nextframe, getimage: v4l2_getimage, getfreq: v4l2_getfreq, setfreq: v4l2_setfreq, is_tuned: v4l2_tuned, }; static __u32 xawtv_pixelformat[VIDEO_FMT_COUNT] = { 0, /* unused */ V4L2_PIX_FMT_HI240, /* RGB8 */ V4L2_PIX_FMT_GREY, /* GRAY8 */ V4L2_PIX_FMT_RGB555, /* RGB15_LE */ V4L2_PIX_FMT_RGB565, /* RGB16_LE */ V4L2_PIX_FMT_RGB555X, /* RGB15_BE */ V4L2_PIX_FMT_RGB565X, /* RGB16_BE */ V4L2_PIX_FMT_BGR24, /* BGR24 */ V4L2_PIX_FMT_BGR32, /* BGR32 */ V4L2_PIX_FMT_RGB24, /* RGB24 */ 0, /* RGB32 */ 0, /* LUT 2 */ 0, /* LUT 4 */ V4L2_PIX_FMT_YUYV, /* YUV422 */ V4L2_PIX_FMT_YUV422P, /* YUV422P */ V4L2_PIX_FMT_YUV420, /* YUV420P */ }; static struct STRTAB stereo[] = { { V4L2_TUNER_MODE_MONO, "mono" }, { V4L2_TUNER_MODE_STEREO, "stereo" }, { V4L2_TUNER_MODE_LANG1, "lang1" }, { V4L2_TUNER_MODE_LANG2, "lang2" }, { -1, NULL }, }; /* ---------------------------------------------------------------------- */ /* debug output */ #define PREFIX "ioctl: " static const char *io_names[] = { "QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT", "G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF", "G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON", "STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD", "ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER", "G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL", "QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43", "44", "45", "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT", "S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR", "S_MODULATOR" }; static const int io_count = (sizeof(io_names)/sizeof(char*)); #define IONAME(cmd) ((cmd & 0xff) < io_count ? \ io_names[cmd & 0xff] : "UNKNOWN") static int xioctl(int fd, int cmd, void *arg, int mayfail) { int rc; rc = ioctl(fd,cmd,arg); if (0 == rc && ng_debug < 2) return rc; if (mayfail && errno == mayfail && ng_debug < 2) return rc; switch (cmd) { case VIDIOC_QUERYCAP: { struct v4l2_capability *a = arg; fprintf(stderr,PREFIX "VIDIOC_QUERYCAP(%s,type=0x%x,in=%d,out=%d," "audio=%d,size=%dx%d-%dx%d,fps=%d,flags=0x%x)", a->name,a->type,a->inputs,a->outputs,a->audios, a->minwidth,a->minheight,a->maxwidth,a->maxheight, a->maxframerate,a->flags); break; } case VIDIOC_G_FMT: case VIDIOC_S_FMT: { struct v4l2_format *a = arg; fprintf(stderr,PREFIX "VIDIOC_%s(type=%d,",IONAME(cmd),a->type); switch (a->type) { case V4L2_BUF_TYPE_CAPTURE: fprintf(stderr, "%dx%d,depth=%d,%c%c%c%c,flags=0x%x,bpl=%d,size=%d)", a->fmt.pix.width,a->fmt.pix.height,a->fmt.pix.depth, a->fmt.pix.pixelformat & 0xff, (a->fmt.pix.pixelformat >> 8) & 0xff, (a->fmt.pix.pixelformat >> 16) & 0xff, (a->fmt.pix.pixelformat >> 24) & 0xff, a->fmt.pix.depth,a->fmt.pix.bytesperline, a->fmt.pix.sizeimage); break; default: fprintf(stderr,"??" "?)"); /* break trigraph */ break; } break; } case VIDIOC_REQBUFS: { struct v4l2_requestbuffers *a = arg; fprintf(stderr,PREFIX "VIDIOC_REQBUFS(count=%d,type=%d)", a->count,a->type); break; } case VIDIOC_QBUF: case VIDIOC_DQBUF: { struct v4l2_buffer *a = arg; fprintf(stderr,PREFIX "VIDIOC_%s(%d,type=%d,off=%d,len=%d,used=%d," "flags=0x%x,ts=%Ld,seq=%d)", IONAME(cmd),a->index,a->type,a->offset,a->length, a->bytesused,a->flags,a->timestamp,a->sequence); break; } case VIDIOC_G_WIN: case VIDIOC_S_WIN: { struct v4l2_window *a = arg; fprintf(stderr,PREFIX "VIDIOC_%s(%dx%d+%d+%d,key=0x%x,clips=%d)", IONAME(cmd), a->width, a->height, a->x, a->y, a->chromakey,a->clipcount); break; } case VIDIOC_PREVIEW: { int *a = arg; fprintf(stderr,PREFIX "VIDIOC_PREVIEW(%s)",*a ? "on" : "off"); break; } case VIDIOC_QUERYCTRL: { struct v4l2_queryctrl *a = arg; fprintf(stderr,PREFIX "VIDIOC_QUERYCTRL(id=%d,%s,%d-%d/%d,def=%d," "type=%d,flags=0x%x)", a->id,a->name,a->minimum,a->maximum,a->step, a->default_value,a->type,a->flags); break; } case VIDIOC_QUERYMENU: { struct v4l2_querymenu *a = arg; fprintf(stderr,PREFIX "VIDIOC_QUERYMENU(id=%d,index=%d,%s)", a->id,a->index,a->name); break; } case VIDIOC_G_CTRL: case VIDIOC_S_CTRL: { struct v4l2_control *a = arg; fprintf(stderr,PREFIX "VIDIOC_%s(id=%d,value=%d)", IONAME(cmd),a->id,a->value); break; } default: fprintf(stderr,PREFIX "VIDIOC_%s(cmd=0x%x)",IONAME(cmd),cmd); break; } fprintf(stderr,": %s\n",(rc == 0) ? "ok" : strerror(errno)); return rc; } static void print_bits(char *title, char **names, int count, int value) { int i; fprintf(stderr,"%s: ",title); for (i = 0; i < count; i++) { if (value & (1 << i)) fprintf(stderr,"%s ",names[i]); } fprintf(stderr,"\n"); } static void print_device_capabilities(struct v4l2_handle *h) { static char *cap_type[] = { "capture", "codec", "output", "fx", "vbi", "vtr", "vtx", "radio", }; static char *cap_flags[] = { "read", "write", "streaming", "preview", "select", "tuner", "monochrome", "teletext" }; static char *ctl_type[] = { "integer", "boolean", "menu" }; static char *cap_parm[] = { "highquality", "vflip", "hflip" }; unsigned int i; fprintf(stderr,"\n*** v4l2: video device capabilities ***\n"); /* capabilities */ fprintf(stderr, "type: %s\n", h->cap.type < SDIMOF(cap_type) ? cap_type[h->cap.type] : "unknown"); print_bits("flags",cap_flags,DIMOF(cap_flags),h->cap.flags); fprintf(stderr,"\n"); fprintf(stderr,"inputs: %d\naudios: %d\n",h->cap.inputs,h->cap.audios); fprintf(stderr,"size: %dx%d => %dx%d\n", h->cap.minwidth,h->cap.minheight,h->cap.maxwidth,h->cap.maxheight); fprintf(stderr,"fps: %d max\n",h->cap.maxframerate); /* inputs */ fprintf(stderr,"video inputs:\n"); for (i = 0; i < h->ninputs; i++) { printf(" %d: \"%s\", tuner: %s, audio: %s\n", i, h->inp[i].name, (h->inp[i].type == V4L2_INPUT_TYPE_TUNER) ? "yes" : "no", (h->inp[i].capability & V4L2_INPUT_CAP_AUDIO) ? "yes" : "no"); } /* video standards */ fprintf(stderr,"video standards:\n"); for (i = 0; i < h->nstds; i++) { printf(" %d: \"%s\"\n", i, h->std[i].std.name); } /* capture formats */ fprintf(stderr,"capture formats:\n"); for (i = 0; i < h->nfmts; i++) { fprintf(stderr," %d: %c%c%c%c, depth=%d,%s \"%s\"\n", i, h->fmt[i].pixelformat & 0xff, (h->fmt[i].pixelformat >> 8) & 0xff, (h->fmt[i].pixelformat >> 16) & 0xff, (h->fmt[i].pixelformat >> 24) & 0xff, h->fmt[i].depth, (h->fmt[i].flags & V4L2_FMT_FLAG_COMPRESSED) ? " compressed" : "", h->fmt[i].description); } /* capture parameters */ fprintf(stderr,"capture parameters:\n"); print_bits(" cap",cap_parm,sizeof(cap_parm)/sizeof(char*), h->streamparm.parm.capture.capability); print_bits(" cur",cap_parm,sizeof(cap_parm)/sizeof(char*), h->streamparm.parm.capture.capturemode); fprintf(stderr," timeperframe=%ld\n", h->streamparm.parm.capture.timeperframe); /* controls */ fprintf(stderr,"supported controls:\n"); for (i = 0; i < MAX_CTRL*2; i++) { if (h->ctl[i].id == UNSET) continue; fprintf(stderr," %2d: \"%s\", [%d .. %d], step=%d, def=%d, type=%s\n", i, h->ctl[i].name, h->ctl[i].minimum,h->ctl[i].maximum, h->ctl[i].step,h->ctl[i].default_value, ctl_type[h->ctl[i].type]); } fprintf(stderr,"\n"); } static void print_bufinfo(struct v4l2_buffer *buf) { static char *type[] = { "", "capture", "codec in", "codec out", "effects in1", "effects in2", "effects out", "video out" }; fprintf(stderr,"v4l2: buf %d: %s 0x%x+%d, used %d\n", buf->index, buf->type < sizeof(type)/sizeof(char*) ? type[buf->type] : "unknown", buf->offset,buf->length,buf->bytesused); } static void print_fbinfo(struct v4l2_framebuffer *fb) { static char *fb_cap[] = { "extern", "chromakey", "clipping", "scale-up", "scale-down" }; static char *fb_flags[] = { "primary", "overlay", "chromakey" }; /* capabilities */ fprintf(stderr,"v4l2: framebuffer info\n"); print_bits(" cap",fb_cap,sizeof(fb_cap)/sizeof(char*),fb->capability); print_bits(" flags",fb_cap,sizeof(fb_flags)/sizeof(char*),fb->flags); fprintf(stderr," base: %p %p %p\n",fb->base[0],fb->base[1],fb->base[2]); fprintf(stderr," format: %dx%d, %c%c%c%c, %d byte\n", fb->fmt.width, fb->fmt.height, fb->fmt.pixelformat & 0xff, (fb->fmt.pixelformat >> 8) & 0xff, (fb->fmt.pixelformat >> 16) & 0xff, (fb->fmt.pixelformat >> 24) & 0xff, fb->fmt.sizeimage); } /* ---------------------------------------------------------------------- */ /* helpers */ static void get_device_capabilities(struct v4l2_handle *h) { unsigned int i; for (h->ninputs = 0; h->ninputs < h->cap.inputs; h->ninputs++) { h->inp[h->ninputs].index = h->ninputs; if (-1 == xioctl(h->fd, VIDIOC_ENUMINPUT, &h->inp[h->ninputs], 0)) break; } for (h->nstds = 0; h->nstds < MAX_NORM; h->nstds++) { h->std[h->nstds].index = h->nstds; if (-1 == xioctl(h->fd, VIDIOC_ENUMSTD, &h->std[h->nstds], EINVAL)) break; } for (h->nfmts = 0; h->nfmts < MAX_FORMAT; h->nfmts++) { h->fmt[h->nfmts].index = h->nfmts; if (-1 == xioctl(h->fd, VIDIOC_ENUM_PIXFMT, &h->fmt[h->nfmts], EINVAL)) break; } h->streamparm.type = V4L2_BUF_TYPE_CAPTURE; ioctl(h->fd,VIDIOC_G_PARM,&h->streamparm); /* controls */ for (i = 0; i < MAX_CTRL; i++) { h->ctl[i].id = V4L2_CID_BASE+i; if (-1 == xioctl(h->fd, VIDIOC_QUERYCTRL, &h->ctl[i], EINVAL) || (h->ctl[i].flags & V4L2_CTRL_FLAG_DISABLED)) h->ctl[i].id = -1; } for (i = 0; i < MAX_CTRL; i++) { h->ctl[i+MAX_CTRL].id = V4L2_CID_PRIVATE_BASE+i; if (-1 == xioctl(h->fd, VIDIOC_QUERYCTRL, &h->ctl[i+MAX_CTRL], EINVAL) || (h->ctl[i+MAX_CTRL].flags & V4L2_CTRL_FLAG_DISABLED)) h->ctl[i+MAX_CTRL].id = -1; } } static struct STRTAB * build_norms(struct v4l2_handle *h) { struct STRTAB *norms; unsigned int i; norms = malloc(sizeof(struct STRTAB) * (h->nstds+1)); for (i = 0; i < h->nstds; i++) { norms[i].nr = i; norms[i].str = h->std[i].std.name; } norms[i].nr = -1; norms[i].str = NULL; return norms; } static struct STRTAB * build_inputs(struct v4l2_handle *h) { struct STRTAB *inputs; unsigned int i; inputs = malloc(sizeof(struct STRTAB) * (h->ninputs+1)); for (i = 0; i < h->ninputs; i++) { inputs[i].nr = i; inputs[i].str = h->inp[i].name; } inputs[i].nr = -1; inputs[i].str = NULL; return inputs; } /* ---------------------------------------------------------------------- */ static struct V4L2_ATTR { unsigned int id; unsigned int v4l2; } v4l2_attr[] = { { ATTR_ID_VOLUME, V4L2_CID_AUDIO_VOLUME }, { ATTR_ID_MUTE, V4L2_CID_AUDIO_MUTE }, { ATTR_ID_COLOR, V4L2_CID_SATURATION }, { ATTR_ID_BRIGHT, V4L2_CID_BRIGHTNESS }, { ATTR_ID_HUE, V4L2_CID_HUE }, { ATTR_ID_CONTRAST, V4L2_CID_CONTRAST }, }; #define NUM_ATTR (sizeof(v4l2_attr)/sizeof(struct V4L2_ATTR)) static struct STRTAB* v4l2_menu(int fd, const struct v4l2_queryctrl *ctl) { struct STRTAB *menu; struct v4l2_querymenu item; int i; menu = malloc(sizeof(struct STRTAB) * (ctl->maximum-ctl->minimum+2)); for (i = ctl->minimum; i <= ctl->maximum; i++) { item.id = ctl->id; item.index = i; if (-1 == xioctl(fd, VIDIOC_QUERYMENU, &item, 0)) { free(menu); return NULL; } menu[i-ctl->minimum].nr = i; menu[i-ctl->minimum].str = strdup(item.name); } menu[i-ctl->minimum].nr = -1; menu[i-ctl->minimum].str = NULL; return menu; } static void v4l2_add_attr(struct v4l2_handle *h, struct v4l2_queryctrl *ctl, int id, struct STRTAB *choices) { static int private_ids = ATTR_ID_COUNT; unsigned int i; h->attr = realloc(h->attr,(h->nattr+2) * sizeof(struct ng_attribute)); memset(h->attr+h->nattr,0,sizeof(struct ng_attribute)*2); if (ctl) { for (i = 0; i < NUM_ATTR; i++) if (v4l2_attr[i].v4l2 == ctl->id) break; if (i != NUM_ATTR) { h->attr[h->nattr].id = v4l2_attr[i].id; } else { h->attr[h->nattr].id = private_ids++; } h->attr[h->nattr].name = ctl->name; h->attr[h->nattr].priv = ctl; h->attr[h->nattr].defval = ctl->default_value; switch (ctl->type) { case V4L2_CTRL_TYPE_INTEGER: h->attr[h->nattr].type = ATTR_TYPE_INTEGER; h->attr[h->nattr].defval = ctl->default_value; h->attr[h->nattr].min = ctl->minimum; h->attr[h->nattr].max = ctl->maximum; break; case V4L2_CTRL_TYPE_BOOLEAN: h->attr[h->nattr].type = ATTR_TYPE_BOOL; break; case V4L2_CTRL_TYPE_MENU: h->attr[h->nattr].type = ATTR_TYPE_CHOICE; h->attr[h->nattr].choices = v4l2_menu(h->fd, ctl); break; default: return; } } else { /* for norms + inputs */ h->attr[h->nattr].id = id; h->attr[h->nattr].defval = 0; h->attr[h->nattr].type = ATTR_TYPE_CHOICE; h->attr[h->nattr].choices = choices; } if (h->attr[h->nattr].id < ATTR_ID_COUNT) h->attr[h->nattr].name = ng_attr_to_desc[h->attr[h->nattr].id]; h->attr[h->nattr].read = v4l2_read_attr; h->attr[h->nattr].write = v4l2_write_attr; h->attr[h->nattr].handle = h; h->nattr++; } static int v4l2_read_attr(struct ng_attribute *attr) { struct v4l2_handle *h = attr->handle; const struct v4l2_queryctrl *ctl = attr->priv; struct v4l2_control c; struct v4l2_tuner tuner; int value = 0; if (NULL != ctl) { c.id = ctl->id; xioctl(h->fd,VIDIOC_G_CTRL,&c,0); value = c.value; } else if (attr->id == ATTR_ID_NORM) { value = -1; /* FIXME */ } else if (attr->id == ATTR_ID_INPUT) { xioctl(h->fd,VIDIOC_G_INPUT,&value,0); } else if (attr->id == ATTR_ID_AUDIO_MODE) { memset(&tuner,0,sizeof(tuner)); xioctl(h->fd,VIDIOC_G_TUNER,&tuner,0); value = tuner.audmode; #if 1 if (ng_debug) { fprintf(stderr,"v4l2: tuner cap:%s%s%s\n", (tuner.capability&V4L2_TUNER_CAP_STEREO) ? " STEREO" : "", (tuner.capability&V4L2_TUNER_CAP_LANG1) ? " LANG1" : "", (tuner.capability&V4L2_TUNER_CAP_LANG2) ? " LANG2" : ""); fprintf(stderr,"v4l2: tuner rxs:%s%s%s%s\n", (tuner.rxsubchans&V4L2_TUNER_SUB_MONO) ? " MONO" : "", (tuner.rxsubchans&V4L2_TUNER_SUB_STEREO) ? " STEREO" : "", (tuner.rxsubchans&V4L2_TUNER_SUB_LANG1) ? " LANG1" : "", (tuner.rxsubchans&V4L2_TUNER_SUB_LANG2) ? " LANG2" : ""); fprintf(stderr,"v4l2: tuner cur:%s%s%s%s\n", (tuner.audmode==V4L2_TUNER_MODE_MONO) ? " MONO" : "", (tuner.audmode==V4L2_TUNER_MODE_STEREO) ? " STEREO" : "", (tuner.audmode==V4L2_TUNER_MODE_LANG1) ? " LANG1" : "", (tuner.audmode==V4L2_TUNER_MODE_LANG2) ? " LANG2" : ""); } #endif } return value; } static void v4l2_write_attr(struct ng_attribute *attr, int value) { struct v4l2_handle *h = attr->handle; const struct v4l2_queryctrl *ctl = attr->priv; struct v4l2_control c; struct v4l2_tuner tuner; if (NULL != ctl) { c.id = ctl->id; c.value = value; xioctl(h->fd,VIDIOC_S_CTRL,&c,0); } else if (attr->id == ATTR_ID_NORM) { xioctl(h->fd,VIDIOC_S_STD,&h->std[value].std,0); } else if (attr->id == ATTR_ID_INPUT) { xioctl(h->fd,VIDIOC_S_INPUT,&value,0); } else if (attr->id == ATTR_ID_AUDIO_MODE) { memset(&tuner,0,sizeof(tuner)); xioctl(h->fd,VIDIOC_G_TUNER,&tuner,0); tuner.audmode = value; xioctl(h->fd,VIDIOC_S_TUNER,&tuner,0); } } /* ---------------------------------------------------------------------- */ static void* v4l2_open(char *device) { struct v4l2_handle *h; int i; h = malloc(sizeof(*h)); if (NULL == h) return NULL; memset(h,0,sizeof(*h)); if (-1 == (h->fd = open(device, O_RDWR))) { fprintf(stderr,"v4l2: open %s: %s\n",device,strerror(errno)); goto err; } if (-1 == ioctl(h->fd,VIDIOC_QUERYCAP,&h->cap)) goto err; if (ng_debug) fprintf(stderr, "v4l2: open\n"); fcntl(h->fd,F_SETFD,FD_CLOEXEC); if (ng_debug) fprintf(stderr,"v4l2: device is %s\n",h->cap.name); get_device_capabilities(h); if (ng_debug) print_device_capabilities(h); /* attributes */ v4l2_add_attr(h, NULL, ATTR_ID_NORM, build_norms(h)); v4l2_add_attr(h, NULL, ATTR_ID_INPUT, build_inputs(h)); if (h->cap.flags & V4L2_FLAG_TUNER) v4l2_add_attr(h, NULL, ATTR_ID_AUDIO_MODE, stereo); for (i = 0; i < MAX_CTRL*2; i++) { if (h->ctl[i].id == UNSET) continue; v4l2_add_attr(h, &h->ctl[i], 0, NULL); } /* capture buffers */ for (i = 0; i < WANTED_BUFFERS; i++) { ng_init_video_buf(h->buf_me+i); h->buf_me[i].release = ng_wakeup_video_buf; } return h; err: if (h->fd != -1) close(h->fd); if (h) free(h); return NULL; } static int v4l2_close(void *handle) { struct v4l2_handle *h = handle; if (ng_debug) fprintf(stderr, "v4l2: close\n"); close(h->fd); free(h); return 0; } static char* v4l2_devname(void *handle) { struct v4l2_handle *h = handle; return h->cap.name; } static int v4l2_flags(void *handle) { struct v4l2_handle *h = handle; int ret = 0; if (h->cap.flags & V4L2_FLAG_PREVIEW && !h->ov_error) ret |= CAN_OVERLAY; if ((h->cap.flags & V4L2_FLAG_STREAMING) || (h->cap.flags & V4L2_FLAG_READ)) ret |= CAN_CAPTURE; if (h->cap.flags & V4L2_FLAG_TUNER) ret |= CAN_TUNE; return ret; } static struct ng_attribute* v4l2_attrs(void *handle) { struct v4l2_handle *h = handle; return h->attr; } /* ---------------------------------------------------------------------- */ static unsigned long v4l2_getfreq(void *handle) { struct v4l2_handle *h = handle; unsigned long freq; xioctl(h->fd, VIDIOC_G_FREQ, &freq, 0); return freq; } static void v4l2_setfreq(void *handle, unsigned long freq) { struct v4l2_handle *h = handle; if (ng_debug) fprintf(stderr,"v4l2: freq: %.3f\n",(float)freq/16); xioctl(h->fd, VIDIOC_S_FREQ, &freq, 0); } static int v4l2_tuned(void *handle) { struct v4l2_handle *h = handle; struct v4l2_tuner tuner; usleep(10000); if (-1 == xioctl(h->fd,VIDIOC_G_TUNER,&tuner,0)) return 0; return tuner.signal ? 1 : 0; } /* ---------------------------------------------------------------------- */ /* overlay */ static int v4l2_setupfb(void *handle, struct ng_video_fmt *fmt, void *base) { struct v4l2_handle *h = handle; if (-1 == xioctl(h->fd, VIDIOC_G_FBUF, &h->ov_fb, 0)) return -1; if (1 /* ng_debug */) print_fbinfo(&h->ov_fb); /* double-check settings */ if (NULL != base && h->ov_fb.base[0] != base) { fprintf(stderr,"v4l2: WARNING: framebuffer base address mismatch\n"); fprintf(stderr,"v4l2: me=%p v4l=%p\n",base,h->ov_fb.base); h->ov_error = 1; return -1; } if (h->ov_fb.fmt.width != fmt->width || h->ov_fb.fmt.height != fmt->height) { fprintf(stderr,"v4l2: WARNING: framebuffer size mismatch\n"); fprintf(stderr,"v4l2: me=%dx%d v4l=%dx%d\n", fmt->width,fmt->height,h->ov_fb.fmt.width,h->ov_fb.fmt.height); h->ov_error = 1; return -1; } if ((h->ov_fb.fmt.flags & V4L2_FMT_FLAG_BYTESPERLINE) && fmt->bytesperline > 0 && fmt->bytesperline != h->ov_fb.fmt.bytesperline) { fprintf(stderr,"v4l2: WARNING: framebuffer bpl mismatch\n"); fprintf(stderr,"v4l2: me=%d v4l=%d\n", fmt->bytesperline,h->ov_fb.fmt.bytesperline); h->ov_error = 1; return -1; } #if 0 if (h->ov_fb.fmt.pixelformat != xawtv_pixelformat[fmt->fmtid]) { fprintf(stderr,"v4l2: WARNING: framebuffer format mismatch\n"); fprintf(stderr,"v4l2: me=%c%c%c%c [%s] v4l=%c%c%c%c\n", xawtv_pixelformat[fmt->fmtid] & 0xff, (xawtv_pixelformat[fmt->fmtid] >> 8) & 0xff, (xawtv_pixelformat[fmt->fmtid] >> 16) & 0xff, (xawtv_pixelformat[fmt->fmtid] >> 24) & 0xff, ng_vfmt_to_desc[fmt->fmtid], h->ov_fb.fmt.pixelformat & 0xff, (h->ov_fb.fmt.pixelformat >> 8) & 0xff, (h->ov_fb.fmt.pixelformat >> 16) & 0xff, (h->ov_fb.fmt.pixelformat >> 24) & 0xff); h->ov_error = 1; return -1; } #endif return 0; } static int v4l2_overlay(void *handle, struct ng_video_fmt *fmt, int x, int y, struct OVERLAY_CLIP *oc, int count, int aspect) { struct v4l2_handle *h = handle; int rc,i; if (h->ov_error) return -1; if (NULL == fmt) { if (ng_debug) fprintf(stderr,"v4l2: overlay off\n"); if (h->ov_enabled) { h->ov_enabled = 0; h->ov_on = 0; xioctl(h->fd, VIDIOC_PREVIEW, &h->ov_on, 0); } return 0; } if (ng_debug) fprintf(stderr,"v4l2: overlay win=%dx%d+%d+%d, %d clips\n", fmt->width,fmt->height,x,y,count); h->ov_win.x = x; h->ov_win.y = y; h->ov_win.width = fmt->width; h->ov_win.height = fmt->height; /* check against max. size */ ioctl(h->fd,VIDIOC_QUERYCAP,&h->cap); if (h->ov_win.width > h->cap.maxwidth) { h->ov_win.width = h->cap.maxwidth; h->ov_win.x += (fmt->width - h->ov_win.width)/2; } if (h->ov_win.height > h->cap.maxheight) { h->ov_win.height = h->cap.maxheight; h->ov_win.y += (fmt->height - h->ov_win.height)/2; } if (aspect) ng_ratio_fixup(&h->ov_win.width,&h->ov_win.height, &h->ov_win.x,&h->ov_win.y); /* fixups */ ng_check_clipping(h->ov_win.width, h->ov_win.height, x - h->ov_win.x, y - h->ov_win.y, oc, &count); if (h->ov_fb.capability & V4L2_FBUF_CAP_CLIPPING) { h->ov_win.clips = h->ov_clips; h->ov_win.clipcount = count; for (i = 0; i < count; i++) { h->ov_clips[i].next = (i+1 == count) ? NULL : &h->ov_clips[i+1]; h->ov_clips[i].x = oc[i].x1; h->ov_clips[i].y = oc[i].y1; h->ov_clips[i].width = oc[i].x2-oc[i].x1; h->ov_clips[i].height = oc[i].y2-oc[i].y1; } } #if 0 if (h->ov_fb.flags & V4L2_FBUF_FLAG_CHROMAKEY) { h->ov_win.chromakey = 0; /* FIXME */ } #endif rc = xioctl(h->fd, VIDIOC_S_WIN, &h->ov_win, 0); h->ov_enabled = (0 == rc) ? 1 : 0; h->ov_on = (0 == rc) ? 1 : 0; xioctl(h->fd, VIDIOC_PREVIEW, &h->ov_on, 0); return 0; } /* ---------------------------------------------------------------------- */ /* capture helpers */ static int v4l2_queue_buffer(struct v4l2_handle *h) { int frame = h->queue % h->reqbufs.count; int rc; if (0 != h->buf_me[frame].refcount) { if (0 != h->queue - h->waiton) return -1; fprintf(stderr,"v4l2: waiting for a free buffer\n"); ng_waiton_video_buf(h->buf_me+frame); } rc = xioctl(h->fd,VIDIOC_QBUF,&h->buf_v4l2[frame], 0); if (0 == rc) h->queue++; return rc; } static void v4l2_queue_all(struct v4l2_handle *h) { for (;;) { if (h->queue - h->waiton >= h->reqbufs.count) return; if (0 != v4l2_queue_buffer(h)) return; } } static int v4l2_waiton(struct v4l2_handle *h) { struct v4l2_buffer buf; struct timeval tv; fd_set rdset; /* wait for the next frame */ again: tv.tv_sec = 5; tv.tv_usec = 0; FD_ZERO(&rdset); FD_SET(h->fd, &rdset); switch (select(h->fd + 1, &rdset, NULL, NULL, &tv)) { case -1: if (EINTR == errno) goto again; perror("v4l2: select"); return -1; case 0: fprintf(stderr,"v4l2: oops: select timeout\n"); return -1; } /* get it */ memset(&buf,0,sizeof(buf)); buf.type = V4L2_BUF_TYPE_CAPTURE; if (-1 == xioctl(h->fd,VIDIOC_DQBUF,&buf, 0)) return -1; h->waiton++; h->buf_v4l2[buf.index] = buf; return buf.index; } static int v4l2_start_streaming(struct v4l2_handle *h, int buffers) { int disable_overlay = 0; int i; /* setup buffers */ h->reqbufs.count = buffers; h->reqbufs.type = V4L2_BUF_TYPE_CAPTURE; if (-1 == xioctl(h->fd, VIDIOC_REQBUFS, &h->reqbufs, 0)) return -1; for (i = 0; i < h->reqbufs.count; i++) { h->buf_v4l2[i].index = i; h->buf_v4l2[i].type = V4L2_BUF_TYPE_CAPTURE; if (-1 == ioctl(h->fd, VIDIOC_QUERYBUF, &h->buf_v4l2[i])) return -1; h->buf_me[i].fmt = h->fmt_me; h->buf_me[i].size = h->buf_me[i].fmt.bytesperline * h->buf_me[i].fmt.height; h->buf_me[i].data = mmap(NULL, h->buf_v4l2[i].length, PROT_READ | PROT_WRITE, MAP_SHARED, h->fd, h->buf_v4l2[i].offset); if ((void*)-1 == h->buf_me[i].data) { perror("mmap"); return -1; } if (ng_debug) print_bufinfo(&h->buf_v4l2[i]); } /* queue up all buffers */ v4l2_queue_all(h); try_again: /* turn off preview (if needed) */ if (disable_overlay) { h->ov_on = 0; xioctl(h->fd, VIDIOC_PREVIEW, &h->ov_on, 0); if (ng_debug) fprintf(stderr,"v4l2: overlay off (start_streaming)\n"); } /* start capture */ if (-1 == xioctl(h->fd,VIDIOC_STREAMON,&h->fmt_v4l2.type, h->ov_on ? EBUSY : 0)) { if (h->ov_on && errno == EBUSY) { disable_overlay = 1; goto try_again; } return -1; } return 0; } static void v4l2_stop_streaming(struct v4l2_handle *h) { int i; /* stop capture */ if (-1 == ioctl(h->fd,VIDIOC_STREAMOFF,&h->fmt_v4l2.type)) perror("ioctl VIDIOC_STREAMOFF"); /* free buffers */ for (i = 0; i < h->reqbufs.count; i++) { if (0 != h->buf_me[i].refcount) ng_waiton_video_buf(&h->buf_me[i]); if (-1 == munmap(h->buf_me[i].data,h->buf_me[i].size)) perror("munmap"); } h->queue = 0; h->waiton = 0; /* turn on preview (if needed) */ if (h->ov_on != h->ov_enabled) { h->ov_on = h->ov_enabled; xioctl(h->fd, VIDIOC_PREVIEW, &h->ov_on, 0); if (ng_debug) fprintf(stderr,"v4l2: overlay on (stop_streaming)\n"); } } /* ---------------------------------------------------------------------- */ /* capture interface */ /* set capture parameters */ static int v4l2_setformat(void *handle, struct ng_video_fmt *fmt) { struct v4l2_handle *h = handle; h->fmt_v4l2.type = V4L2_BUF_TYPE_CAPTURE; h->fmt_v4l2.fmt.pix.pixelformat = xawtv_pixelformat[fmt->fmtid]; h->fmt_v4l2.fmt.pix.flags = V4L2_FMT_FLAG_INTERLACED; h->fmt_v4l2.fmt.pix.depth = ng_vfmt_to_depth[fmt->fmtid]; h->fmt_v4l2.fmt.pix.width = fmt->width; h->fmt_v4l2.fmt.pix.height = fmt->height; h->fmt_v4l2.fmt.pix.bytesperline = fmt->bytesperline; if (-1 == xioctl(h->fd, VIDIOC_S_FMT, &h->fmt_v4l2, EINVAL)) return -1; if (h->fmt_v4l2.fmt.pix.pixelformat != xawtv_pixelformat[fmt->fmtid]) return -1; fmt->width = h->fmt_v4l2.fmt.pix.width; fmt->height = h->fmt_v4l2.fmt.pix.height; fmt->bytesperline = h->fmt_v4l2.fmt.pix.bytesperline; if (0 == fmt->bytesperline) fmt->bytesperline = fmt->width * ng_vfmt_to_depth[fmt->fmtid] / 8; h->fmt_me = *fmt; if (ng_debug) fprintf(stderr,"v4l2: new capture params (%dx%d, %c%c%c%c, %d byte)\n", fmt->width,fmt->height, h->fmt_v4l2.fmt.pix.pixelformat & 0xff, (h->fmt_v4l2.fmt.pix.pixelformat >> 8) & 0xff, (h->fmt_v4l2.fmt.pix.pixelformat >> 16) & 0xff, (h->fmt_v4l2.fmt.pix.pixelformat >> 24) & 0xff, h->fmt_v4l2.fmt.pix.sizeimage); return 0; } /* start/stop video */ static int v4l2_startvideo(void *handle, int fps, unsigned int buffers) { struct v4l2_handle *h = handle; if (0 != h->fps) fprintf(stderr,"v4l2_startvideo: oops: fps!=0\n"); h->fps = fps; h->first = 1; h->start = 0; if (h->cap.flags & V4L2_FLAG_STREAMING) return v4l2_start_streaming(h,buffers); return 0; } static void v4l2_stopvideo(void *handle) { struct v4l2_handle *h = handle; if (0 == h->fps) fprintf(stderr,"v4l2_stopvideo: oops: fps==0\n"); h->fps = 0; if (h->cap.flags & V4L2_FLAG_STREAMING) v4l2_stop_streaming(h); } /* read images */ static struct ng_video_buf* v4l2_nextframe(void *handle) { struct v4l2_handle *h = handle; struct ng_video_buf *buf = NULL; int rc,size,frame = 0; if (h->cap.flags & V4L2_FLAG_STREAMING) { v4l2_queue_all(h); frame = v4l2_waiton(h); if (-1 == frame) return NULL; h->buf_me[frame].refcount++; buf = &h->buf_me[frame]; memset(&buf->info,0,sizeof(buf->info)); buf->info.ts = h->buf_v4l2[frame].timestamp; } else { size = h->fmt_me.bytesperline * h->fmt_me.height; buf = ng_malloc_video_buf(&h->fmt_me,size); rc = read(h->fd,buf->data,size); if (rc != size) { if (-1 == rc) { perror("v4l2: read"); } else { fprintf(stderr, "v4l2: read: rc=%d/size=%d\n",rc,size); } ng_release_video_buf(buf); return NULL; } memset(&buf->info,0,sizeof(buf->info)); buf->info.ts = ng_get_timestamp(); } if (h->first) { h->first = 0; h->start = buf->info.ts; if (ng_debug) fprintf(stderr,"v4l2: start ts=%lld\n",h->start); } buf->info.ts -= h->start; return buf; } static struct ng_video_buf* v4l2_getimage(void *handle) { struct v4l2_handle *h = handle; struct ng_video_buf *buf; int size,frame,rc; size = h->fmt_me.bytesperline * h->fmt_me.height; buf = ng_malloc_video_buf(&h->fmt_me,size); if (h->cap.flags & V4L2_FLAG_READ) { rc = read(h->fd,buf->data,size); if (rc != size) { if (-1 == rc) { perror("v4l2: read"); } else { fprintf(stderr, "v4l2: read: rc=%d/size=%d\n",rc,size); } ng_release_video_buf(buf); return NULL; } } else { if (-1 == v4l2_start_streaming(h,1)) { v4l2_stop_streaming(h); return NULL; } frame = v4l2_waiton(h); if (-1 == frame) { v4l2_stop_streaming(h); return NULL; } memcpy(buf->data,h->buf_me[0].data,size); v4l2_stop_streaming(h); } return buf; } /* ---------------------------------------------------------------------- */ extern void ng_plugin_init(void); void ng_plugin_init(void) { ng_vid_driver_register(NG_PLUGIN_MAGIC,__FILE__,&v4l2_driver); } amsn-0.98.9/utils/linux/capture/libng/plugins/Makefile0000644000175000017500000000003410246003435022541 0ustar billiobbilliobdefault: cd ../..; $(MAKE) amsn-0.98.9/utils/linux/capture/libng/plugins/sn9c10x.c0000644000175000017500000002275610574640152022500 0ustar billiobbilliob/* * SN9C10x formats * (C) 2007 Gabriel Gambetta * * A libng plugin for the SN9C102 driver formats. * * * * BA81 decoding taken from : * * Sonix SN9C101 based webcam basic I/F routines * Copyright (C) 2004 Takafumi Mizuno * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * * S910 decoding taken from sn-webcam (http://sn-webcam.sourceforge.net) * */ #define NG_PRIVATE #include "config.h" #include #include #include #include #include #include #include "grab-ng.h" /* ======================================================================== */ /* BA81 decoder */ /* ======================================================================== */ static void* bayer_init (struct ng_video_fmt* out, void* priv) { return 0; } static void bayer_decompress (void* handle, struct ng_video_buf* out, struct ng_video_buf* in) { long int i; unsigned char* rawpt; unsigned char* scanpt; long int size; int WIDTH, HEIGHT; WIDTH = in->fmt.width; HEIGHT = in->fmt.height; rawpt = in->data; scanpt = out->data; size = WIDTH * HEIGHT; for (i = 0; i < size; i++) { if ((i / WIDTH) % 2 == 0) { if ((i % 2) == 0) { /* B */ if ((i > WIDTH) && ((i % WIDTH) > 0)) { *scanpt++ = (*(rawpt - WIDTH - 1) + *(rawpt - WIDTH + 1) + *(rawpt + WIDTH - 1) + *(rawpt + WIDTH + 1)) / 4; /* R */ *scanpt++ = (*(rawpt - 1) + *(rawpt + 1) + *(rawpt + WIDTH) + *(rawpt - WIDTH)) / 4; /* G */ *scanpt++ = *rawpt; /* B */ } else { /* first line or left column */ *scanpt++ = *(rawpt + WIDTH + 1); /* R */ *scanpt++ = (*(rawpt + 1) + *(rawpt + WIDTH)) / 2; /* G */ *scanpt++ = *rawpt; /* B */ } } else { /* (B)G */ if ((i > WIDTH) && ((i % WIDTH) < (WIDTH - 1))) { *scanpt++ = (*(rawpt + WIDTH) + *(rawpt - WIDTH)) / 2; /* R */ *scanpt++ = *rawpt; /* G */ *scanpt++ = (*(rawpt - 1) + *(rawpt + 1)) / 2; /* B */ } else { /* first line or right column */ *scanpt++ = *(rawpt + WIDTH); /* R */ *scanpt++ = *rawpt; /* G */ *scanpt++ = *(rawpt - 1); /* B */ } } } else { if ((i % 2) == 0) { /* G(R) */ if ((i < (WIDTH * (HEIGHT - 1))) && ((i % WIDTH) > 0)) { *scanpt++ = (*(rawpt - 1) + *(rawpt + 1)) / 2; /* R */ *scanpt++ = *rawpt; /* G */ *scanpt++ = (*(rawpt + WIDTH) + *(rawpt - WIDTH)) / 2; /* B */ } else { /* bottom line or left column */ *scanpt++ = *(rawpt + 1); /* R */ *scanpt++ = *rawpt; /* G */ *scanpt++ = *(rawpt - WIDTH); /* B */ } } else { /* R */ if (i < (WIDTH * (HEIGHT - 1)) && ((i % WIDTH) < (WIDTH - 1))) { *scanpt++ = *rawpt; /* R */ *scanpt++ = (*(rawpt - 1) + *(rawpt + 1) + *(rawpt - WIDTH) + *(rawpt + WIDTH)) / 4; /* G */ *scanpt++ = (*(rawpt - WIDTH - 1) + *(rawpt - WIDTH + 1) + *(rawpt + WIDTH - 1) + *(rawpt + WIDTH + 1)) / 4; /* B */ } else { /* bottom line or right column */ *scanpt++ = *rawpt; /* R */ *scanpt++ = (*(rawpt - 1) + *(rawpt - WIDTH)) / 2; /* G */ *scanpt++ = *(rawpt - WIDTH - 1); /* B */ } } } rawpt++; } } static void bayer_cleanup (void* handle) { } /* ======================================================================== */ /* SN10 decoder */ /* ======================================================================== */ #define CLAMP(x) ((x)<0?0:((x)>255)?255:(x)) typedef struct { int is_abs; int len; int val; int unk; } code_table_t; /* local storage */ static code_table_t table[256]; static int init_done = 0; /* global variable */ int sonix_unknown = 0; /* sonix_decompress_init ===================== pre-calculates a locally stored table for efficient huffman-decoding. Each entry at index x in the table represents the codeword present at the MSB of byte x. */ static void sonix_decompress_init (void) { int i; int is_abs, val, len, unk; for (i = 0; i < 256; i++) { is_abs = 0; val = 0; len = 0; unk = 0; if ((i & 0x80) == 0) { /* code 0 */ val = 0; len = 1; } else if ((i & 0xE0) == 0x80) { /* code 100 */ val = +4; len = 3; } else if ((i & 0xE0) == 0xA0) { /* code 101 */ val = -4; len = 3; } else if ((i & 0xF0) == 0xD0) { /* code 1101 */ val = +11; len = 4; } else if ((i & 0xF0) == 0xF0) { /* code 1111 */ val = -11; len = 4; } else if ((i & 0xF8) == 0xC8) { /* code 11001 */ val = +20; len = 5; } else if ((i & 0xFC) == 0xC0) { /* code 110000 */ val = -20; len = 6; } else if ((i & 0xFC) == 0xC4) { /* code 110001xx: unknown */ val = 0; len = 8; unk = 1; } else if ((i & 0xF0) == 0xE0) { /* code 1110xxxx */ is_abs = 1; val = (i & 0x0F) << 4; len = 8; } table[i].is_abs = is_abs; table[i].val = val; table[i].len = len; table[i].unk = unk; } sonix_unknown = 0; init_done = 1; } struct S910Context { unsigned char* sTempBuffer; void* pBayerContext; }; static void* s910_init (struct ng_video_fmt* out, void* priv) { struct S910Context* pContext; if (!init_done) sonix_decompress_init(); pContext = (struct S910Context*)malloc(sizeof(struct S910Context)); pContext->sTempBuffer = (unsigned char*)malloc(3*out->width*out->height); pContext->pBayerContext = bayer_init(out, priv); return pContext; } static void s910_decompress (void* handle, struct ng_video_buf* out, struct ng_video_buf* in) { int row, col; int val; int bitpos; unsigned char code; unsigned char* addr; int width; int height; unsigned char* inp; unsigned char* outp; unsigned char* inp_save; struct S910Context* pContext; if (!init_done) return; pContext = (struct S910Context*)handle; width = out->fmt.width; height = out->fmt.height; inp = in->data; outp = pContext->sTempBuffer; inp_save = in->data; bitpos = 0; for (row = 0; row < height; row++) { col = 0; /* first two pixels in first two rows are stored as raw 8-bit */ if (row < 2) { addr = inp + (bitpos >> 3); code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7))); bitpos += 8; *outp++ = code; addr = inp + (bitpos >> 3); code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7))); bitpos += 8; *outp++ = code; col += 2; } while (col < width) { /* get bitcode from bitstream */ addr = inp + (bitpos >> 3); code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7))); /* update bit position */ bitpos += table[code].len; /* update code statistics */ sonix_unknown += table[code].unk; /* calculate pixel value */ val = table[code].val; if (!table[code].is_abs) { /* value is relative to top and left pixel */ if (col < 2) { /* left column: relative to top pixel */ val += outp[-2 * width]; } else if (row < 2) { /* top row: relative to left pixel */ val += outp[-2]; } else { /* main area: average of left pixel and top pixel */ val += (outp[-2] + outp[-2 * width]) / 2; } } /* store pixel */ *outp++ = CLAMP(val); col++; } } in->data = pContext->sTempBuffer; bayer_decompress(NULL, out, in); in->data = inp_save; } static void s910_cleanup (void* handle) { struct S910Context* pContext; pContext = (struct S910Context*)handle; bayer_cleanup(pContext->pBayerContext); free(pContext->sTempBuffer); free(pContext); } /* ======================================================================== */ /* Init stuff */ /* ======================================================================== */ static struct ng_video_conv conv_list[] = { { .init = s910_init, .p.frame = s910_decompress, .p.fini = s910_cleanup, .p.mode = NG_MODE_TRIVIAL, .fmtid_in = VIDEO_S910, .fmtid_out = VIDEO_RGB24, }, { .init = bayer_init, .p.frame = bayer_decompress, .p.fini = bayer_cleanup, .p.mode = NG_MODE_TRIVIAL, .fmtid_in = VIDEO_BAYER, .fmtid_out = VIDEO_RGB24, }, }; static const int nconv = sizeof(conv_list)/sizeof(struct ng_video_conv); /* ------------------------------------------------------------------- */ static void __init ng_plugin_init(void) { ng_conv_register(NG_PLUGIN_MAGIC, __FILE__, conv_list, nconv); } amsn-0.98.9/utils/linux/capture/libng/plugins/conv-mjpeg.c0000644000175000017500000005153610545303304023327 0ustar billiobbilliob#include "config.h" #include #include #include #include #include #include #include "grab-ng.h" /* ---------------------------------------------------------------------- */ struct mjpeg_compress { struct jpeg_destination_mgr mjpg_dest; /* must be first */ struct jpeg_compress_struct mjpg_cinfo; struct jpeg_error_mgr mjpg_jerr; struct ng_video_fmt fmt; JOCTET *mjpg_buffer; size_t mjpg_bufsize; size_t mjpg_bufused; int mjpg_tables; /* yuv */ unsigned char **mjpg_ptrs[3]; }; struct mjpeg_decompress { struct jpeg_source_mgr mjpg_src; /* must be first */ struct jpeg_decompress_struct mjpg_cinfo; struct jpeg_error_mgr mjpg_jerr; struct ng_video_fmt fmt; struct ng_video_buf *buf; /* yuv */ unsigned char **mjpg_ptrs[3]; }; struct mjpeg_yuv_priv { int luma_h; int luma_v; }; static void swap_rgb24(char *mem, int n) { char c; char *p = mem; int i = n; while (--i) { c = p[0]; p[0] = p[2]; p[2] = c; p += 3; } } /* ---------------------------------------------------------------------- */ /* I/O manager */ static void mjpg_dest_init(struct jpeg_compress_struct *cinfo) { struct mjpeg_compress *h = (struct mjpeg_compress*)cinfo->dest; cinfo->dest->next_output_byte = h->mjpg_buffer; cinfo->dest->free_in_buffer = h->mjpg_bufsize; } static boolean mjpg_dest_flush(struct jpeg_compress_struct *cinfo) { fprintf(stderr,"mjpg: panic: output buffer too small\n"); exit(1); } static void mjpg_dest_term(struct jpeg_compress_struct *cinfo) { struct mjpeg_compress *h = (struct mjpeg_compress*)cinfo->dest; h->mjpg_bufused = h->mjpg_bufsize - cinfo->dest->free_in_buffer; } static void mjpg_src_init(struct jpeg_decompress_struct *cinfo) { struct mjpeg_decompress *h = (struct mjpeg_decompress*)cinfo->src; cinfo->src->next_input_byte = h->buf->data; cinfo->src->bytes_in_buffer = h->buf->size; } static int mjpg_src_fill(struct jpeg_decompress_struct *cinfo) { fprintf(stderr,"mjpg: panic: no more input data\n"); exit(1); } static void mjpg_src_skip(struct jpeg_decompress_struct *cinfo, long num_bytes) { cinfo->src->next_input_byte += num_bytes; } static void mjpg_src_term(struct jpeg_decompress_struct *cinfo) { /* nothing */ } /* ---------------------------------------------------------------------- */ /* compress */ static struct mjpeg_compress* mjpg_init(struct ng_video_fmt *fmt) { struct mjpeg_compress *h; h = malloc(sizeof(*h)); if (NULL == h) return NULL; memset(h,0,sizeof(*h)); h->mjpg_cinfo.err = jpeg_std_error(&h->mjpg_jerr); jpeg_create_compress(&h->mjpg_cinfo); h->mjpg_dest.init_destination = mjpg_dest_init; h->mjpg_dest.empty_output_buffer = mjpg_dest_flush; h->mjpg_dest.term_destination = mjpg_dest_term; h->mjpg_cinfo.dest = &h->mjpg_dest; h->fmt = *fmt; h->mjpg_tables = TRUE; h->mjpg_cinfo.image_width = fmt->width; h->mjpg_cinfo.image_height = fmt->height; h->mjpg_cinfo.image_width &= ~(2*DCTSIZE-1); h->mjpg_cinfo.image_height &= ~(2*DCTSIZE-1); return h; } static void mjpg_cleanup(void *handle) { struct mjpeg_compress *h = handle; int i; if (ng_debug > 1) fprintf(stderr,"mjpg_cleanup\n"); jpeg_destroy_compress(&h->mjpg_cinfo); for (i = 0; i < 3; i++) if (NULL != h->mjpg_ptrs[i]) free(h->mjpg_ptrs[i]); free(h); } /* ---------------------------------------------------------------------- */ static void* mjpg_rgb_init(struct ng_video_fmt *out, void *priv) { struct mjpeg_compress *h; if (ng_debug > 1) fprintf(stderr,"mjpg_rgb_init\n"); h = mjpg_init(out); if (NULL == h) return NULL; h->mjpg_cinfo.input_components = 3; h->mjpg_cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&h->mjpg_cinfo); h->mjpg_cinfo.dct_method = JDCT_FASTEST; jpeg_set_quality(&h->mjpg_cinfo, ng_jpeg_quality, TRUE); jpeg_suppress_tables(&h->mjpg_cinfo, TRUE); return h; } static void mjpg_rgb_compress(void *handle, struct ng_video_buf *out, struct ng_video_buf *in) { struct mjpeg_compress *h = handle; unsigned char *line; unsigned int i; if (ng_debug > 1) fprintf(stderr,"mjpg_rgb_compress\n"); h->mjpg_buffer = out->data; h->mjpg_bufsize = out->size; jpeg_start_compress(&h->mjpg_cinfo, h->mjpg_tables); for (i = 0, line = in->data; i < h->mjpg_cinfo.image_height; i++, line += 3*h->mjpg_cinfo.image_width) jpeg_write_scanlines(&h->mjpg_cinfo, &line, 1); jpeg_finish_compress(&h->mjpg_cinfo); out->size = h->mjpg_bufused; } static void mjpg_bgr_compress(void *handle, struct ng_video_buf *out, struct ng_video_buf *in) { swap_rgb24(in->data,in->fmt.width*in->fmt.height); /* FIXME */ return mjpg_rgb_compress(handle,out,in); } /* ---------------------------------------------------------------------- */ static void* mjpg_yuv_init(struct ng_video_fmt *out, void *priv) { struct mjpeg_compress *h; struct mjpeg_yuv_priv *c = priv; if (ng_debug > 1) fprintf(stderr,"mjpg_yuv_init\n"); h = mjpg_init(out); if (NULL == h) return NULL; h->mjpg_cinfo.input_components = 3; h->mjpg_cinfo.in_color_space = JCS_YCbCr; jpeg_set_defaults(&h->mjpg_cinfo); h->mjpg_cinfo.dct_method = JDCT_FASTEST; jpeg_set_quality(&h->mjpg_cinfo, ng_jpeg_quality, TRUE); h->mjpg_cinfo.raw_data_in = TRUE; jpeg_set_colorspace(&h->mjpg_cinfo,JCS_YCbCr); h->mjpg_ptrs[0] = malloc(h->fmt.height*sizeof(char*)); h->mjpg_ptrs[1] = malloc(h->fmt.height*sizeof(char*)); h->mjpg_ptrs[2] = malloc(h->fmt.height*sizeof(char*)); h->mjpg_cinfo.comp_info[0].h_samp_factor = c->luma_h; h->mjpg_cinfo.comp_info[0].v_samp_factor = c->luma_v; h->mjpg_cinfo.comp_info[1].h_samp_factor = 1; h->mjpg_cinfo.comp_info[1].v_samp_factor = 1; h->mjpg_cinfo.comp_info[2].h_samp_factor = 1; h->mjpg_cinfo.comp_info[2].v_samp_factor = 1; jpeg_suppress_tables(&h->mjpg_cinfo, TRUE); return h; } static void mjpg_420_compress(struct mjpeg_compress *h) { unsigned char **mjpg_run[3]; unsigned int y; mjpg_run[0] = h->mjpg_ptrs[0]; mjpg_run[1] = h->mjpg_ptrs[1]; mjpg_run[2] = h->mjpg_ptrs[2]; jpeg_start_compress(&h->mjpg_cinfo, h->mjpg_tables); for (y = 0; y < h->mjpg_cinfo.image_height; y += 2*DCTSIZE) { jpeg_write_raw_data(&h->mjpg_cinfo, mjpg_run,2*DCTSIZE); mjpg_run[0] += 2*DCTSIZE; mjpg_run[1] += DCTSIZE; mjpg_run[2] += DCTSIZE; } jpeg_finish_compress(&h->mjpg_cinfo); } static void mjpg_422_compress(struct mjpeg_compress *h) { unsigned char **mjpg_run[3]; unsigned int y; mjpg_run[0] = h->mjpg_ptrs[0]; mjpg_run[1] = h->mjpg_ptrs[1]; mjpg_run[2] = h->mjpg_ptrs[2]; h->mjpg_cinfo.write_JFIF_header = FALSE; jpeg_start_compress(&h->mjpg_cinfo, h->mjpg_tables); jpeg_write_marker(&h->mjpg_cinfo, JPEG_APP0, "AVI1\0\0\0\0", 8); for (y = 0; y < h->mjpg_cinfo.image_height; y += DCTSIZE) { jpeg_write_raw_data(&h->mjpg_cinfo, mjpg_run, DCTSIZE); mjpg_run[0] += DCTSIZE; mjpg_run[1] += DCTSIZE; mjpg_run[2] += DCTSIZE; } jpeg_finish_compress(&h->mjpg_cinfo); } /* ---------------------------------------------------------------------- */ static void mjpg_422_420_compress(void *handle, struct ng_video_buf *out, struct ng_video_buf *in) { struct mjpeg_compress *h = handle; unsigned char *line; unsigned int i; if (ng_debug > 1) fprintf(stderr,"mjpg_422_420_compress\n"); h->mjpg_buffer = out->data; h->mjpg_bufsize = out->size; line = in->data; for (i = 0; i < h->mjpg_cinfo.image_height; i++, line += in->fmt.width) h->mjpg_ptrs[0][i] = line; line = in->data + in->fmt.width*in->fmt.height; for (i = 0; i < h->mjpg_cinfo.image_height; i+=2, line += in->fmt.width) h->mjpg_ptrs[1][i/2] = line; line = in->data + in->fmt.width*in->fmt.height*3/2; for (i = 0; i < h->mjpg_cinfo.image_height; i+=2, line += in->fmt.width) h->mjpg_ptrs[2][i/2] = line; mjpg_420_compress(h); out->size = h->mjpg_bufused; } static void mjpg_420_420_compress(void *handle, struct ng_video_buf *out, struct ng_video_buf *in) { struct mjpeg_compress *h = handle; unsigned char *line; unsigned int i; if (ng_debug > 1) fprintf(stderr,"mjpg_420_420_compress\n"); h->mjpg_buffer = out->data; h->mjpg_bufsize = out->size; line = in->data; for (i = 0; i < h->mjpg_cinfo.image_height; i++, line += in->fmt.width) h->mjpg_ptrs[0][i] = line; line = in->data + in->fmt.width*in->fmt.height; for (i = 0; i < h->mjpg_cinfo.image_height; i+=2, line += in->fmt.width/2) h->mjpg_ptrs[1][i/2] = line; line = in->data + in->fmt.width*in->fmt.height*5/4; for (i = 0; i < h->mjpg_cinfo.image_height; i+=2, line += in->fmt.width/2) h->mjpg_ptrs[2][i/2] = line; mjpg_420_compress(h); out->size = h->mjpg_bufused; } /* ---------------------------------------------------------------------- */ static void mjpg_422_422_compress(void *handle, struct ng_video_buf *out, struct ng_video_buf *in) { struct mjpeg_compress *h = handle; unsigned char *line; unsigned int i; if (ng_debug > 1) fprintf(stderr,"mjpg_422_422_compress\n"); h->mjpg_buffer = out->data; h->mjpg_bufsize = out->size; line = in->data; for (i = 0; i < h->mjpg_cinfo.image_height; i++, line += in->fmt.width) h->mjpg_ptrs[0][i] = line; line = in->data + in->fmt.width*in->fmt.height; for (i = 0; i < h->mjpg_cinfo.image_height; i++, line += in->fmt.width/2) h->mjpg_ptrs[1][i] = line; line = in->data + in->fmt.width*in->fmt.height*3/2; for (i = 0; i < h->mjpg_cinfo.image_height; i++, line += in->fmt.width/2) h->mjpg_ptrs[2][i] = line; mjpg_422_compress(h); out->size = h->mjpg_bufused; } /* ---------------------------------------------------------------------- */ /* decompress */ static void* mjpg_de_init(struct ng_video_fmt *fmt, void *priv) { struct mjpeg_decompress *h; h = malloc(sizeof(*h)); if (NULL == h) return NULL; memset(h,0,sizeof(*h)); h->fmt = *fmt; h->mjpg_cinfo.err = jpeg_std_error(&h->mjpg_jerr); jpeg_create_decompress(&h->mjpg_cinfo); jpeg_load_dht((j_common_ptr)&h->mjpg_cinfo, h->mjpg_cinfo.ac_huff_tbl_ptrs, h->mjpg_cinfo.dc_huff_tbl_ptrs); h->mjpg_src.init_source = mjpg_src_init; h->mjpg_src.fill_input_buffer = mjpg_src_fill; h->mjpg_src.skip_input_data = mjpg_src_skip; h->mjpg_src.resync_to_restart = jpeg_resync_to_restart; h->mjpg_src.term_source = mjpg_src_term; h->mjpg_cinfo.src = &h->mjpg_src; switch (h->fmt.fmtid) { case VIDEO_YUV420P: h->mjpg_ptrs[0] = malloc(h->fmt.height*sizeof(char*)); h->mjpg_ptrs[1] = malloc(h->fmt.height*sizeof(char*)); h->mjpg_ptrs[2] = malloc(h->fmt.height*sizeof(char*)); break; } return h; } static void mjpg_rgb_decompress(void *handle, struct ng_video_buf *out, struct ng_video_buf *in) { struct mjpeg_decompress *h = handle; unsigned char *line; unsigned int i; if (ng_debug > 1) fprintf(stderr,"mjpg_rgb_decompress\n"); h->buf = in; jpeg_read_header(&h->mjpg_cinfo,1); h->mjpg_cinfo.out_color_space = JCS_RGB; jpeg_start_decompress(&h->mjpg_cinfo); for (i = 0, line = out->data; i < out->fmt.height; i++, line += out->fmt.bytesperline) { jpeg_read_scanlines(&h->mjpg_cinfo, &line, 1); } jpeg_finish_decompress(&h->mjpg_cinfo); } static void mjpg_yuv420_decompress(void *handle, struct ng_video_buf *out, struct ng_video_buf *in) { struct mjpeg_decompress *h = handle; unsigned char **mjpg_run[3]; unsigned char *line; unsigned int i,y; if (ng_debug > 1) fprintf(stderr,"mjpg_yuv_decompress\n"); h->buf = in; jpeg_read_header(&h->mjpg_cinfo,1); h->mjpg_cinfo.raw_data_out = 1; if (ng_debug > 1) fprintf(stderr,"yuv: %dx%d - %d %d / %d %d / %d %d\n", h->mjpg_cinfo.image_width, h->mjpg_cinfo.image_height, h->mjpg_cinfo.comp_info[0].h_samp_factor, h->mjpg_cinfo.comp_info[0].v_samp_factor, h->mjpg_cinfo.comp_info[1].h_samp_factor, h->mjpg_cinfo.comp_info[1].v_samp_factor, h->mjpg_cinfo.comp_info[2].h_samp_factor, h->mjpg_cinfo.comp_info[2].v_samp_factor); jpeg_start_decompress(&h->mjpg_cinfo); mjpg_run[0] = h->mjpg_ptrs[0]; mjpg_run[1] = h->mjpg_ptrs[1]; mjpg_run[2] = h->mjpg_ptrs[2]; line = out->data; for (i = 0; i < h->mjpg_cinfo.image_height; i++, line += out->fmt.width) h->mjpg_ptrs[0][i] = line; if (2 == h->mjpg_cinfo.comp_info[0].v_samp_factor) { /* file has 420 -- all fine */ line = out->data + out->fmt.width*out->fmt.height; for (i = 0; i < out->fmt.height; i+=2, line += out->fmt.width/2) h->mjpg_ptrs[1][i/2] = line; line = out->data + out->fmt.width*out->fmt.height*5/4; for (i = 0; i < out->fmt.height; i+=2, line += out->fmt.width/2) h->mjpg_ptrs[2][i/2] = line; for (y = 0; y < out->fmt.height; y += 2*DCTSIZE) { jpeg_read_raw_data(&h->mjpg_cinfo, mjpg_run,2*DCTSIZE); mjpg_run[0] += 2*DCTSIZE; mjpg_run[1] += DCTSIZE; mjpg_run[2] += DCTSIZE; } } else { /* file has 422 -- drop lines */ line = out->data + out->fmt.width*out->fmt.height; for (i = 0; i < out->fmt.height; i+=2, line += out->fmt.width/2) { h->mjpg_ptrs[1][i+0] = line; h->mjpg_ptrs[1][i+1] = line; } line = out->data + out->fmt.width*out->fmt.height*5/4; for (i = 0; i < out->fmt.height; i+=2, line += out->fmt.width/2) { h->mjpg_ptrs[2][i+0] = line; h->mjpg_ptrs[2][i+1] = line; } for (y = 0; y < h->mjpg_cinfo.image_height; y += DCTSIZE) { jpeg_read_raw_data(&h->mjpg_cinfo, mjpg_run,DCTSIZE); mjpg_run[0] += DCTSIZE; mjpg_run[1] += DCTSIZE; mjpg_run[2] += DCTSIZE; } } jpeg_finish_decompress(&h->mjpg_cinfo); } static void mjpg_de_cleanup(void *handle) { struct mjpeg_decompress *h = handle; if (ng_debug > 1) fprintf(stderr,"mjpg_de_cleanup\n"); jpeg_destroy_decompress(&h->mjpg_cinfo); if (h->mjpg_ptrs[0]) free(h->mjpg_ptrs[0]); if (h->mjpg_ptrs[1]) free(h->mjpg_ptrs[1]); if (h->mjpg_ptrs[2]) free(h->mjpg_ptrs[2]); free(h); } /* ---------------------------------------------------------------------- */ /* static data + register */ static struct mjpeg_yuv_priv priv_420 = { luma_h: 2, luma_v: 2, }; static struct mjpeg_yuv_priv priv_422 = { luma_h: 2, luma_v: 1, }; static struct ng_video_conv mjpg_list[] = { { /* --- compress --- */ .init= mjpg_yuv_init, .p.frame= mjpg_420_420_compress, .p.fini= mjpg_cleanup, .p.mode= NG_MODE_TRIVIAL, .fmtid_in= VIDEO_YUV420P, .fmtid_out= VIDEO_JPEG, .priv= &priv_420, },{ .init= mjpg_yuv_init, .p.frame= mjpg_422_420_compress, .p.fini= mjpg_cleanup, .p.mode= NG_MODE_TRIVIAL, .fmtid_in= VIDEO_YUV422P, .fmtid_out= VIDEO_JPEG, .priv= &priv_420, },{ .init= mjpg_rgb_init, .p.frame= mjpg_rgb_compress, .p.fini= mjpg_cleanup, .p.mode= NG_MODE_TRIVIAL, .fmtid_in= VIDEO_RGB24, .fmtid_out= VIDEO_JPEG, },{ .init= mjpg_rgb_init, .p.frame= mjpg_bgr_compress, .p.fini= mjpg_cleanup, .p.mode= NG_MODE_TRIVIAL, .fmtid_in= VIDEO_BGR24, .fmtid_out= VIDEO_JPEG, },{ .init= mjpg_yuv_init, .p.frame= mjpg_422_422_compress, .p.fini= mjpg_cleanup, .p.mode= NG_MODE_TRIVIAL, .fmtid_in= VIDEO_YUV422P, .fmtid_out= VIDEO_MJPEG, .priv= &priv_422, },{ /* --- uncompress --- */ .init= mjpg_de_init, .p.frame= mjpg_rgb_decompress, .p.fini= mjpg_de_cleanup, .p.mode= NG_MODE_TRIVIAL, .fmtid_in= VIDEO_MJPEG, .fmtid_out= VIDEO_RGB24, },{ .init= mjpg_de_init, .p.frame= mjpg_rgb_decompress, .p.fini= mjpg_de_cleanup, .p.mode= NG_MODE_TRIVIAL, .fmtid_in= VIDEO_JPEG, .fmtid_out= VIDEO_RGB24, },{ .init= mjpg_de_init, .p.frame= mjpg_yuv420_decompress, .p.fini= mjpg_de_cleanup, .p.mode= NG_MODE_TRIVIAL, .fmtid_in= VIDEO_MJPEG, .fmtid_out= VIDEO_YUV420P, },{ .init= mjpg_de_init, .p.frame= mjpg_yuv420_decompress, .p.fini= mjpg_de_cleanup, .p.mode= NG_MODE_TRIVIAL, .fmtid_in= VIDEO_JPEG, .fmtid_out= VIDEO_YUV420P, } }; static const int nconv = sizeof(mjpg_list)/sizeof(struct ng_video_conv); //extern void ng_plugin_init(void); static void __init ng_plugin_init(void) { ng_conv_register(NG_PLUGIN_MAGIC,__FILE__,mjpg_list,nconv); } // Here are huffmann tables /* JPEG DHT Segment for YCrCb omitted from MJPG data */ static unsigned char jpeg_odml_dht[0x1a4] = { 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa }; /* Parse the DHT table */ int jpeg_load_dht (j_common_ptr info, JHUFF_TBL* ac_tables[], JHUFF_TBL* dc_tables[]) { unsigned int length = (jpeg_odml_dht[2] << 8) + jpeg_odml_dht[3] - 2; unsigned int pos = 4; unsigned int count, i; int index; JHUFF_TBL **hufftbl; unsigned char bits[17]; unsigned char huffval[256]; while (length > 16) { bits[0] = 0; index = jpeg_odml_dht[pos++]; count = 0; for (i = 1; i <= 16; ++i) { bits[i] = jpeg_odml_dht[pos++]; count += bits[i]; } length -= 17; if (count > 256 || count > length) return -1; for (i = 0; i < count; ++i) huffval[i] = jpeg_odml_dht[pos++]; length -= count; if (index & 0x10) { index -= 0x10; hufftbl = &ac_tables[index]; } else hufftbl = &dc_tables[index]; if (index < 0 || index >= NUM_HUFF_TBLS) return -1; if (*hufftbl == NULL) *hufftbl = jpeg_alloc_huff_table (info); if (*hufftbl == NULL) return -1; memcpy((*hufftbl)->bits, bits, sizeof (*hufftbl)->bits); memcpy((*hufftbl)->huffval, huffval, sizeof (*hufftbl)->huffval); } if (length != 0) return -1; return 0; } amsn-0.98.9/utils/linux/capture/libng/plugins/drv0-bsd.c0000644000175000017500000005531010246003435022675 0ustar billiobbilliob/* * interface to the bsd bktr driver * * (c) 2000-04 Gerd Knorr * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(HAVE_DEV_IC_BT8XX_H) # include #elif defined(HAVE_DEV_BKTR_IOCTL_BT848_H) # include # include #else # include # include #endif #include "grab-ng.h" /* ---------------------------------------------------------------------- */ /* global variables */ struct bsd_handle { int fd; int tfd; char *device; char *tdevice; /* formats */ int pf_count; struct meteor_pixfmt pf[64]; int xawtv2pf[VIDEO_FMT_COUNT]; unsigned char *map; /* attributes */ int muted; struct ng_attribute *attr; /* overlay */ struct meteor_video fb,pos; struct meteor_geomet ovgeo; struct meteor_pixfmt *ovfmt; struct bktr_clip clip[BT848_MAX_CLIP_NODE]; int ov_enabled,ov_on; /* capture */ int fps; long long start; struct ng_video_fmt fmt; struct meteor_video nofb; struct meteor_geomet capgeo; struct meteor_pixfmt *capfmt; struct bktr_clip noclip[BT848_MAX_CLIP_NODE]; }; /* ---------------------------------------------------------------------- */ /* prototypes */ /* open/close */ static void* bsd_init(char *device); static int bsd_open(void *handle); static int bsd_close(void *handle); static int bsd_fini(void *handle); static char* bsd_devname(void *handle); static struct ng_devinfo* bsd_probe(void); /* attributes */ static int bsd_flags(void *handle); static struct ng_attribute* bsd_attrs(void *handle); static int bsd_read_attr(struct ng_attribute*); static void bsd_write_attr(struct ng_attribute*, int val); #if 0 static int bsd_setupfb(void *handle, struct ng_video_fmt *fmt, void *base); static int bsd_overlay(void *handle, struct ng_video_fmt *fmt, int x, int y, struct OVERLAY_CLIP *oc, int count, int aspect); #endif /* capture */ static void catchsignal(int signal); static void siginit(void); static int bsd_setformat(void *handle, struct ng_video_fmt *fmt); static int bsd_startvideo(void *handle, int fps, unsigned int buffers); static void bsd_stopvideo(void *handle); static struct ng_video_buf* bsd_nextframe(void *handle); static struct ng_video_buf* bsd_getimage(void *handle); /* tuner */ static unsigned long bsd_getfreq(void *handle); static void bsd_setfreq(void *handle, unsigned long freq); static int bsd_tuned(void *handle); struct ng_vid_driver bsd_driver = { .name = "bktr", .priority = 1, .init = bsd_init, .open = bsd_open, .close = bsd_close, .fini = bsd_fini, .devname = bsd_devname, .probe = bsd_probe, .capabilities = bsd_flags, .list_attrs = bsd_attrs, #if 0 .setupfb = bsd_setupfb, .overlay = bsd_overlay, #endif .setformat = bsd_setformat, .startvideo = bsd_startvideo, .stopvideo = bsd_stopvideo, .nextframe = bsd_nextframe, .getimage = bsd_getimage, .getfreq = bsd_getfreq, .setfreq = bsd_setfreq, .is_tuned = bsd_tuned, }; /* ---------------------------------------------------------------------- */ static struct STRTAB inputs[] = { { 0, "Television" }, { 1, "Composite1" }, { 2, "S-Video" }, { 3, "CSVIDEO" }, { -1, NULL } }; static long inputs_map[] = { METEOR_INPUT_DEV1, METEOR_INPUT_DEV0, METEOR_INPUT_DEV_SVIDEO, METEOR_INPUT_DEV2, }; static struct STRTAB norms[] = { { 0, "NTSC" }, { 1, "NTSC-JP" }, { 2, "PAL" }, { 3, "PAL-M" }, { 4, "PAL-N" }, { 5, "SECAM" }, { 6, "RSVD" }, { -1, NULL } }; static long norms_map[] = { BT848_IFORM_F_NTSCM, BT848_IFORM_F_NTSCJ, BT848_IFORM_F_PALBDGHI, BT848_IFORM_F_PALM, BT848_IFORM_F_PALN, BT848_IFORM_F_SECAM, BT848_IFORM_F_RSVD, }; static struct STRTAB audio[] = { { 0, "Tuner" }, { 1, "Extern" }, { 2, "Intern" }, { -1, NULL } }; static long audio_map[] = { AUDIO_TUNER, AUDIO_EXTERN, AUDIO_INTERN, }; static struct ng_attribute bsd_attr[] = { { .id = ATTR_ID_COUNT+1, .name = "audio", .priority = 2, .type = ATTR_TYPE_CHOICE, .choices = audio, .read = bsd_read_attr, .write = bsd_write_attr, },{ .id = ATTR_ID_NORM, .name = "norm", .priority = 2, .type = ATTR_TYPE_CHOICE, .choices = norms, .read = bsd_read_attr, .write = bsd_write_attr, },{ .id = ATTR_ID_INPUT, .name = "input", .priority = 2, .type = ATTR_TYPE_CHOICE, .choices = inputs, .read = bsd_read_attr, .write = bsd_write_attr, },{ .id = ATTR_ID_MUTE, .name = "mute", .priority = 2, .type = ATTR_TYPE_BOOL, .read = bsd_read_attr, .write = bsd_write_attr, },{ .id = ATTR_ID_HUE, .name = "hue", .priority = 2, .type = ATTR_TYPE_INTEGER, .min = BT848_HUEREGMIN, .max = BT848_HUEREGMAX, .read = bsd_read_attr, .write = bsd_write_attr, },{ .id = ATTR_ID_BRIGHT, .name = "bright", .priority = 2, .type = ATTR_TYPE_INTEGER, .min = BT848_BRIGHTREGMIN, .max = BT848_BRIGHTREGMAX, .read = bsd_read_attr, .write = bsd_write_attr, },{ .id = ATTR_ID_CONTRAST, .name = "contrast", .priority = 2, .type = ATTR_TYPE_INTEGER, .min = BT848_CONTRASTREGMIN, .max = BT848_CONTRASTREGMAX, .read = bsd_read_attr, .write = bsd_write_attr, },{ .id = ATTR_ID_COLOR, .name = "color", .priority = 2, .type = ATTR_TYPE_INTEGER, .min = BT848_CHROMAREGMIN, .max = BT848_CHROMAREGMAX, .read = bsd_read_attr, .write = bsd_write_attr, },{ /* end of list */ } }; static int single = METEOR_CAP_SINGLE; static int start = METEOR_CAP_CONTINOUS; static int stop = METEOR_CAP_STOP_CONT; static int signal_on = SIGUSR1; static int signal_off = METEOR_SIG_MODE_MASK; /* ---------------------------------------------------------------------- */ #define PREFIX "bktr: ioctl: " static int xioctl(int fd, unsigned long cmd, void *arg) { int rc; rc = ioctl(fd,cmd,arg); if (0 == rc && ng_debug < 2) return 0; switch (cmd) { case METEORSVIDEO: { struct meteor_video *a = arg; fprintf(stderr,PREFIX "METEORSVIDEO(addr=0x%08lx,width=%ld,bank=%ld,ram=%ld)", a->addr,a->width,a->banksize,a->ramsize); break; } case METEORSETGEO: { struct meteor_geomet *a = arg; fprintf(stderr,PREFIX "METEORSETGEO(%dx%d,frames=%d,oformat=0x%lx)", a->columns,a->rows,a->frames,a->oformat); break; } case METEORSACTPIXFMT: { struct meteor_pixfmt *a = arg; fprintf(stderr,PREFIX "METEORSACTPIXFMT(%d,type=%d,bpp=%d," "masks=0x%lx/0x%lx/0x%lx,sb=%d,ss=%d)", a->index,a->type,a->Bpp,a->masks[0],a->masks[1],a->masks[2], a->swap_bytes,a->swap_shorts); break; } case METEORCAPTUR: { int *a = arg; fprintf(stderr,PREFIX "METEORCAPTUR(%d)",*a); break; } case METEORSSIGNAL: { int *a = arg; fprintf(stderr,PREFIX "METEORSSIGNAL(0x%x)",*a); break; } case BT848SCLIP: { fprintf(stderr,PREFIX "BT848SCLIP"); break; } default: fprintf(stderr,PREFIX "UNKNOWN(cmd=0x%lx)",cmd); break; } fprintf(stderr,": %s\n",(rc == 0) ? "ok" : strerror(errno)); return rc; } /* ---------------------------------------------------------------------- */ static void bsd_print_format(struct meteor_pixfmt *pf, int format) { switch (pf->type) { case METEOR_PIXTYPE_RGB: fprintf(stderr, "bktr: pf: rgb bpp=%d mask=%ld,%ld,%ld", pf->Bpp,pf->masks[0],pf->masks[1],pf->masks[2]); break; case METEOR_PIXTYPE_YUV: fprintf(stderr,"bktr: pf: yuv h422 v111 (planar)"); break; case METEOR_PIXTYPE_YUV_PACKED: fprintf(stderr,"bktr: pf: yuyv h422 v111 (packed)"); break; case METEOR_PIXTYPE_YUV_12: fprintf(stderr,"bktr: pf: yuv h422 v422 (planar)"); break; default: fprintf(stderr,"bktr: pf: unknown"); } fprintf(stderr," sbytes=%d sshorts=%d (fmt=%d)\n", pf->swap_bytes,pf->swap_shorts,format); } /* ---------------------------------------------------------------------- */ static int bsd_open(void *handle) { struct bsd_handle *h = handle; BUG_ON(h->fd != -1,"device is open"); if (ng_debug) fprintf(stderr, "bktr: open\n"); if (-1 == (h->fd = open(h->device,O_RDONLY))) { fprintf(stderr,"bktr: open %s: %s\n", h->device, strerror(errno)); goto err1; } if (-1 == (h->tfd = open(h->tdevice,O_RDONLY))) { fprintf(stderr,"bktr: open %s: %s\n", h->tdevice, strerror(errno)); goto err2; } h->map = mmap(0,768*576*4, PROT_READ, MAP_SHARED, h->fd, 0); if (MAP_FAILED == h->map) { perror("bktr: mmap"); h->map = NULL; goto err3; } return 0; err3: close(h->tfd); h->tfd = -1; err2: close(h->fd); h->fd = -1; err1: return -1; } static int bsd_close(void *handle) { struct bsd_handle *h = handle; BUG_ON(h->fd == -1,"device not open"); if (ng_debug) fprintf(stderr, "bktr: close\n"); close(h->fd); if (-1 != h->tfd) close(h->tfd); if (NULL != h->map) munmap(h->map,768*576*4); h->fd = -1; h->tfd = -1; return 0; } static int bsd_fini(void *handle) { struct bsd_handle *h = handle; BUG_ON(h->fd != -1,"device is open"); if (ng_debug) fprintf(stderr, "bktr: fini\n"); if (h->device) free(h->device); if (h->tdevice) free(h->tdevice); if (h->attr) free(h->attr); free(h); return 0; } static void* bsd_init(char *filename) { struct bsd_handle *h; int format,i; if (NULL == filename) return NULL; if (0 != strncmp(filename,"/dev/",5)) return NULL; h = malloc(sizeof(*h)); if (NULL == h) return NULL; memset(h,0,sizeof(*h)); h->fd = -1; h->tfd = -1; h->device = strdup(filename); h->tdevice = strdup("/dev/tuner0"); // FIXME if (-1 == bsd_open(h)) goto err1; /* video formats */ for (format = 0; format < VIDEO_FMT_COUNT; format++) h->xawtv2pf[format] = -1; for (h->pf_count = 0; h->pf_count < 64; h->pf_count++) { h->pf[h->pf_count].index = h->pf_count; if (-1 == ioctl(h->fd, METEORGSUPPIXFMT,h->pf+h->pf_count)) { if (ng_debug) perror("bktr: ioctl METEORGSUPPIXFMT"); if (0 == h->pf_count) goto err2; break; } format = -1; switch (h->pf[h->pf_count].type) { case METEOR_PIXTYPE_RGB: switch(h->pf[h->pf_count].masks[0]) { case 31744: /* 15 bpp */ format = h->pf[h->pf_count].swap_bytes ? VIDEO_RGB15_LE : VIDEO_RGB15_BE; break; case 63488: /* 16 bpp */ format = h->pf[h->pf_count].swap_bytes ? VIDEO_RGB16_LE : VIDEO_RGB16_BE; break; case 16711680: /* 24/32 bpp */ if (h->pf[h->pf_count].Bpp == 3 && h->pf[h->pf_count].swap_bytes == 1) { format = VIDEO_BGR24; } else if (h->pf[h->pf_count].Bpp == 4 && h->pf[h->pf_count].swap_bytes == 1 && h->pf[h->pf_count].swap_shorts == 1) { format = VIDEO_BGR32; } else if (h->pf[h->pf_count].Bpp == 4 && h->pf[h->pf_count].swap_bytes == 0 && h->pf[h->pf_count].swap_shorts == 0) { format = VIDEO_RGB32; } } break; case METEOR_PIXTYPE_YUV: format = VIDEO_YUV422P; break; #if 0 case METEOR_PIXTYPE_YUV_PACKED: format = VIDEO_YUV422; h->pf[h->pf_count].swap_shorts = 0; /* seems not to work */ break; #endif case METEOR_PIXTYPE_YUV_12: case METEOR_PIXTYPE_YUV_PACKED: /* nothing */ break; } if (-1 != format) h->xawtv2pf[format] = h->pf_count; if (ng_debug) bsd_print_format(h->pf+h->pf_count,format); } bsd_close(h); siginit(); h->attr = malloc(sizeof(bsd_attr)); memcpy(h->attr,bsd_attr,sizeof(bsd_attr)); for (i = 0; h->attr[i].name != NULL; i++) h->attr[i].handle = h; return h; err2: bsd_close(h); err1: bsd_fini(h); return NULL; } static char* bsd_devname(void *handle) { return "bsd bkdr device"; } static struct ng_devinfo* bsd_probe(void) { struct ng_devinfo *info = NULL; int i,n,fd,status; n = 0; for (i = 0; NULL != ng_dev.video_scan[i]; i++) { fd = open(ng_dev.video_scan[i], O_RDONLY); if (-1 == fd) continue; if (-1 == ioctl(fd,BT848_GSTATUS,&status)) { close(fd); continue; } info = realloc(info,sizeof(*info) * (n+2)); memset(info+n,0,sizeof(*info)*2); strcpy(info[n].device, ng_dev.video_scan[i]); sprintf(info[n].name, ng_dev.video_scan[i]); close(fd); n++; } return info; } static int bsd_flags(void *handle) { int ret = 0; ret |= CAN_CAPTURE; ret |= CAN_TUNE; return ret; } static struct ng_attribute* bsd_attrs(void *handle) { struct bsd_handle *h = handle; return h->attr; } /* ---------------------------------------------------------------------- */ static int bsd_get_range(int id, int *get, long *set) { switch (id) { case ATTR_ID_HUE: *get = BT848_GHUE; *set = BT848_SHUE; break; case ATTR_ID_BRIGHT: *get = BT848_GBRIG; *set = BT848_SBRIG; break; case ATTR_ID_CONTRAST: *get = BT848_GCONT; *set = BT848_SCONT; break; case ATTR_ID_COLOR: *get = BT848_GCSAT; *set = BT848_SCSAT; break; default: return -1; } return 0; } static int bsd_read_attr(struct ng_attribute *attr) { struct bsd_handle *h = attr->handle; int get, i; long arg, set; int value = -1; BUG_ON(h->fd == -1,"device not open"); switch (attr->id) { case ATTR_ID_NORM: if (-1 != xioctl(h->fd,BT848GFMT,&arg)) for (i = 0; i < sizeof(norms_map)/sizeof(*norms_map); i++) if (arg == norms_map[i]) value = i; break; case ATTR_ID_INPUT: if (-1 != xioctl(h->fd,METEORGINPUT,&arg)) for (i = 0; i < sizeof(inputs_map)/sizeof(*inputs_map); i++) if (arg == inputs_map[i]) value = i; break; case ATTR_ID_MUTE: if (-1 != xioctl(h->tfd, BT848_GAUDIO, &arg)) value = (arg == AUDIO_MUTE) ? 1 : 0; break; case ATTR_ID_HUE: case ATTR_ID_BRIGHT: case ATTR_ID_CONTRAST: case ATTR_ID_COLOR: bsd_get_range(attr->id,&get,&set); if (-1 != xioctl(h->tfd,get,&arg)) value = arg; break; case ATTR_ID_COUNT+1: /* AUDIO */ if (-1 != xioctl(h->tfd, BT848_GAUDIO, &arg)) for (i = 0; i < sizeof(audio_map)/sizeof(*audio_map); i++) if (arg == audio_map[i]) value = i; break; default: break; } return value; } static void bsd_write_attr(struct ng_attribute *attr, int value) { struct bsd_handle *h = attr->handle; int get; long arg, set; BUG_ON(h->fd == -1,"device not open"); switch (attr->id) { case ATTR_ID_NORM: xioctl(h->fd,BT848SFMT,&norms_map[value]); break; case ATTR_ID_INPUT: xioctl(h->fd,METEORSINPUT,&inputs_map[value]); break; case ATTR_ID_MUTE: h->muted = value; arg = h->muted ? AUDIO_MUTE : AUDIO_UNMUTE; xioctl(h->tfd, BT848_SAUDIO, &arg); break; case ATTR_ID_HUE: case ATTR_ID_BRIGHT: case ATTR_ID_CONTRAST: case ATTR_ID_COLOR: bsd_get_range(attr->id,&get,&set); arg = value; xioctl(h->tfd,set,&arg); break; case ATTR_ID_COUNT+1: /* audio */ xioctl(h->tfd, BT848_SAUDIO,&audio_map[value]); break; default: break; } } static unsigned long bsd_getfreq(void *handle) { struct bsd_handle *h = handle; unsigned long freq = 0; BUG_ON(h->fd == -1,"device not open"); if (-1 == ioctl(h->tfd, TVTUNER_GETFREQ, &freq)) perror("bktr: ioctl TVTUNER_GETFREQ"); if (ng_debug) fprintf(stderr,"bktr: get freq: %.3f\n",(float)freq/16); return freq; } static void bsd_setfreq(void *handle, unsigned long freq) { struct bsd_handle *h = handle; BUG_ON(h->fd == -1,"device not open"); if (ng_debug) fprintf(stderr,"bktr: set freq: %.3f\n",(float)freq/16); if (-1 == ioctl(h->tfd, TVTUNER_SETFREQ, &freq)) perror("bktr: ioctl TVTUNER_SETFREQ"); } static int bsd_tuned(void *handle) { struct bsd_handle *h = handle; int signal; BUG_ON(h->fd == -1,"device not open"); usleep(10000); if (-1 == xioctl(h->tfd, TVTUNER_GETSTATUS, &signal)) return 0; return signal == 106 ? 1 : 0; } /* ---------------------------------------------------------------------- */ /* overlay */ static void set_overlay(struct bsd_handle *h, int state) { if (h->ov_on == state) return; h->ov_on = state; if (state) { /* enable */ xioctl(h->fd, METEORSVIDEO, &h->pos); xioctl(h->fd, METEORSETGEO, &h->ovgeo); xioctl(h->fd, METEORSACTPIXFMT, h->ovfmt); xioctl(h->fd, BT848SCLIP, &h->clip); xioctl(h->fd, METEORCAPTUR, &start); } else { /* disable */ xioctl(h->fd, METEORCAPTUR, &stop); } } #if 0 static int bsd_setupfb(void *handle, struct ng_video_fmt *fmt, void *base) { struct bsd_handle *h = handle; h->fb.addr = (long)base; h->fb.width = fmt->bytesperline; h->fb.banksize = fmt->bytesperline * fmt->height; h->fb.ramsize = fmt->bytesperline * fmt->height / 1024; return 0; } static int bsd_overlay(void *handle, struct ng_video_fmt *fmt, int x, int y, struct OVERLAY_CLIP *oc, int count, int aspect) { struct bsd_handle *h = handle; int i,win_width,win_height,win_x,win_y; h->ov_enabled = 0; set_overlay(h,h->ov_enabled); if (NULL == fmt) return 0; if (-1 == h->xawtv2pf[fmt->fmtid]) return -1; /* fixups - fixme: no fixed max size */ win_x = x; win_y = y; win_width = fmt->width; win_height = fmt->height; if (win_width > 768) { win_width = 768; win_x += (fmt->width - win_width)/2; } if (win_height > 576) { win_height = 576; win_y += (fmt->height - win_height)/2; } if (aspect) ng_ratio_fixup(&win_width,&win_height,&win_x,&win_y); ng_check_clipping(win_width, win_height, x - win_x, y - win_y, oc, &count); /* fill data */ h->pos = h->fb; h->pos.addr += win_y*h->pos.width; h->pos.addr += win_x*ng_vfmt_to_depth[fmt->fmtid]>>3; h->ovgeo.rows = win_height; h->ovgeo.columns = win_width; h->ovgeo.frames = 1; h->ovgeo.oformat = 0x10000; if (ng_debug) fprintf(stderr,"bktr: overlay win=%dx%d+%d+%d, %d clips\n", win_width,win_height,win_x,win_y,count); /* clipping */ memset(h->clip,0,sizeof(h->clip)); for (i = 0; i < count; i++) { #if 0 /* This way it *should* work IMHO ... */ h->clip[i].x_min = oc[i].x1; h->clip[i].x_max = oc[i].x2; h->clip[i].y_min = oc[i].y1; h->clip[i].y_max = oc[i].y2; #else /* This way it does work. Sort of ... */ h->clip[i].x_min = (oc[i].y1) >> 1; h->clip[i].x_max = (oc[i].y2) >> 1; h->clip[i].y_min = oc[i].x1; h->clip[i].y_max = oc[i].x2; #endif } h->ovfmt = h->pf+h->xawtv2pf[fmt->fmtid]; h->ov_enabled = 1; set_overlay(h,h->ov_enabled); return 0; } #endif /* ---------------------------------------------------------------------- */ /* capture */ static void catchsignal(int signal) { if (signal == SIGUSR1 && ng_debug > 1) fprintf(stderr,"bktr: sigusr1\n"); if (signal == SIGALRM) fprintf(stderr,"bktr: sigalrm\n"); } static void siginit(void) { struct sigaction act,old; memset(&act,0,sizeof(act)); sigemptyset(&act.sa_mask); act.sa_handler = catchsignal; sigaction(SIGUSR1,&act,&old); sigaction(SIGALRM,&act,&old); } static int bsd_setformat(void *handle, struct ng_video_fmt *fmt) { struct bsd_handle *h = handle; BUG_ON(h->fd == -1,"device not open"); if (-1 == h->xawtv2pf[fmt->fmtid]) return -1; if (fmt->width > 768) fmt->width = 768; if (fmt->height > 576) fmt->height = 576; fmt->bytesperline = fmt->width * ng_vfmt_to_depth[fmt->fmtid] / 8; h->capfmt = h->pf+h->xawtv2pf[fmt->fmtid]; h->capgeo.rows = fmt->height; h->capgeo.columns = fmt->width; h->capgeo.frames = 1; h->capgeo.oformat = 0 /* FIXME */; if (fmt->height <= 320) h->capgeo.oformat |= METEOR_GEO_ODD_ONLY; h->fmt = *fmt; return 0; } static void set_capture(struct bsd_handle *h, int state) { if (state) { /* enable */ xioctl(h->fd, METEORSVIDEO, &h->nofb); xioctl(h->fd, METEORSETGEO, &h->capgeo); xioctl(h->fd, METEORSACTPIXFMT, h->capfmt); xioctl(h->fd, BT848SCLIP, &h->noclip); } else { /* disable */ xioctl(h->fd, METEORCAPTUR, &stop); } } static int bsd_startvideo(void *handle, int fps, unsigned int buffers) { struct bsd_handle *h = handle; BUG_ON(h->fd == -1,"device not open"); set_overlay(h,0); h->fps = fps; h->start = ng_get_timestamp(); set_capture(h,1); xioctl(h->fd, METEORSSIGNAL, &signal_on); xioctl(h->fd, METEORCAPTUR, &start); return 0; } static void bsd_stopvideo(void *handle) { struct bsd_handle *h = handle; BUG_ON(h->fd == -1,"device not open"); h->fps = 0; set_capture(h,0); xioctl(h->fd, METEORCAPTUR, &stop); xioctl(h->fd, METEORSSIGNAL, &signal_off); set_overlay(h,h->ov_enabled); } static struct ng_video_buf* bsd_nextframe(void *handle) { struct bsd_handle *h = handle; struct ng_video_buf *buf; int size; sigset_t sa_mask; BUG_ON(h->fd == -1,"device not open"); size = h->fmt.bytesperline * h->fmt.height; buf = ng_malloc_video_buf(NULL,&h->fmt); alarm(1); sigfillset(&sa_mask); sigdelset(&sa_mask,SIGUSR1); sigdelset(&sa_mask,SIGALRM); sigsuspend(&sa_mask); alarm(0); memcpy(buf->data,h->map,size); buf->info.ts = ng_get_timestamp() - h->start; return buf; } static struct ng_video_buf* bsd_getimage(void *handle) { struct bsd_handle *h = handle; struct ng_video_buf *buf; int size; BUG_ON(h->fd == -1,"device not open"); set_overlay(h,0); set_capture(h,1); size = h->fmt.bytesperline * h->fmt.height; buf = ng_malloc_video_buf(NULL,&h->fmt); xioctl(h->fd, METEORCAPTUR, &single); memcpy(buf->data,h->map,size); set_capture(h,0); set_overlay(h,h->ov_enabled); return buf; } /* ---------------------------------------------------------------------- */ static void __init plugin_init(void) { ng_vid_driver_register(NG_PLUGIN_MAGIC,__FILE__,&bsd_driver); } amsn-0.98.9/utils/linux/capture/libng/plugins/drv0-v4l2.c0000644000175000017500000010617411136206316022723 0ustar billiobbilliob/* * interface to the v4l2 driver * * (c) 1998-2002 Gerd Knorr * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_VIDEODEV2_H /* Solaris */ #include #define MAJOR_NUM 188 #else /* Linux */ #include /* XXX glibc */ #include "videodev2.h" #define MAJOR_NUM 81 #endif #include "grab-ng.h" #include "struct-dump.h" #include "struct-v4l2.h" #ifdef HAVE_LIBV4L #include #else #define v4l2_close close #define v4l2_dup dup #define v4l2_ioctl ioctl #define v4l2_read read #define v4l2_mmap mmap #define v4l2_munmap munmap #endif /* ---------------------------------------------------------------------- */ /* open+close */ static void* v4l2_init(char *device); static int v4l2_open_handle(void *handle); static int v4l2_close_handle(void *handle); static int v4l2_fini(void *handle); static struct ng_devinfo* v4l2_probe(int verbose); /* attributes */ static char* v4l2_devname(void *handle); static char* v4l2_busname(void *handle); static int v4l2_flags(void *handle); static struct ng_attribute* v4l2_attrs(void *handle); static int v4l2_read_attr(struct ng_attribute*); static void v4l2_write_attr(struct ng_attribute*, int val); #if 0 /* overlay */ static int v4l2_setupfb(void *handle, struct ng_video_fmt *fmt, void *base); static int v4l2_overlay(void *handle, struct ng_video_fmt *fmt, int x, int y, struct OVERLAY_CLIP *oc, int count, int aspect); #endif /* capture video */ static int v4l2_setformat(void *handle, struct ng_video_fmt *fmt); static int v4l2_startvideo(void *handle, int fps, unsigned int buffers); static void v4l2_stopvideo(void *handle); static struct ng_video_buf* v4l2_nextframe(void *handle); static struct ng_video_buf* v4l2_getimage(void *handle); /* mpeg */ static char *v4l2_setup_mpeg(void *handle, int flags); /* tuner */ static unsigned long v4l2_getfreq(void *handle); static void v4l2_setfreq(void *handle, unsigned long freq); static int v4l2_tuned(void *handle); /* ---------------------------------------------------------------------- */ #define WANTED_BUFFERS 32 #define MAX_INPUT 16 #define MAX_NORM 16 #define MAX_FORMAT 32 #define MAX_CTRL 32 struct v4l2_handle { int fd; char *device; /* device descriptions */ int ninputs,nstds,nfmts; struct v4l2_capability cap; struct v4l2_streamparm streamparm; struct v4l2_input inp[MAX_INPUT]; struct v4l2_standard std[MAX_NORM]; struct v4l2_fmtdesc fmt[MAX_FORMAT]; struct v4l2_queryctrl ctl[MAX_CTRL*2]; int flags; int mpeg; /* attributes */ int nattr; struct ng_attribute *attr; /* capture */ int fps,first; long long start; struct v4l2_format fmt_v4l2; struct ng_video_fmt fmt_me; struct v4l2_requestbuffers reqbufs; struct v4l2_buffer buf_v4l2[WANTED_BUFFERS]; struct ng_video_buf buf_me[WANTED_BUFFERS]; unsigned int queue,waiton; /* overlay */ struct v4l2_framebuffer ov_fb; struct v4l2_format ov_win; struct v4l2_clip ov_clips[256]; #if 0 enum v4l2_field ov_fields; #endif int ov_error; int ov_enabled; int ov_on; }; static void v4l2_probe_mpeg(struct v4l2_handle *h); /* ---------------------------------------------------------------------- */ struct ng_vid_driver v4l2_driver = { .name = "v4l2", .priority = 1, .init = v4l2_init, .open = v4l2_open_handle, .close = v4l2_close_handle, .fini = v4l2_fini, .devname = v4l2_devname, .busname = v4l2_busname, .probe = v4l2_probe, .capabilities = v4l2_flags, .list_attrs = v4l2_attrs, #if 0 .setupfb = v4l2_setupfb, .overlay = v4l2_overlay, #endif .setformat = v4l2_setformat, .startvideo = v4l2_startvideo, .stopvideo = v4l2_stopvideo, .nextframe = v4l2_nextframe, .getimage = v4l2_getimage, .getfreq = v4l2_getfreq, .setfreq = v4l2_setfreq, .is_tuned = v4l2_tuned, .setup_mpeg = v4l2_setup_mpeg, }; static __u32 xawtv_pixelformat[VIDEO_FMT_COUNT] = { [ VIDEO_RGB08 ] = V4L2_PIX_FMT_HI240, [ VIDEO_GRAY ] = V4L2_PIX_FMT_GREY, [ VIDEO_RGB15_LE ] = V4L2_PIX_FMT_RGB555, [ VIDEO_RGB16_LE ] = V4L2_PIX_FMT_RGB565, [ VIDEO_RGB15_BE ] = V4L2_PIX_FMT_RGB555X, [ VIDEO_RGB16_BE ] = V4L2_PIX_FMT_RGB565X, [ VIDEO_BGR24 ] = V4L2_PIX_FMT_BGR24, [ VIDEO_BGR32 ] = V4L2_PIX_FMT_BGR32, [ VIDEO_RGB24 ] = V4L2_PIX_FMT_RGB24, [ VIDEO_YUYV ] = V4L2_PIX_FMT_YUYV, [ VIDEO_UYVY ] = V4L2_PIX_FMT_UYVY, [ VIDEO_YUV422P ] = V4L2_PIX_FMT_YUV422P, [ VIDEO_YUV420P ] = V4L2_PIX_FMT_YUV420, [ VIDEO_JPEG ] = V4L2_PIX_FMT_JPEG, [ VIDEO_MJPEG ] = V4L2_PIX_FMT_MJPEG, // [ VIDEO_MPEG ] = V4L2_PIX_FMT_MPEG, // MPEG is supported in a different way #ifdef V4L2_PIX_FMT_BA81 [ VIDEO_BAYER ] = V4L2_PIX_FMT_BA81, #endif #ifdef V4L2_PIX_FMT_S910 [ VIDEO_S910 ] = V4L2_PIX_FMT_S910, #endif }; static struct STRTAB stereo[] = { { V4L2_TUNER_MODE_MONO, "mono" }, { V4L2_TUNER_MODE_STEREO, "stereo" }, { V4L2_TUNER_MODE_LANG1, "lang1" }, { V4L2_TUNER_MODE_LANG2, "lang2" }, { -1, NULL }, }; /* ---------------------------------------------------------------------- */ /* debug output */ #define PREFIX "ioctl: " static int xioctl(int fd, int cmd, void *arg, int mayfail) { int rc; rc = v4l2_ioctl(fd,cmd,arg); if (0 <= rc && ng_debug < 2) return rc; if (mayfail && errno == mayfail && ng_debug < 2) return rc; print_ioctl(stderr,ioctls_v4l2,PREFIX,cmd,arg); fprintf(stderr,": %s\n",(rc == 0) ? "ok" : strerror(errno)); return rc; } static void print_bufinfo(struct v4l2_buffer *buf) { static char *type[] = { [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap", [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over", [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out", [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap", [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", }; fprintf(stderr,"v4l2: buf %d: %s 0x%x+%d, used %d\n", buf->index, buf->type < sizeof(type)/sizeof(char*) ? type[buf->type] : "unknown", buf->m.offset,buf->length,buf->bytesused); } /* ---------------------------------------------------------------------- */ /* helpers */ static void get_device_capabilities(struct v4l2_handle *h) { int i; for (h->ninputs = 0; h->ninputs < MAX_INPUT; h->ninputs++) { h->inp[h->ninputs].index = h->ninputs; if (-1 == xioctl(h->fd, VIDIOC_ENUMINPUT, &h->inp[h->ninputs], EINVAL)) break; } /* This crashes on Solaris for an unknown reason. */ #ifndef __sun for (h->nstds = 0; h->nstds < MAX_NORM; h->nstds++) { h->std[h->nstds].index = h->nstds; if (-1 == xioctl(h->fd, VIDIOC_ENUMSTD, &h->std[h->nstds], EINVAL)) break; } #endif for (h->nfmts = 0; h->nfmts < MAX_FORMAT; h->nfmts++) { h->fmt[h->nfmts].index = h->nfmts; h->fmt[h->nfmts].type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl(h->fd, VIDIOC_ENUM_FMT, &h->fmt[h->nfmts], EINVAL)) break; } h->streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; v4l2_ioctl(h->fd,VIDIOC_G_PARM,&h->streamparm); /* controls */ for (i = 0; i < MAX_CTRL; i++) { h->ctl[i].id = V4L2_CID_BASE+i; if (-1 == xioctl(h->fd, VIDIOC_QUERYCTRL, &h->ctl[i], EINVAL) || (h->ctl[i].flags & V4L2_CTRL_FLAG_DISABLED)) h->ctl[i].id = -1; } for (i = 0; i < MAX_CTRL; i++) { h->ctl[i+MAX_CTRL].id = V4L2_CID_PRIVATE_BASE+i; if (-1 == xioctl(h->fd, VIDIOC_QUERYCTRL, &h->ctl[i+MAX_CTRL], EINVAL) || (h->ctl[i+MAX_CTRL].flags & V4L2_CTRL_FLAG_DISABLED)) h->ctl[i+MAX_CTRL].id = -1; } } static struct STRTAB * build_norms(struct v4l2_handle *h) { struct STRTAB *norms; int i; norms = malloc(sizeof(struct STRTAB) * (h->nstds+1)); for (i = 0; i < h->nstds; i++) { norms[i].nr = i; norms[i].str = h->std[i].name; } norms[i].nr = -1; norms[i].str = NULL; return norms; } static struct STRTAB * build_inputs(struct v4l2_handle *h) { struct STRTAB *inputs; int i; inputs = malloc(sizeof(struct STRTAB) * (h->ninputs+1)); for (i = 0; i < h->ninputs; i++) { inputs[i].nr = i; inputs[i].str = h->inp[i].name; } inputs[i].nr = -1; inputs[i].str = NULL; return inputs; } /* ---------------------------------------------------------------------- */ static struct V4L2_ATTR { unsigned int id; unsigned int v4l2; } v4l2_attr[] = { { ATTR_ID_VOLUME, V4L2_CID_AUDIO_VOLUME }, { ATTR_ID_MUTE, V4L2_CID_AUDIO_MUTE }, { ATTR_ID_COLOR, V4L2_CID_SATURATION }, { ATTR_ID_BRIGHT, V4L2_CID_BRIGHTNESS }, { ATTR_ID_HUE, V4L2_CID_HUE }, { ATTR_ID_CONTRAST, V4L2_CID_CONTRAST }, }; #define NUM_ATTR (sizeof(v4l2_attr)/sizeof(struct V4L2_ATTR)) static struct STRTAB* v4l2_menu(int fd, const struct v4l2_queryctrl *ctl) { struct STRTAB *menu; struct v4l2_querymenu item; int i; menu = malloc(sizeof(struct STRTAB) * (ctl->maximum-ctl->minimum+2)); for (i = ctl->minimum; i <= ctl->maximum; i++) { item.id = ctl->id; item.index = i; if (-1 == xioctl(fd, VIDIOC_QUERYMENU, &item, 0)) { free(menu); return NULL; } menu[i-ctl->minimum].nr = i; menu[i-ctl->minimum].str = strdup(item.name); } menu[i-ctl->minimum].nr = -1; menu[i-ctl->minimum].str = NULL; return menu; } static void v4l2_add_attr(struct v4l2_handle *h, struct v4l2_queryctrl *ctl, int id, struct STRTAB *choices) { static int private_ids = ATTR_ID_COUNT; unsigned int i; h->attr = realloc(h->attr,(h->nattr+2) * sizeof(struct ng_attribute)); memset(h->attr+h->nattr,0,sizeof(struct ng_attribute)*2); if (ctl) { for (i = 0; i < NUM_ATTR; i++) if (v4l2_attr[i].v4l2 == ctl->id) break; if (i != NUM_ATTR) { h->attr[h->nattr].id = v4l2_attr[i].id; } else { h->attr[h->nattr].id = private_ids++; } h->attr[h->nattr].name = ctl->name; h->attr[h->nattr].priority = 2; h->attr[h->nattr].priv = ctl; h->attr[h->nattr].defval = ctl->default_value; switch (ctl->type) { case V4L2_CTRL_TYPE_INTEGER: h->attr[h->nattr].type = ATTR_TYPE_INTEGER; h->attr[h->nattr].defval = ctl->default_value; h->attr[h->nattr].min = ctl->minimum; h->attr[h->nattr].max = ctl->maximum; break; case V4L2_CTRL_TYPE_BOOLEAN: h->attr[h->nattr].type = ATTR_TYPE_BOOL; break; case V4L2_CTRL_TYPE_MENU: h->attr[h->nattr].type = ATTR_TYPE_CHOICE; h->attr[h->nattr].choices = v4l2_menu(h->fd, ctl); break; default: memset(h->attr+h->nattr,0,sizeof(struct ng_attribute)*2); return; } } else { /* for norms + inputs */ h->attr[h->nattr].id = id; if (-1 == h->attr[h->nattr].id) h->attr[h->nattr].id = private_ids++; h->attr[h->nattr].defval = 0; h->attr[h->nattr].type = ATTR_TYPE_CHOICE; h->attr[h->nattr].choices = choices; } if (h->attr[h->nattr].id < ATTR_ID_COUNT) h->attr[h->nattr].name = ng_attr_to_desc[h->attr[h->nattr].id]; h->attr[h->nattr].read = v4l2_read_attr; h->attr[h->nattr].write = v4l2_write_attr; h->attr[h->nattr].handle = h; h->nattr++; } static int v4l2_read_attr(struct ng_attribute *attr) { struct v4l2_handle *h = attr->handle; const struct v4l2_queryctrl *ctl = attr->priv; struct v4l2_control c; struct v4l2_tuner tuner; v4l2_std_id std; int value = 0; int i; if (NULL != ctl) { c.id = ctl->id; xioctl(h->fd,VIDIOC_G_CTRL,&c,0); value = c.value; } else if (attr->id == ATTR_ID_NORM) { value = -1; xioctl(h->fd,VIDIOC_G_STD,&std,0); for (i = 0; i < h->nstds; i++) if (std & h->std[i].id) value = i; } else if (attr->id == ATTR_ID_INPUT) { xioctl(h->fd,VIDIOC_G_INPUT,&value,0); } else if (attr->id == ATTR_ID_AUDIO_MODE) { memset(&tuner,0,sizeof(tuner)); xioctl(h->fd,VIDIOC_G_TUNER,&tuner,0); value = tuner.audmode; #if 1 if (ng_debug) { fprintf(stderr,"v4l2: tuner cap:%s%s%s\n", (tuner.capability&V4L2_TUNER_CAP_STEREO) ? " STEREO" : "", (tuner.capability&V4L2_TUNER_CAP_LANG1) ? " LANG1" : "", (tuner.capability&V4L2_TUNER_CAP_LANG2) ? " LANG2" : ""); fprintf(stderr,"v4l2: tuner rxs:%s%s%s%s\n", (tuner.rxsubchans&V4L2_TUNER_SUB_MONO) ? " MONO" : "", (tuner.rxsubchans&V4L2_TUNER_SUB_STEREO) ? " STEREO" : "", (tuner.rxsubchans&V4L2_TUNER_SUB_LANG1) ? " LANG1" : "", (tuner.rxsubchans&V4L2_TUNER_SUB_LANG2) ? " LANG2" : ""); fprintf(stderr,"v4l2: tuner cur:%s%s%s%s\n", (tuner.audmode==V4L2_TUNER_MODE_MONO) ? " MONO" : "", (tuner.audmode==V4L2_TUNER_MODE_STEREO) ? " STEREO" : "", (tuner.audmode==V4L2_TUNER_MODE_LANG1) ? " LANG1" : "", (tuner.audmode==V4L2_TUNER_MODE_LANG2) ? " LANG2" : ""); } #endif } return value; } static void v4l2_write_attr(struct ng_attribute *attr, int value) { struct v4l2_handle *h = attr->handle; const struct v4l2_queryctrl *ctl = attr->priv; struct v4l2_control c; struct v4l2_tuner tuner; if (NULL != ctl) { c.id = ctl->id; c.value = value; xioctl(h->fd,VIDIOC_S_CTRL,&c,0); } else if (attr->id == ATTR_ID_NORM) { xioctl(h->fd,VIDIOC_S_STD,&h->std[value].id,0); } else if (attr->id == ATTR_ID_INPUT) { xioctl(h->fd,VIDIOC_S_INPUT,&value,0); } else if (attr->id == ATTR_ID_AUDIO_MODE) { memset(&tuner,0,sizeof(tuner)); xioctl(h->fd,VIDIOC_G_TUNER,&tuner,0); tuner.audmode = value; xioctl(h->fd,VIDIOC_S_TUNER,&tuner,0); } } /* ---------------------------------------------------------------------- */ static int v4l2_open_handle(void *handle) { struct v4l2_handle *h = handle; if (ng_debug) fprintf(stderr, "v4l2: open\n"); BUG_ON(h->fd != -1,"device is open"); h->fd = ng_chardev_open(h->device, O_RDWR, MAJOR_NUM, 1, 1); if (-1 == h->fd) return -1; if (-1 == xioctl(h->fd,VIDIOC_QUERYCAP,&h->cap,EINVAL)) { v4l2_close(h->fd); return -1; } return 0; } static int v4l2_close_handle(void *handle) { struct v4l2_handle *h = handle; if (ng_debug) fprintf(stderr, "v4l2: close\n"); BUG_ON(h->fd == -1,"device not open"); v4l2_close(h->fd); h->fd = -1; return 0; } static void* v4l2_init(char *device) { struct v4l2_handle *h; int i; if (device && 0 != strncmp(device,"/dev/",5)) return NULL; h = malloc(sizeof(*h)); if (NULL == h) return NULL; memset(h,0,sizeof(*h)); h->fd = -1; h->device = strdup(device ? device : ng_dev.video); if (0 != v4l2_open_handle(h)) goto err; if (ng_debug) fprintf(stderr, "v4l2: init\nv4l2: device info:\n" " %s %d.%d.%d / %s @ %s\n", h->cap.driver, (h->cap.version >> 16) & 0xff, (h->cap.version >> 8) & 0xff, h->cap.version & 0xff, h->cap.card,h->cap.bus_info); get_device_capabilities(h); /* attributes */ v4l2_add_attr(h, NULL, ATTR_ID_NORM, build_norms(h)); v4l2_add_attr(h, NULL, ATTR_ID_INPUT, build_inputs(h)); if (h->cap.capabilities & V4L2_CAP_TUNER) v4l2_add_attr(h, NULL, ATTR_ID_AUDIO_MODE, stereo); for (i = 0; i < MAX_CTRL*2; i++) { if (h->ctl[i].id == UNSET) continue; v4l2_add_attr(h, &h->ctl[i], 0, NULL); } /* capture buffers */ for (i = 0; i < WANTED_BUFFERS; i++) { ng_init_video_buf(h->buf_me+i); h->buf_me[i].release = ng_wakeup_video_buf; } /* init flags */ #if 0 if (h->cap.capabilities & V4L2_CAP_VIDEO_OVERLAY && !h->ov_error) h->flags |= CAN_OVERLAY; #endif if (h->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) h->flags |= CAN_CAPTURE; if (h->cap.capabilities & V4L2_CAP_TUNER) h->flags |= CAN_TUNE; /* check for MPEG capabilities */ v4l2_probe_mpeg(h); v4l2_close_handle(h); return h; err: if (h->fd != -1) v4l2_close(h->fd); if (h) free(h); return NULL; } static int v4l2_fini(void *handle) { struct v4l2_handle *h = handle; if (ng_debug) fprintf(stderr, "v4l2: fini\n"); BUG_ON(h->fd != -1,"device is open"); free(h->device); free(h); return 0; } static char* v4l2_devname(void *handle) { struct v4l2_handle *h = handle; return h->cap.card; } static char* v4l2_busname(void *handle) { struct v4l2_handle *h = handle; return h->cap.bus_info; } static struct ng_devinfo* v4l2_probe(int verbose) { struct ng_devinfo *info = NULL; struct v4l2_capability cap; int i,n,fd; n = 0; for (i = 0; NULL != ng_dev.video_scan[i]; i++) { fd = ng_chardev_open(ng_dev.video_scan[i], O_RDONLY | O_NONBLOCK, MAJOR_NUM, verbose, 1); if (-1 == fd) continue; if (-1 == xioctl(fd,VIDIOC_QUERYCAP,&cap,EINVAL)) { if (verbose) perror("ioctl VIDIOC_QUERYCAP"); close(fd); continue; } info = realloc(info,sizeof(*info) * (n+2)); memset(info+n,0,sizeof(*info)*2); strcpy(info[n].device, ng_dev.video_scan[i]); snprintf(info[n].name, sizeof(info[n].name), "%s", cap.card); snprintf(info[n].bus, sizeof(info[n].bus), "%s", cap.bus_info); close(fd); n++; } return info; } static int v4l2_flags(void *handle) { struct v4l2_handle *h = handle; return h->flags; } static struct ng_attribute* v4l2_attrs(void *handle) { struct v4l2_handle *h = handle; return h->attr; } /* ---------------------------------------------------------------------- */ static unsigned long v4l2_getfreq(void *handle) { struct v4l2_handle *h = handle; struct v4l2_frequency f; BUG_ON(h->fd == -1,"device not open"); memset(&f,0,sizeof(f)); xioctl(h->fd, VIDIOC_G_FREQUENCY, &f, 0); return f.frequency; } static void v4l2_setfreq(void *handle, unsigned long freq) { struct v4l2_handle *h = handle; struct v4l2_frequency f; if (ng_debug) fprintf(stderr,"v4l2: freq: %.3f\n",(float)freq/16); BUG_ON(h->fd == -1,"device not open"); memset(&f,0,sizeof(f)); f.type = V4L2_TUNER_ANALOG_TV; f.frequency = freq; xioctl(h->fd, VIDIOC_S_FREQUENCY, &f, 0); } static int v4l2_tuned(void *handle) { struct v4l2_handle *h = handle; struct v4l2_tuner tuner; BUG_ON(h->fd == -1,"device not open"); usleep(10000); memset(&tuner,0,sizeof(tuner)); if (-1 == xioctl(h->fd,VIDIOC_G_TUNER,&tuner,0)) return 0; return tuner.signal ? 1 : 0; } /* ---------------------------------------------------------------------- */ /* overlay */ #if 0 static int v4l2_setupfb(void *handle, struct ng_video_fmt *fmt, void *base) { struct v4l2_handle *h = handle; BUG_ON(h->fd == -1,"device not open"); if (-1 == xioctl(h->fd, VIDIOC_G_FBUF, &h->ov_fb, 0)) return -1; /* double-check settings */ if (NULL != base && h->ov_fb.base != base) { fprintf(stderr,"v4l2: WARNING: framebuffer base address mismatch\n"); fprintf(stderr,"v4l2: me=%p v4l=%p\n",base,h->ov_fb.base); h->ov_error = 1; return -1; } if (h->ov_fb.fmt.width != fmt->width || h->ov_fb.fmt.height != fmt->height) { fprintf(stderr,"v4l2: WARNING: framebuffer size mismatch\n"); fprintf(stderr,"v4l2: me=%dx%d v4l=%dx%d\n", fmt->width,fmt->height,h->ov_fb.fmt.width,h->ov_fb.fmt.height); h->ov_error = 1; return -1; } if (fmt->bytesperline > 0 && fmt->bytesperline != h->ov_fb.fmt.bytesperline) { fprintf(stderr,"v4l2: WARNING: framebuffer bpl mismatch\n"); fprintf(stderr,"v4l2: me=%d v4l=%d\n", fmt->bytesperline,h->ov_fb.fmt.bytesperline); h->ov_error = 1; return -1; } #if 0 if (h->ov_fb.fmt.pixelformat != xawtv_pixelformat[fmt->fmtid]) { fprintf(stderr,"v4l2: WARNING: framebuffer format mismatch\n"); fprintf(stderr,"v4l2: me=%c%c%c%c [%s] v4l=%c%c%c%c\n", xawtv_pixelformat[fmt->fmtid] & 0xff, (xawtv_pixelformat[fmt->fmtid] >> 8) & 0xff, (xawtv_pixelformat[fmt->fmtid] >> 16) & 0xff, (xawtv_pixelformat[fmt->fmtid] >> 24) & 0xff, ng_vfmt_to_desc[fmt->fmtid], h->ov_fb.fmt.pixelformat & 0xff, (h->ov_fb.fmt.pixelformat >> 8) & 0xff, (h->ov_fb.fmt.pixelformat >> 16) & 0xff, (h->ov_fb.fmt.pixelformat >> 24) & 0xff); h->ov_error = 1; return -1; } #endif return 0; } static int v4l2_overlay(void *handle, struct ng_video_fmt *fmt, int x, int y, struct OVERLAY_CLIP *oc, int count, int aspect) { struct v4l2_handle *h = handle; struct v4l2_format win; int rc,i; BUG_ON(h->fd == -1,"device not open"); if (h->ov_error) return -1; if (NULL == fmt) { if (ng_debug) fprintf(stderr,"v4l2: overlay off\n"); if (h->ov_enabled) { h->ov_enabled = 0; h->ov_on = 0; xioctl(h->fd, VIDIOC_OVERLAY, &h->ov_on, 0); } return 0; } if (ng_debug) fprintf(stderr,"v4l2: overlay win=%dx%d+%d+%d, %d clips\n", fmt->width,fmt->height,x,y,count); memset(&win,0,sizeof(win)); win.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; win.fmt.win.w.left = x; win.fmt.win.w.top = y; win.fmt.win.w.width = fmt->width; win.fmt.win.w.height = fmt->height; /* check against max. size */ xioctl(h->fd,VIDIOC_TRY_FMT,&win,0); if (win.fmt.win.w.width != (int)fmt->width) win.fmt.win.w.left = x + (fmt->width - win.fmt.win.w.width)/2; if (win.fmt.win.w.height != (int)fmt->height) win.fmt.win.w.top = y + (fmt->height - win.fmt.win.w.height)/2; if (aspect) ng_ratio_fixup(&win.fmt.win.w.width,&win.fmt.win.w.height, &win.fmt.win.w.left,&win.fmt.win.w.top); /* fixups */ ng_check_clipping(win.fmt.win.w.width, win.fmt.win.w.height, x - win.fmt.win.w.left, y - win.fmt.win.w.top, oc, &count); h->ov_win = win; if (h->ov_fb.capability & V4L2_FBUF_CAP_LIST_CLIPPING) { h->ov_win.fmt.win.clips = h->ov_clips; h->ov_win.fmt.win.clipcount = count; for (i = 0; i < count; i++) { h->ov_clips[i].next = (i+1 == count) ? NULL : &h->ov_clips[i+1]; h->ov_clips[i].c.left = oc[i].x1; h->ov_clips[i].c.top = oc[i].y1; h->ov_clips[i].c.width = oc[i].x2-oc[i].x1; h->ov_clips[i].c.height = oc[i].y2-oc[i].y1; } } #if 0 if (h->ov_fb.flags & V4L2_FBUF_FLAG_CHROMAKEY) { h->ov_win.chromakey = 0; /* FIXME */ } #endif rc = xioctl(h->fd, VIDIOC_S_FMT, &h->ov_win, 0); h->ov_enabled = (0 == rc) ? 1 : 0; h->ov_on = (0 == rc) ? 1 : 0; xioctl(h->fd, VIDIOC_OVERLAY, &h->ov_on, 0); return 0; } #endif /* ---------------------------------------------------------------------- */ /* capture helpers */ static int v4l2_queue_buffer(struct v4l2_handle *h) { struct v4l2_buffer buf; int frame = h->queue % h->reqbufs.count; int rc; if (0 != h->buf_me[frame].refcount) { if (0 != h->queue - h->waiton) return -1; fprintf(stderr,"v4l2: waiting for a free buffer\n"); ng_waiton_video_buf(h->buf_me+frame); } memset(&buf,0,sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = h->buf_v4l2[frame].index; rc = xioctl(h->fd,VIDIOC_QBUF,&buf, 0); if (0 == rc) h->queue++; return rc; } static void v4l2_queue_all(struct v4l2_handle *h) { for (;;) { if (h->queue - h->waiton >= h->reqbufs.count) return; if (0 != v4l2_queue_buffer(h)) return; } } static int v4l2_waiton(struct v4l2_handle *h) { struct v4l2_buffer buf; struct timeval tv; fd_set rdset; /* PWC doesn't respect V4L2 standard and modifies length field we must keep it */ __u32 length; /* * Do not call select() on Solaris. This code can likely be removed for * all systems, as the V4L2 specification states that VIDIOC_DQBUF will block * unless O_NONBLOCK was used in open(). We do not use O_NONBLOCK. */ #ifndef __sun /* wait for the next frame */ again: tv.tv_sec = 5; tv.tv_usec = 0; FD_ZERO(&rdset); FD_SET(h->fd, &rdset); switch (select(h->fd + 1, &rdset, NULL, NULL, &tv)) { case -1: if (EINTR == errno) goto again; perror("v4l2: select"); return -1; case 0: fprintf(stderr,"v4l2: oops: select timeout\n"); return -1; } #endif /* get it */ memset(&buf,0,sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; if (-1 == xioctl(h->fd,VIDIOC_DQBUF,&buf, 0)) return -1; h->waiton++; //Shitty PWC that is confused between size of payload and size of buffer length = h->buf_v4l2[buf.index].length; h->buf_v4l2[buf.index] = buf; h->buf_v4l2[buf.index].length = length; #if 0 if (1) { /* for driver debugging */ static const char *fn[] = { "any", "none", "top", "bottom", "interlaced", "tb", "bt", "alternate", }; static struct timeval last; signed long diff; diff = (buf.timestamp.tv_sec - last.tv_sec) * 1000000; diff += buf.timestamp.tv_usec - last.tv_usec; fprintf(stderr,"\tdiff %6.1f ms buf %d field %d [%s]\n", diff/1000.0, buf.index, buf.field, fn[buf.field%8]); last = buf.timestamp; } #endif return buf.index; } static int v4l2_start_streaming(struct v4l2_handle *h, int buffers) { int disable_overlay = 0; unsigned int i; /* setup buffers */ h->reqbufs.count = buffers; h->reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; h->reqbufs.memory = V4L2_MEMORY_MMAP; if (-1 == xioctl(h->fd, VIDIOC_REQBUFS, &h->reqbufs, 0)) return -1; for (i = 0; i < h->reqbufs.count; i++) { h->buf_v4l2[i].index = i; h->buf_v4l2[i].type = V4L2_BUF_TYPE_VIDEO_CAPTURE; h->buf_v4l2[i].memory = V4L2_MEMORY_MMAP; if (-1 == xioctl(h->fd, VIDIOC_QUERYBUF, &h->buf_v4l2[i], 0)) return -1; h->buf_me[i].fmt = h->fmt_me; h->buf_me[i].size = h->buf_me[i].fmt.bytesperline * h->buf_me[i].fmt.height; h->buf_me[i].data = v4l2_mmap(NULL, h->buf_v4l2[i].length, PROT_READ | PROT_WRITE, MAP_SHARED, h->fd, h->buf_v4l2[i].m.offset); if (MAP_FAILED == h->buf_me[i].data) { perror("mmap"); return -1; } if (ng_debug) print_bufinfo(&h->buf_v4l2[i]); } /* queue up all buffers */ v4l2_queue_all(h); try_again: /* turn off preview (if needed) */ if (disable_overlay) { h->ov_on = 0; xioctl(h->fd, VIDIOC_OVERLAY, &h->ov_on, 0); if (ng_debug) fprintf(stderr,"v4l2: overlay off (start_streaming)\n"); } /* start capture */ if (-1 == xioctl(h->fd,VIDIOC_STREAMON,&h->fmt_v4l2.type, h->ov_on ? EBUSY : 0)) { if (h->ov_on && errno == EBUSY) { disable_overlay = 1; goto try_again; } return -1; } return 0; } static void v4l2_stop_streaming(struct v4l2_handle *h) { unsigned int i; /* stop capture */ if (-1 == v4l2_ioctl(h->fd,VIDIOC_STREAMOFF,&h->fmt_v4l2.type)) perror("ioctl VIDIOC_STREAMOFF"); /* free buffers */ for (i = 0; i < h->reqbufs.count; i++) { if (0 != h->buf_me[i].refcount) ng_waiton_video_buf(&h->buf_me[i]); if (ng_debug) print_bufinfo(&h->buf_v4l2[i]); if (-1 == v4l2_munmap(h->buf_me[i].data,h->buf_v4l2[i].length)) perror("munmap"); } h->queue = 0; h->waiton = 0; /* unrequest buffers (only needed for some drivers) */ h->reqbufs.count = 0; xioctl(h->fd, VIDIOC_REQBUFS, &h->reqbufs, EINVAL); /* turn on preview (if needed) */ if (h->ov_on != h->ov_enabled) { h->ov_on = h->ov_enabled; xioctl(h->fd, VIDIOC_OVERLAY, &h->ov_on, 0); if (ng_debug) fprintf(stderr,"v4l2: overlay on (stop_streaming)\n"); } } /* ---------------------------------------------------------------------- */ /* capture interface */ /* set capture parameters */ static int v4l2_setformat(void *handle, struct ng_video_fmt *fmt) { struct v4l2_handle *h = handle; BUG_ON(h->fd == -1,"device not open"); h->fmt_v4l2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; h->fmt_v4l2.fmt.pix.pixelformat = xawtv_pixelformat[fmt->fmtid]; h->fmt_v4l2.fmt.pix.width = fmt->width; h->fmt_v4l2.fmt.pix.height = fmt->height; h->fmt_v4l2.fmt.pix.field = V4L2_FIELD_ANY; //h->fmt_v4l2.fmt.pix.field = V4L2_FIELD_ALTERNATE; if (fmt->bytesperline != fmt->width * ng_vfmt_to_depth[fmt->fmtid]/8) h->fmt_v4l2.fmt.pix.bytesperline = fmt->bytesperline; else h->fmt_v4l2.fmt.pix.bytesperline = 0; if (-1 == xioctl(h->fd, VIDIOC_S_FMT, &h->fmt_v4l2, EINVAL)) return -1; if (h->fmt_v4l2.fmt.pix.pixelformat != xawtv_pixelformat[fmt->fmtid]) return -1; fmt->width = h->fmt_v4l2.fmt.pix.width; fmt->height = h->fmt_v4l2.fmt.pix.height; fmt->bytesperline = h->fmt_v4l2.fmt.pix.bytesperline; /* struct v4l2_format.fmt.pix.bytesperline is bytesperline for the main plane for planar formats, where as we want it to be the total bytesperline for all planes */ switch (fmt->fmtid) { case VIDEO_YUV422P: fmt->bytesperline *= 2; break; case VIDEO_YUV420P: fmt->bytesperline = fmt->bytesperline * 3 / 2; break; } if (0 == fmt->bytesperline) fmt->bytesperline = fmt->width * ng_vfmt_to_depth[fmt->fmtid] / 8; h->fmt_me = *fmt; if (ng_debug) fprintf(stderr,"v4l2: new capture params (%dx%d, %c%c%c%c, %d byte)\n", fmt->width,fmt->height, h->fmt_v4l2.fmt.pix.pixelformat & 0xff, (h->fmt_v4l2.fmt.pix.pixelformat >> 8) & 0xff, (h->fmt_v4l2.fmt.pix.pixelformat >> 16) & 0xff, (h->fmt_v4l2.fmt.pix.pixelformat >> 24) & 0xff, h->fmt_v4l2.fmt.pix.sizeimage); return 0; } /* start/stop video */ static int v4l2_startvideo(void *handle, int fps, unsigned int buffers) { struct v4l2_handle *h = handle; BUG_ON(h->fd == -1,"device not open"); if (0 != h->fps) fprintf(stderr,"v4l2_startvideo: oops: fps!=0\n"); h->fps = fps; h->first = 1; h->start = 0; if (h->cap.capabilities & V4L2_CAP_STREAMING) return v4l2_start_streaming(h,buffers); return 0; } static void v4l2_stopvideo(void *handle) { struct v4l2_handle *h = handle; BUG_ON(h->fd == -1,"device not open"); if (0 == h->fps) fprintf(stderr,"v4l2_stopvideo: oops: fps==0\n"); h->fps = 0; if (h->cap.capabilities & V4L2_CAP_STREAMING) v4l2_stop_streaming(h); } /* read images */ static struct ng_video_buf* v4l2_nextframe(void *handle) { struct v4l2_handle *h = handle; struct ng_video_buf *buf = NULL; int rc,frame = 0; BUG_ON(h->fd == -1,"device not open"); if (h->cap.capabilities & V4L2_CAP_STREAMING) { v4l2_queue_all(h); frame = v4l2_waiton(h); if (-1 == frame) return NULL; h->buf_me[frame].refcount++; h->buf_me[frame].size = h->buf_v4l2[frame].bytesused; buf = &h->buf_me[frame]; memset(&buf->info,0,sizeof(buf->info)); buf->info.ts = ng_tofday_to_timestamp(&h->buf_v4l2[frame].timestamp); } else { buf = ng_malloc_video_buf(NULL, &h->fmt_me); rc = v4l2_read(h->fd,buf->data,buf->size); if (rc < 0) { perror("v4l2: read"); ng_release_video_buf(buf); return NULL; } memset(&buf->info,0,sizeof(buf->info)); buf->info.ts = ng_get_timestamp(); } if (h->first) { h->first = 0; h->start = buf->info.ts; if (ng_debug) fprintf(stderr,"v4l2: start ts=%lld\n",h->start); } buf->info.ts -= h->start; return buf; } static struct ng_video_buf* v4l2_getimage(void *handle) { struct v4l2_handle *h = handle; struct ng_video_buf *buf; int frame,rc; BUG_ON(h->fd == -1,"device not open"); buf = ng_malloc_video_buf(NULL, &h->fmt_me); if (h->cap.capabilities & V4L2_CAP_READWRITE) { rc = v4l2_read(h->fd,buf->data,buf->size); if (-1 == rc && EBUSY == errno && h->ov_on) { h->ov_on = 0; xioctl(h->fd, VIDIOC_OVERLAY, &h->ov_on, 0); rc = v4l2_read(h->fd,buf->data,buf->size); h->ov_on = 1; xioctl(h->fd, VIDIOC_OVERLAY, &h->ov_on, 0); } if (rc != buf->size) { if (-1 == rc) { perror("v4l2: read"); } else { fprintf(stderr, "v4l2: read: rc=%d/size=%ld\n",rc,buf->size); } ng_release_video_buf(buf); return NULL; } } else { if (-1 == v4l2_start_streaming(h,1)) { v4l2_stop_streaming(h); return NULL; } frame = v4l2_waiton(h); if (-1 == frame) { v4l2_stop_streaming(h); return NULL; } memcpy(buf->data,h->buf_me[0].data,buf->size); v4l2_stop_streaming(h); } return buf; } /* ---------------------------------------------------------------------- */ #define MPEG_TYPE_V4L2 1 #define MPEG_TYPE_IVTV 2 /* from ivtv.h */ #define IVTV_IOC_G_CODEC 0xFFEE7703 #define IVTV_IOC_S_CODEC 0xFFEE7704 #define IVTV_STREAM_PS 0 #define IVTV_STREAM_TS 1 /* more follow .... */ struct ivtv_ioctl_codec { uint32_t aspect; uint32_t audio_bitmap; uint32_t bframes; uint32_t bitrate_mode; uint32_t bitrate; uint32_t bitrate_peak; uint32_t dnr_mode; uint32_t dnr_spatial; uint32_t dnr_temporal; uint32_t dnr_type; uint32_t framerate; uint32_t framespergop; uint32_t gop_closure; uint32_t pulldown; uint32_t stream_type; }; static void v4l2_probe_mpeg(struct v4l2_handle *h) { struct ivtv_ioctl_codec codec; int i; /* check for v4l2 device */ for (i = 0; i < h->nfmts; i++) { if (h->fmt[i].pixelformat == V4L2_PIX_FMT_MPEG) { /* saa7134 sets this and deliveres a transport stream */ /* FIXME: v4l2 API needs some refinements for this... */ h->flags |= CAN_MPEG_TS; h->mpeg = MPEG_TYPE_V4L2; } } if (h->mpeg) goto done; /* check for ivtv driver */ if (0 == ioctl(h->fd, IVTV_IOC_G_CODEC, &codec)) { h->flags |= CAN_MPEG_PS; h->flags |= CAN_MPEG_TS; h->mpeg = MPEG_TYPE_IVTV; } if (h->mpeg) goto done; done: if (!ng_debug) return; switch (h->mpeg) { case MPEG_TYPE_V4L2: fprintf(stderr, "v4l2: detected MPEG-capable v4l2 device.\n"); break; case MPEG_TYPE_IVTV: fprintf(stderr, "v4l2: detected ivtv driver\n"); break; default: return; } if (h->flags & CAN_MPEG_TS) fprintf(stderr, "v4l2: supports mpeg transport streams\n"); if (h->flags & CAN_MPEG_TS) fprintf(stderr, "v4l2: supports mpeg programs streams\n"); } static char *v4l2_setup_mpeg(void *handle, int flags) { struct v4l2_handle *h = handle; switch (h->mpeg) { case MPEG_TYPE_V4L2: return h->device; case MPEG_TYPE_IVTV: { struct ivtv_ioctl_codec codec; if (0 != ioctl(h->fd, IVTV_IOC_G_CODEC, &codec)) return NULL; if (flags & MPEG_FLAGS_PS) codec.stream_type = IVTV_STREAM_PS; if (flags & MPEG_FLAGS_TS) codec.stream_type = IVTV_STREAM_TS; if (0 != ioctl(h->fd, IVTV_IOC_S_CODEC, &codec)) return NULL; return h->device; } default: return NULL; } } /* ---------------------------------------------------------------------- */ static void __init plugin_init(void) { ng_vid_driver_register(NG_PLUGIN_MAGIC,__FILE__,&v4l2_driver); } amsn-0.98.9/utils/linux/capture/libng/plugins/drv1-v4l.c0000644000175000017500000010176411136206316022642 0ustar billiobbilliob/* * interface to the v4l driver * * (c) 1997-2004 Gerd Knorr * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "videodev.h" #include "grab-ng.h" #include "struct-dump.h" #include "struct-v4l.h" #define SYNC_TIMEOUT 5 /* ---------------------------------------------------------------------- */ /* open+close */ static void* v4l_init(char *device); static int v4l_open(void *handle); static int v4l_close(void *handle); static int v4l_fini(void *handle); static char* v4l_devname(void *handle); static struct ng_devinfo* v4l_probe(int verbose); /* attributes */ static int v4l_flags(void *handle); static struct ng_attribute* v4l_attrs(void *handle); static int v4l_read_attr(struct ng_attribute*); static void v4l_write_attr(struct ng_attribute*, int val); #if 0 /* overlay */ static int v4l_setupfb(void *handle, struct ng_video_fmt *fmt, void *base); static int v4l_overlay(void *handle, struct ng_video_fmt *fmt, int x, int y, struct OVERLAY_CLIP *oc, int count, int aspect); #endif /* capture video */ static int v4l_setformat(void *handle, struct ng_video_fmt *fmt); static int v4l_startvideo(void *handle, int fps, unsigned int buffers); static void v4l_stopvideo(void *handle); static struct ng_video_buf* v4l_nextframe(void *handle); static struct ng_video_buf* v4l_getimage(void *handle); /* tuner */ static unsigned long v4l_getfreq(void *handle); static void v4l_setfreq(void *handle, unsigned long freq); static int v4l_tuned(void *handle); /* ---------------------------------------------------------------------- */ static const char *device_cap[] = { "capture", "tuner", "teletext", "overlay", "chromakey", "clipping", "frameram", "scales", "monochrome", NULL }; static const char *device_pal[] = { "-", "grey", "hi240", "rgb16", "rgb24", "rgb32", "rgb15", "yuv422", "yuyv", "uyvy", "yuv420", "yuv411", "raw", "yuv422p", "yuv411p", "yuv420p", "yuv410p" }; #define PALETTE(x) ((x < sizeof(device_pal)/sizeof(char*)) ? device_pal[x] : "UNKNOWN") static struct STRTAB stereo[] = { { 0, "auto" }, { VIDEO_SOUND_MONO, "mono" }, { VIDEO_SOUND_STEREO, "stereo" }, { VIDEO_SOUND_LANG1, "lang1" }, { VIDEO_SOUND_LANG2, "lang2" }, { -1, NULL }, }; static struct STRTAB norms_v4l[] = { { VIDEO_MODE_PAL, "PAL" }, { VIDEO_MODE_NTSC, "NTSC" }, { VIDEO_MODE_SECAM, "SECAM" }, { VIDEO_MODE_AUTO, "AUTO" }, { -1, NULL } }; static struct STRTAB norms_bttv[] = { { VIDEO_MODE_PAL, "PAL" }, { VIDEO_MODE_NTSC, "NTSC" }, { VIDEO_MODE_SECAM, "SECAM" }, { 3, "PAL-NC" }, { 4, "PAL-M" }, { 5, "PAL-N" }, { 6, "NTSC-JP" }, { -1, NULL } }; static unsigned short format2palette[VIDEO_FMT_COUNT] = { [ VIDEO_RGB08 ] = VIDEO_PALETTE_HI240, [ VIDEO_GRAY ] = VIDEO_PALETTE_GREY, [ VIDEO_RGB15_LE ] = VIDEO_PALETTE_RGB555, [ VIDEO_RGB16_LE ] = VIDEO_PALETTE_RGB565, [ VIDEO_BGR24 ] = VIDEO_PALETTE_RGB24, [ VIDEO_BGR32 ] = VIDEO_PALETTE_RGB32, [ VIDEO_YUYV ] = VIDEO_PALETTE_YUV422, [ VIDEO_UYVY ] = VIDEO_PALETTE_UYVY, [ VIDEO_YUV422P ] = VIDEO_PALETTE_YUV422P, [ VIDEO_YUV420P ] = VIDEO_PALETTE_YUV420P, }; #if 0 /* pass 0/1 by reference */ static int one = 1, zero = 0; #endif /* ---------------------------------------------------------------------- */ struct v4l_handle { int fd; char *device; /* general informations */ struct video_capability capability; struct video_channel *channels; struct video_tuner tuner; struct video_audio audio; struct video_picture pict; /* attributes */ int nattr; struct ng_attribute *attr; int input; int audio_mode; /* overlay */ struct video_buffer fbuf; struct video_window win; int ov_error; unsigned int ov_fmtid; int ov_enabled; int ov_on; /* capture */ int use_read; int rw; struct ng_video_fmt fmt; long long start; int fps; /* capture via read() */ struct ng_video_fmt rd_fmt; struct video_window rd_win; unsigned int rd_fmtid; /* capture to mmap()'ed buffers */ struct video_mbuf mbuf; unsigned char *mmap; unsigned int nbuf; unsigned int queue; unsigned int waiton; int probe[VIDEO_FMT_COUNT]; struct video_mmap *buf_v4l; struct ng_video_buf *buf_me; }; struct ng_vid_driver v4l_driver = { .name = "v4l", .priority = 2, .init = v4l_init, .open = v4l_open, .close = v4l_close, .fini = v4l_fini, .devname = v4l_devname, .probe = v4l_probe, .capabilities = v4l_flags, .list_attrs = v4l_attrs, #if 0 .setupfb = v4l_setupfb, .overlay = v4l_overlay, #endif .setformat = v4l_setformat, .startvideo = v4l_startvideo, .stopvideo = v4l_stopvideo, .nextframe = v4l_nextframe, .getimage = v4l_getimage, .getfreq = v4l_getfreq, .setfreq = v4l_setfreq, .is_tuned = v4l_tuned, }; /* ---------------------------------------------------------------------- */ static int alarms; static void sigalarm(int signal) { alarms++; fprintf(stderr,"v4l: timeout (got SIGALRM), hardware/driver problems?\n"); } static void siginit(void) { struct sigaction act,old; memset(&act,0,sizeof(act)); act.sa_handler = sigalarm; sigemptyset(&act.sa_mask); sigaction(SIGALRM,&act,&old); } /* ---------------------------------------------------------------------- */ #define PREFIX "ioctl: " static int xioctl(int fd, int cmd, void *arg) { int rc; rc = ioctl(fd,cmd,arg); if (0 == rc && ng_debug < 2) return 0; print_ioctl(stderr,ioctls_v4l1,PREFIX,cmd,arg); fprintf(stderr,": %s\n",(rc == 0) ? "ok" : strerror(errno)); return rc; } /* ---------------------------------------------------------------------- */ static void v4l_add_attr(struct v4l_handle *h, int id, int type, int defval, struct STRTAB *choices) { h->attr = realloc(h->attr,(h->nattr+2) * sizeof(struct ng_attribute)); memset(h->attr+h->nattr,0,sizeof(struct ng_attribute)*2); h->attr[h->nattr].id = id; h->attr[h->nattr].priority = 2; h->attr[h->nattr].type = type; h->attr[h->nattr].defval = defval; h->attr[h->nattr].choices = choices; if (ATTR_TYPE_INTEGER == type) { h->attr[h->nattr].min = 0; h->attr[h->nattr].max = 65535; } if (id < ATTR_ID_COUNT) h->attr[h->nattr].name = ng_attr_to_desc[id]; h->attr[h->nattr].read = v4l_read_attr; h->attr[h->nattr].write = v4l_write_attr; h->attr[h->nattr].handle = h; h->nattr++; } static void v4l_buffer_map(struct v4l_handle *h) { int i, flags; if (0 == xioctl(h->fd,VIDIOCGMBUF,&h->mbuf)) { if (ng_debug) fprintf(stderr," mbuf: size=%d frames=%d\n", h->mbuf.size,h->mbuf.frames); flags = PROT_READ; if (h->rw) flags |= PROT_WRITE; h->mmap = mmap(0,h->mbuf.size, flags, MAP_SHARED,h->fd,0); if (MAP_FAILED == h->mmap) perror("mmap"); } else { h->mmap = MAP_FAILED; } if (MAP_FAILED != h->mmap) { if (ng_debug) fprintf(stderr," v4l: using mapped buffers for capture\n"); h->use_read = 0; h->nbuf = h->mbuf.frames; h->buf_v4l = malloc(h->nbuf * sizeof(struct video_mmap)); memset(h->buf_v4l,0,h->nbuf * sizeof(struct video_mmap)); h->buf_me = malloc(h->nbuf * sizeof(struct ng_video_buf)); for (i = 0; i < h->nbuf; i++) { ng_init_video_buf(h->buf_me+i); h->buf_me[i].release = ng_wakeup_video_buf; } } else { if (ng_debug) fprintf(stderr," v4l: using read() for capture\n"); h->use_read = 1; } } static void v4l_buffer_unmap(struct v4l_handle *h) { if (MAP_FAILED != h->mmap) { munmap(h->mmap,h->mbuf.size); free(h->buf_v4l); free(h->buf_me); h->buf_v4l = NULL; h->buf_me = NULL; h->nbuf = 0; h->mmap = MAP_FAILED; } else { h->use_read = 0; } } /* ---------------------------------------------------------------------- */ static int v4l_open(void *handle) { struct v4l_handle *h = handle; if (ng_debug) fprintf(stderr, "v4l: open\n"); BUG_ON(h->fd != -1,"device is open"); h->rw = 1; h->fd = ng_chardev_open(h->device, O_RDWR, 81, 1, 0); if (-1 == h->fd) { h->rw = 0; h->fd = ng_chardev_open(h->device, O_RDONLY, 81, 1, 0); if (-1 == h->fd) return -1; } if (-1 == ioctl(h->fd,VIDIOCGCAP,&h->capability)) { close(h->fd); return -1; } v4l_buffer_map(h); return 0; } static int v4l_close(void *handle) { struct v4l_handle *h = handle; if (ng_debug) fprintf(stderr, "v4l: close\n"); BUG_ON(h->fd == -1,"device not open"); v4l_buffer_unmap(h); close(h->fd); h->fd = -1; return 0; } static void* v4l_init(char *device) { struct v4l_handle *h; struct STRTAB *inputs; struct STRTAB *norms; unsigned int i; int rc; if (device && 0 != strncmp(device,"/dev/",5)) return NULL; h = malloc(sizeof(*h)); if (NULL == h) return NULL; memset(h,0,sizeof(*h)); h->device = strdup(device ? device : ng_dev.video); h->fd = -1; h->mmap = MAP_FAILED; /* open device */ if (0 != v4l_open(h)) goto err; if (ng_debug) fprintf(stderr, "v4l: init: %s (%s)\n",device,h->capability.name); siginit(); if (ng_debug) { fprintf(stderr," capabilities: "); for (i = 0; device_cap[i] != NULL; i++) if (h->capability.type & (1 << i)) fprintf(stderr," %s",device_cap[i]); fprintf(stderr,"\n"); fprintf(stderr," size : %dx%d => %dx%d\n", h->capability.minwidth,h->capability.minheight, h->capability.maxwidth,h->capability.maxheight); } /* input sources */ if (ng_debug) fprintf(stderr," channels: %d\n",h->capability.channels); h->channels = malloc(sizeof(struct video_channel)*h->capability.channels); memset(h->channels,0,sizeof(struct video_channel)*h->capability.channels); inputs = malloc(sizeof(struct STRTAB)*(h->capability.channels+1)); memset(inputs,0,sizeof(struct STRTAB)*(h->capability.channels+1)); for (i = 0; i < h->capability.channels; i++) { h->channels[i].channel = i; xioctl(h->fd,VIDIOCGCHAN,&(h->channels[i])); inputs[i].nr = i; inputs[i].str = h->channels[i].name; if (ng_debug) fprintf(stderr," %s: %d %s%s %s%s\n", h->channels[i].name, h->channels[i].tuners, (h->channels[i].flags & VIDEO_VC_TUNER) ? "tuner " : "", (h->channels[i].flags & VIDEO_VC_AUDIO) ? "audio " : "", (h->channels[i].type & VIDEO_TYPE_TV) ? "tv " : "", (h->channels[i].type & VIDEO_TYPE_CAMERA) ? "camera " : ""); } inputs[i].nr = -1; inputs[i].str = NULL; v4l_add_attr(h,ATTR_ID_INPUT,ATTR_TYPE_CHOICE,0,inputs); /* audios */ if (ng_debug) fprintf(stderr," audios : %d\n",h->capability.audios); if (h->capability.audios) { h->audio.audio = 0; xioctl(h->fd,VIDIOCGAUDIO,&h->audio); if (ng_debug) { fprintf(stderr," %d (%s): ",i,h->audio.name); if (h->audio.flags & VIDEO_AUDIO_MUTABLE) fprintf(stderr,"muted=%s ", (h->audio.flags&VIDEO_AUDIO_MUTE) ? "yes":"no"); if (h->audio.flags & VIDEO_AUDIO_VOLUME) fprintf(stderr,"volume=%d ",h->audio.volume); if (h->audio.flags & VIDEO_AUDIO_BASS) fprintf(stderr,"bass=%d ",h->audio.bass); if (h->audio.flags & VIDEO_AUDIO_TREBLE) fprintf(stderr,"treble=%d ",h->audio.treble); fprintf(stderr,"\n"); } v4l_add_attr(h,ATTR_ID_MUTE,ATTR_TYPE_BOOL,0,NULL); v4l_add_attr(h,ATTR_ID_AUDIO_MODE,ATTR_TYPE_CHOICE,0,stereo); if (h->audio.flags & VIDEO_AUDIO_VOLUME) v4l_add_attr(h,ATTR_ID_VOLUME,ATTR_TYPE_INTEGER,0,NULL); } /* tv norms / tuner */ norms = malloc(sizeof(norms_v4l)); memcpy(norms,norms_v4l,sizeof(norms_v4l)); if (h->capability.type & VID_TYPE_TUNER) { /* have tuner */ xioctl(h->fd,VIDIOCGTUNER,&h->tuner); if (ng_debug) fprintf(stderr," tuner : %s %lu-%lu", h->tuner.name,h->tuner.rangelow,h->tuner.rangehigh); for (i = 0; norms[i].str != NULL; i++) { if (h->tuner.flags & (1<channels[0], sizeof(struct video_channel)); for (i = 0; norms[i].str != NULL; i++) { vchan.norm = i; if (-1 == xioctl(h->fd,VIDIOCSCHAN,&vchan)) norms[i].nr = -1; else if (ng_debug) fprintf(stderr," %s",norms[i].str); } /* restore settings after probe */ memcpy(&vchan, &h->channels[0], sizeof(struct video_channel)); xioctl(h->fd,VIDIOCSCHAN,&vchan); if (ng_debug) fprintf(stderr,"\n"); } #if 1 #define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int) /* dirty hack time / v4l design flaw -- works with bttv only * this adds support for a few less common PAL versions */ if (-1 != (rc = ioctl(h->fd,BTTV_VERSION,&i))) { norms = norms_bttv; if (ng_debug || rc < 0x000700) fprintf(stderr,"v4l: bttv version %d.%d.%d\n", (rc >> 16) & 0xff, (rc >> 8) & 0xff, rc & 0xff); if (rc < 0x000700) fprintf(stderr, "v4l: prehistoric bttv version found, please try to\n" " upgrade the driver before mailing bug reports\n"); } #endif v4l_add_attr(h,ATTR_ID_NORM,ATTR_TYPE_CHOICE,0,norms); /* frame buffer */ xioctl(h->fd,VIDIOCGFBUF,&h->fbuf); if (ng_debug) fprintf(stderr," fbuffer : base=0x%p size=%dx%d depth=%d bpl=%d\n", h->fbuf.base, h->fbuf.width, h->fbuf.height, h->fbuf.depth, h->fbuf.bytesperline); /* picture parameters */ xioctl(h->fd,VIDIOCGPICT,&h->pict); v4l_add_attr(h,ATTR_ID_BRIGHT, ATTR_TYPE_INTEGER,0,NULL); v4l_add_attr(h,ATTR_ID_HUE, ATTR_TYPE_INTEGER,0,NULL); v4l_add_attr(h,ATTR_ID_COLOR, ATTR_TYPE_INTEGER,0,NULL); v4l_add_attr(h,ATTR_ID_CONTRAST,ATTR_TYPE_INTEGER,0,NULL); if (ng_debug) { fprintf(stderr, " picture : brightness=%d hue=%d colour=%d contrast=%d\n", h->pict.brightness, h->pict.hue, h->pict.colour, h->pict.contrast); fprintf(stderr, " picture : whiteness=%d depth=%d palette=%s\n", h->pict.whiteness, h->pict.depth, PALETTE(h->pict.palette)); } v4l_close(h); return h; err: if (h->fd != -1) close(h->fd); free(h); return NULL; } static int v4l_fini(void *handle) { struct v4l_handle *h = handle; BUG_ON(h->fd != -1,"device still open"); if (ng_debug) fprintf(stderr, "v4l: close\n"); free(h->device); free(h); return 0; } /* ---------------------------------------------------------------------- */ static char* v4l_devname(void *handle) { struct v4l_handle *h = handle; return h->capability.name; } static struct ng_devinfo* v4l_probe(int verbose) { struct ng_devinfo *info = NULL; struct video_capability cap; int i,n,fd; n = 0; for (i = 0; NULL != ng_dev.video_scan[i]; i++) { fd = ng_chardev_open(ng_dev.video_scan[i], O_RDONLY | O_NONBLOCK, 81, verbose, 0); if (-1 == fd) continue; if (-1 == xioctl(fd,VIDIOCGCAP,&cap)) { if (verbose) perror("ioctl VIDIOCGCAP"); close(fd); continue; } info = realloc(info,sizeof(*info) * (n+2)); memset(info+n,0,sizeof(*info)*2); strcpy(info[n].device, ng_dev.video_scan[i]); sprintf(info[n].name, "%.32s", cap.name); close(fd); n++; } return info; } static int v4l_flags(void *handle) { struct v4l_handle *h = handle; int ret = 0; #if 0 if (h->capability.type & VID_TYPE_OVERLAY) ret |= CAN_OVERLAY; #endif if (h->capability.type & VID_TYPE_CAPTURE && !h->ov_error) ret |= CAN_CAPTURE; if (h->capability.type & VID_TYPE_TUNER) ret |= CAN_TUNE; if (h->capability.type & VID_TYPE_CHROMAKEY) ret |= NEEDS_CHROMAKEY; return ret; } static struct ng_attribute* v4l_attrs(void *handle) { struct v4l_handle *h = handle; return h->attr; } static int audio_mode_mask2bit(int mode) { if (mode & VIDEO_SOUND_STEREO) return VIDEO_SOUND_STEREO; if (mode & VIDEO_SOUND_LANG1) return VIDEO_SOUND_LANG1; if (mode & VIDEO_SOUND_LANG2) return VIDEO_SOUND_LANG2; if (mode & VIDEO_SOUND_MONO) return VIDEO_SOUND_MONO; return 0; } static int v4l_read_attr(struct ng_attribute *attr) { struct v4l_handle *h = attr->handle; BUG_ON(h->fd == -1,"device not open"); switch (attr->id) { case ATTR_ID_INPUT: return -1; case ATTR_ID_NORM: xioctl(h->fd, VIDIOCGCHAN, &h->channels[h->input]); return h->channels[h->input].norm; case ATTR_ID_MUTE: xioctl(h->fd, VIDIOCGAUDIO, &h->audio); return h->audio.flags & VIDEO_AUDIO_MUTE; case ATTR_ID_VOLUME: xioctl(h->fd, VIDIOCGAUDIO, &h->audio); return h->audio.volume; case ATTR_ID_AUDIO_MODE: xioctl(h->fd, VIDIOCGAUDIO, &h->audio); return audio_mode_mask2bit(h->audio.mode); case ATTR_ID_COLOR: xioctl(h->fd, VIDIOCGPICT, &h->pict); return h->pict.colour; case ATTR_ID_BRIGHT: xioctl(h->fd, VIDIOCGPICT, &h->pict); return h->pict.brightness; case ATTR_ID_HUE: xioctl(h->fd, VIDIOCGPICT, &h->pict); return h->pict.hue; case ATTR_ID_CONTRAST: xioctl(h->fd, VIDIOCGPICT, &h->pict); return h->pict.contrast; } return -1; } static void v4l_write_attr(struct ng_attribute *attr, int val) { struct v4l_handle *h = attr->handle; BUG_ON(h->fd == -1,"device not open"); /* read ... */ switch (attr->id) { case ATTR_ID_INPUT: /* nothing */ break; case ATTR_ID_NORM: xioctl(h->fd, VIDIOCGCHAN, &h->channels[h->input]); break; case ATTR_ID_MUTE: case ATTR_ID_VOLUME: case ATTR_ID_AUDIO_MODE: xioctl(h->fd, VIDIOCGAUDIO, &h->audio); break; case ATTR_ID_COLOR: case ATTR_ID_BRIGHT: case ATTR_ID_HUE: case ATTR_ID_CONTRAST: xioctl(h->fd, VIDIOCGPICT, &h->pict); break; } /* ... modify ... */ switch (attr->id) { case ATTR_ID_INPUT: h->input = val; h->audio_mode = 0; break; case ATTR_ID_NORM: h->channels[h->input].norm = val; h->audio_mode = 0; break; case ATTR_ID_MUTE: if (val) h->audio.flags |= VIDEO_AUDIO_MUTE; else h->audio.flags &= ~VIDEO_AUDIO_MUTE; break; case ATTR_ID_VOLUME: h->audio.volume = val; break; case ATTR_ID_AUDIO_MODE: h->audio_mode = val; break; case ATTR_ID_COLOR: h->pict.colour = val; break; case ATTR_ID_BRIGHT: h->pict.brightness = val; break; case ATTR_ID_HUE: h->pict.hue = val; break; case ATTR_ID_CONTRAST: h->pict.contrast = val; break; } /* have to set that all the time as read and write have slightly different semantics: read == bitmask with all available modes flagged write == one bit set (for the selected mode, zero is autodetect) */ h->audio.mode = h->audio_mode; /* ... write */ switch (attr->id) { case ATTR_ID_INPUT: case ATTR_ID_NORM: xioctl(h->fd, VIDIOCSCHAN, &h->channels[h->input]); break; case ATTR_ID_MUTE: case ATTR_ID_VOLUME: case ATTR_ID_AUDIO_MODE: xioctl(h->fd, VIDIOCSAUDIO, &h->audio); break; case ATTR_ID_COLOR: case ATTR_ID_BRIGHT: case ATTR_ID_HUE: case ATTR_ID_CONTRAST: xioctl(h->fd, VIDIOCSPICT, &h->pict); break; } } static unsigned long v4l_getfreq(void *handle) { struct v4l_handle *h = handle; unsigned long freq; BUG_ON(h->fd == -1,"device not open"); xioctl(h->fd, VIDIOCGFREQ, &freq); return freq; } static void v4l_setfreq(void *handle, unsigned long freq) { struct v4l_handle *h = handle; if (ng_debug) fprintf(stderr,"v4l: freq: %.3f\n",(float)freq/16); BUG_ON(h->fd == -1,"device not open"); xioctl(h->fd, VIDIOCSFREQ, &freq); h->audio_mode = 0; } static int v4l_tuned(void *handle) { struct v4l_handle *h = handle; BUG_ON(h->fd == -1,"device not open"); /* usleep(10000); */ if (-1 == xioctl(h->fd,VIDIOCGTUNER,&h->tuner)) return 0; return h->tuner.signal ? 1 : 0; } /* ---------------------------------------------------------------------- */ /* do overlay */ #if 0 int v4l_setupfb(void *handle, struct ng_video_fmt *fmt, void *base) { struct v4l_handle *h = handle; BUG_ON(h->fd == -1,"device not open"); /* overlay supported ?? */ if (!(h->capability.type & VID_TYPE_OVERLAY)) { if (ng_debug) fprintf(stderr,"v4l: device has no overlay support\n"); return -1; } /* double-check settings */ if (ng_debug) fprintf(stderr,"v4l: %dx%d, %d bit/pixel, %d byte/scanline\n", h->fbuf.width,h->fbuf.height, h->fbuf.depth,h->fbuf.bytesperline); if ((fmt->bytesperline > 0 && h->fbuf.bytesperline != fmt->bytesperline) || (h->fbuf.width != fmt->width) || (h->fbuf.height != fmt->height)) { fprintf(stderr, "WARNING: v4l and x11 disagree about the screen size\n" "WARNING: Is v4l-conf installed correctly?\n"); h->ov_error = 1; } if (ng_vfmt_to_depth[fmt->fmtid] != ((h->fbuf.depth+7)&0xf8)) { fprintf(stderr, "WARNING: v4l and x11 disagree about the color depth\n" "WARNING: fbuf.depth=%d, x11 depth=%d\n" "WARNING: Is v4l-conf installed correctly?\n", h->fbuf.depth,ng_vfmt_to_depth[fmt->fmtid]); h->ov_error = 1; } if (NULL != base) { /* XXX: minor differences are legal... (matrox problems) */ if ((void*)((unsigned long)h->fbuf.base & 0xfffff000) != (void*)((unsigned long)base & 0xfffff000)) { fprintf(stderr, "WARNING: v4l and dga disagree about the framebuffer base\n" "WARNING: fbuf.base=%p, dga=%p\n" "WARNING: Is v4l-conf installed correctly?\n", h->fbuf.base,base); h->ov_error = 1; } } if (h->ov_error) { fprintf(stderr,"WARNING: overlay mode disabled\n"); return -1; } return 0; } static void v4l_overlay_set(struct v4l_handle *h, int state) { int rc; if (0 == state) { /* off */ if (0 == h->ov_on) return; xioctl(h->fd, VIDIOCCAPTURE, &zero); h->ov_on = 0; } else { /* on */ h->pict.depth = ng_vfmt_to_depth[h->ov_fmtid]; h->pict.palette = GETELEM(format2palette,h->ov_fmtid,0); xioctl(h->fd, VIDIOCSPICT, &h->pict); rc = xioctl(h->fd, VIDIOCSWIN, &h->win); if (0 == rc) { if (0 != h->ov_on) return; xioctl(h->fd, VIDIOCCAPTURE, &one); h->ov_on = 1; } else { /* disable overlay on SWIN failure */ xioctl(h->fd, VIDIOCCAPTURE, &zero); h->ov_on = 0; } } } int v4l_overlay(void *handle, struct ng_video_fmt *fmt, int x, int y, struct OVERLAY_CLIP *oc, int count, int aspect) { struct v4l_handle *h = handle; int i; BUG_ON(h->fd == -1,"device not open"); if (h->ov_error) return -1; if (NULL == fmt) { if (ng_debug) fprintf(stderr,"v4l: overlay off\n"); h->ov_enabled = 0; v4l_overlay_set(h,h->ov_enabled); return 0; } h->win.x = x; h->win.y = y; h->win.width = fmt->width; h->win.height = fmt->height; h->win.flags = 0; h->win.chromakey = 0; /* check against max. size */ xioctl(h->fd,VIDIOCGCAP,&h->capability); if (h->win.width > h->capability.maxwidth) { h->win.width = h->capability.maxwidth; h->win.x += (fmt->width - h->win.width)/2; } if (h->win.height > h->capability.maxheight) { h->win.height = h->capability.maxheight; h->win.y += (fmt->height - h->win.height)/2; } if (aspect) ng_ratio_fixup(&h->win.width,&h->win.height,&h->win.x,&h->win.y); #if 0 /* pass aligned values -- the driver does'nt get it right yet */ h->win.width &= ~3; h->win.height &= ~3; h->win.x &= ~3; if (h->win.x < x) h->win.x += 4; if (h->win.x+h->win.width > x+fmt->width) h->win.width -= 4; #endif /* fixups */ ng_check_clipping(h->win.width, h->win.height, x - h->win.x, y - h->win.y, oc, &count); /* handle clipping */ if (h->win.clips) { free(h->win.clips); h->win.clips = NULL; } h->win.clipcount = 0; if (h->capability.type & VID_TYPE_CLIPPING && count > 0) { h->win.clipcount = count; h->win.clips = malloc(count * sizeof(struct video_clip)); for (i = 0; i < count; i++) { h->win.clips[i].x = oc[i].x1; h->win.clips[i].y = oc[i].y1; h->win.clips[i].width = oc[i].x2-oc[i].x1; h->win.clips[i].height = oc[i].y2-oc[i].y1; } } if (h->capability.type & VID_TYPE_CHROMAKEY) h->win.chromakey = ng_chromakey; h->ov_enabled = 1; h->ov_fmtid = fmt->fmtid; v4l_overlay_set(h,h->ov_enabled); if (ng_debug) fprintf(stderr,"v4l: overlay win=%dx%d+%d+%d, %d clips\n", fmt->width,fmt->height,x,y,count); return 0; } #else static void v4l_overlay_set(struct v4l_handle *h, int state) { /* dummy */ } #endif /* ---------------------------------------------------------------------- */ static int mm_queue(struct v4l_handle *h) { int frame = h->queue % h->nbuf; int rc; if (0 != h->buf_me[frame].refcount) { if (0 != h->queue - h->waiton) return -1; fprintf(stderr,"v4l: waiting for a free buffer\n"); ng_waiton_video_buf(h->buf_me+frame); } rc = xioctl(h->fd,VIDIOCMCAPTURE,h->buf_v4l+frame); if (0 == rc) h->queue++; return rc; } static void mm_queue_all(struct v4l_handle *h) { for (;;) { if (h->queue - h->waiton >= h->nbuf) return; if (0 != mm_queue(h)) return; } } static int mm_waiton(struct v4l_handle *h) { int frame = h->waiton % h->nbuf; int rc; if (0 == h->queue - h->waiton) return -1; h->waiton++; alarms=0; alarm(SYNC_TIMEOUT); retry: if (-1 == (rc = xioctl(h->fd,VIDIOCSYNC,h->buf_v4l+frame))) { if (errno == EINTR && !alarms) goto retry; } alarm(0); if (-1 == rc) return -1; return frame; } static void mm_clear(struct v4l_handle *h) { while (h->queue > h->waiton) mm_waiton(h); h->queue = 0; h->waiton = 0; } static int mm_probe(struct v4l_handle *h, unsigned int fmtid) { if (0 != h->probe[fmtid]) goto done; if (ng_debug) fprintf(stderr, "v4l: capture probe %s...\t", ng_vfmt_to_desc[fmtid]); h->buf_v4l[0].frame = 0; h->buf_v4l[0].width = h->capability.minwidth; h->buf_v4l[0].height = h->capability.minheight; h->buf_v4l[0].format = GETELEM(format2palette,fmtid,0); #if 1 /* bug compatibility: bttv up to 0.7.67 reports wrong minwidth */ if (h->buf_v4l[0].width == 32) h->buf_v4l[0].width = 48; #endif if (0 == h->buf_v4l[0].format) goto fail; if (-1 == mm_queue(h)) goto fail; if (-1 == mm_waiton(h)) goto fail; if (ng_debug) fprintf(stderr, "ok\n"); h->probe[fmtid] = 1; goto done; fail: if (ng_debug) fprintf(stderr, "failed\n"); h->probe[fmtid] = 2; done: mm_clear(h); return h->probe[fmtid] == 1; } static int mm_setparams(struct v4l_handle *h, struct ng_video_fmt *fmt) { unsigned int i; /* buffers available ? */ if (h->mbuf.frames < 1) return -1; /* verify parameters */ xioctl(h->fd,VIDIOCGCAP,&h->capability); if (fmt->width > h->capability.maxwidth) fmt->width = h->capability.maxwidth; if (fmt->height > h->capability.maxheight) fmt->height = h->capability.maxheight; if (fmt->width < h->capability.minwidth) fmt->width = h->capability.minwidth; if (fmt->height < h->capability.minheight) fmt->height = h->capability.minheight; fmt->bytesperline = fmt->width * ng_vfmt_to_depth[fmt->fmtid] / 8; /* check if we can handle the format */ if (!mm_probe(h,fmt->fmtid)) return -1; /* initialize everything */ h->nbuf = h->mbuf.frames; for (i = 0; i < h->nbuf; i++) { h->buf_v4l[i].format = GETELEM(format2palette,fmt->fmtid,0); h->buf_v4l[i].frame = i; h->buf_v4l[i].width = fmt->width; h->buf_v4l[i].height = fmt->height; h->buf_me[i].fmt = *fmt; h->buf_me[i].data = h->mmap + h->mbuf.offsets[i]; h->buf_me[i].size = fmt->height * fmt->bytesperline; } return 0; } /* ---------------------------------------------------------------------- */ static int read_setformat(struct v4l_handle *h, struct ng_video_fmt *fmt) { xioctl(h->fd,VIDIOCGCAP,&h->capability); if (fmt->width > h->capability.maxwidth) fmt->width = h->capability.maxwidth; if (fmt->height > h->capability.maxheight) fmt->height = h->capability.maxheight; fmt->bytesperline = fmt->width * ng_vfmt_to_depth[fmt->fmtid] / 8; h->rd_win.width = fmt->width; h->rd_win.height = fmt->height; h->rd_fmtid = fmt->fmtid; h->pict.depth = ng_vfmt_to_depth[h->rd_fmtid]; h->pict.palette = GETELEM(format2palette,h->rd_fmtid,0); if (-1 == xioctl(h->fd, VIDIOCSPICT, &h->pict)) return -1; if (-1 == xioctl(h->fd, VIDIOCSWIN, &h->rd_win)) return -1; fmt->width = h->rd_win.width; fmt->height = h->rd_win.height; fmt->bytesperline = fmt->width * ng_vfmt_to_depth[fmt->fmtid] / 8; h->rd_fmt = *fmt; return 0; } static struct ng_video_buf* read_getframe(struct v4l_handle *h) { struct ng_video_buf* buf; h->pict.depth = ng_vfmt_to_depth[h->rd_fmtid]; h->pict.palette = GETELEM(format2palette,h->rd_fmtid,0); xioctl(h->fd, VIDIOCSPICT, &h->pict); xioctl(h->fd, VIDIOCSWIN, &h->rd_win); buf = ng_malloc_video_buf(NULL, &h->rd_fmt); if (NULL == buf) return NULL; if (buf->size != read(h->fd,buf->data,buf->size)) { ng_release_video_buf(buf); return NULL; } return buf; } /* ---------------------------------------------------------------------- */ int v4l_setformat(void *handle, struct ng_video_fmt *fmt) { struct v4l_handle *h = handle; int rc; BUG_ON(h->fd == -1,"device not open"); #if 0 /* for debugging color space conversion functions: force xawtv to capture some specific format */ if (fmt->fmtid != VIDEO_YUV420P) return -1; #endif if (ng_debug) fprintf(stderr,"v4l: setformat\n"); if (h->use_read) { v4l_overlay_set(h,0); rc = read_setformat(h,fmt); v4l_overlay_set(h,h->ov_enabled); } else { if (h->queue != h->waiton) fprintf(stderr,"v4l: Huh? setformat: found queued buffers (%d %d)\n", h->queue, h->waiton); mm_clear(h); rc = mm_setparams(h,fmt); } return rc; } int v4l_startvideo(void *handle, int fps, unsigned int buffers) { struct v4l_handle *h = handle; BUG_ON(h->fd == -1,"device not open"); if (ng_debug) fprintf(stderr,"v4l: startvideo\n"); if (0 != h->fps) fprintf(stderr,"v4l: Huh? start: fps != 0\n"); if (!h->use_read) { if (h->nbuf > buffers) h->nbuf = buffers; mm_queue_all(h); } h->start = ng_get_timestamp(); h->fps = fps; return 0; } void v4l_stopvideo(void *handle) { struct v4l_handle *h = handle; BUG_ON(h->fd == -1,"device not open"); if (ng_debug) fprintf(stderr,"v4l: stopvideo\n"); if (0 == h->fps) fprintf(stderr,"v4l: Huh? stop: fps == 0\n"); if (!h->use_read) mm_clear(h); h->fps = 0; } struct ng_video_buf* v4l_nextframe(void *handle) { struct v4l_handle *h = handle; struct ng_video_buf* buf = NULL; int frame = 0; if (ng_debug > 1) fprintf(stderr,"v4l: getimage\n"); BUG_ON(h->fd == -1,"device not open"); if (0 == h->fps) { fprintf(stderr,"v4l: nextframe: fps == 0\n"); return NULL; } if (h->use_read) { if (buf) ng_release_video_buf(buf); v4l_overlay_set(h,0); buf = read_getframe(h); v4l_overlay_set(h,h->ov_enabled); if (NULL == buf) return NULL; memset(&buf->info,0,sizeof(buf->info)); buf->info.ts = ng_get_timestamp() - h->start; return buf; } else { mm_queue_all(h); frame = mm_waiton(h); if (-1 == frame) return NULL; memset(&h->buf_me[frame].info,0,sizeof(h->buf_me[frame].info)); h->buf_me[frame].refcount++; h->buf_me[frame].info.ts = ng_get_timestamp() - h->start; return h->buf_me+frame; } } /* ---------------------------------------------------------------------- */ struct ng_video_buf* v4l_getimage(void *handle) { struct v4l_handle *h = handle; struct ng_video_buf* buf = NULL; int frame; if (ng_debug) fprintf(stderr,"v4l: getimage\n"); BUG_ON(h->fd == -1,"device not open"); if (0 != h->fps) { fprintf(stderr,"v4l: getimage: fps != 0\n"); return NULL; } if (h->use_read) { v4l_overlay_set(h,0); buf = read_getframe(h); v4l_overlay_set(h,h->ov_enabled); return buf; } else { mm_queue(h); frame = mm_waiton(h); if (-1 == frame) return NULL; h->buf_me[frame].refcount++; return h->buf_me+frame; } } /* ---------------------------------------------------------------------- */ static void __init plugin_init(void) { ng_vid_driver_register(NG_PLUGIN_MAGIC,__FILE__,&v4l_driver); } amsn-0.98.9/utils/linux/capture/libng/plugins/Rules.mk0000644000175000017500000000255111755465524022553 0ustar billiobbilliob# targets to build TARGETS-plugins := $(capture_dir)/libng/plugins/conv-mjpeg.so TARGETS-plugins += $(patsubst %,$(capture_dir)/libng/plugins/%.so,${LIBNG_PLUGINS}) # global targets all:: $(TARGETS-plugins) clean:: clean-plugins clean-plugins: rm -f $(TARGETS-plugins) $(capture_dir)/libng/plugins/*.o $(TARGETS-plugins): CFLAGS+=$(V4L_CFLAGS) -I$(capture_dir) -I$(capture_dir)/libng -I$(capture_dir)/structs $(TARGETS-plugins): LDFLAGS+=$(foreach rp,$(RPATH),"-Wl,-rpath=$(rp)/$(capture_dir)/libng") $(TARGETS-plugins): MORE_LIBS=-L$(capture_dir)/libng -lng $(TARGETS-plugins): | $(capture_dir)/libng/libng.so $(capture_dir)/libng/plugins/drv0-v4l2.so: \ $(capture_dir)/libng/plugins/drv0-v4l2.o \ $(capture_dir)/libng/plugins/struct-v4l2.o \ $(capture_dir)/libng/plugins/struct-dump.o @$(echo_link_so) @$(link_so) $(capture_dir)/libng/plugins/drv1-v4l.so: \ $(capture_dir)/libng/plugins/drv1-v4l.o \ $(capture_dir)/libng/plugins/struct-v4l.o \ $(capture_dir)/libng/plugins/struct-dump.o @$(echo_link_so) @$(link_so) $(capture_dir)/libng/plugins/struct-dump.o: $(capture_dir)/structs/struct-dump.c @$(echo_compile_c) @$(compile_c) $(capture_dir)/libng/plugins/struct-v4l.o: $(capture_dir)/structs/struct-v4l.c @$(echo_compile_c) @$(compile_c) $(capture_dir)/libng/plugins/struct-v4l2.o: $(capture_dir)/structs/struct-v4l2.c @$(echo_compile_c) @$(compile_c) amsn-0.98.9/utils/linux/capture/libng/writefile.h0000644000175000017500000000044410246003435021570 0ustar billiobbilliobint patch_up(char *name); char* snap_filename(char *base, char *channel, char *ext); int write_jpeg(char *filename, struct ng_video_buf *buf, int quality, int gray); int write_ppm(char *filename, struct ng_video_buf *buf); int write_pgm(char *filename, struct ng_video_buf *buf); amsn-0.98.9/utils/linux/capture/libng/color_yuv2rgb.c0000644000175000017500000003050211755523031022372 0ustar billiobbilliob/* * colorspace conversion functions * -- yuv to rgb colorspace conversions * * (c) 2001-03 Gerd Knorr * */ #define NG_PRIVATE #include "config.h" #include #include #include #include #include #include #include #include "grab-ng.h" /* ------------------------------------------------------------------- */ #define CLIP 320 #if 0 # define RED_NULL 137 # define BLUE_NULL 156 # define LUN_MUL 360 # define RED_MUL 512 # define BLUE_MUL 512 #else # define RED_NULL 128 # define BLUE_NULL 128 # define LUN_MUL 256 # define RED_MUL 512 # define BLUE_MUL 512 #endif #define GREEN1_MUL (-RED_MUL/2) #define GREEN2_MUL (-BLUE_MUL/6) #define RED_ADD (-RED_NULL * RED_MUL) #define BLUE_ADD (-BLUE_NULL * BLUE_MUL) #define GREEN1_ADD (-RED_ADD/2) #define GREEN2_ADD (-BLUE_ADD/6) /* lookup tables */ static int32_t ng_yuv_gray[256]; static int32_t ng_yuv_red[256]; static int32_t ng_yuv_blue[256]; static int32_t ng_yuv_g1[256]; static int32_t ng_yuv_g2[256]; static int32_t ng_clip[256 + 2 * CLIP]; #define GRAY(val) ng_yuv_gray[val] #define RED(gray,red) ng_clip[ CLIP + gray + ng_yuv_red[red] ] #define GREEN(gray,red,blue) ng_clip[ CLIP + gray + ng_yuv_g1[red] + \ ng_yuv_g2[blue] ] #define BLUE(gray,blue) ng_clip[ CLIP + gray + ng_yuv_blue[blue] ] /* ------------------------------------------------------------------- */ /* packed pixel yuv to gray / rgb */ static void yuv422_to_gray(uint8_t* restrict dest, uint8_t* restrict s, int p) { uint8_t* restrict d = dest; while (p) { d[0] = GRAY(s[0]); p--; d++; s+=2; } } static void yuv422_to_rgb24(uint8_t* restrict dest, uint8_t* restrict s, int p) { uint8_t* restrict d = dest; int gray; while (p) { gray = GRAY(s[0]); d[0] = RED(gray,s[3]); d[1] = GREEN(gray,s[3],s[1]); d[2] = BLUE(gray,s[1]); gray = GRAY(s[2]); d[3] = RED(gray,s[3]); d[4] = GREEN(gray,s[3],s[1]); d[5] = BLUE(gray,s[1]); d += 6; s += 4; p -= 2; } } void ng_yuv422_to_lut2(uint8_t* restrict dest, uint8_t* restrict s, int p) { uint16_t* restrict d = (uint16_t*)dest; int gray; while (p) { gray = GRAY(s[0]); *(d++) = ng_lut_red[RED(gray,s[3])] | ng_lut_green[GREEN(gray,s[3],s[1])] | ng_lut_blue[BLUE(gray,s[1])]; gray = GRAY(s[2]); *(d++) = ng_lut_red[RED(gray,s[3])] | ng_lut_green[GREEN(gray,s[3],s[1])] | ng_lut_blue[BLUE(gray,s[1])]; s += 4; p -= 2; } } void ng_yuv422_to_lut4(uint8_t* restrict dest, uint8_t* restrict s, int p) { uint32_t* restrict d = (uint32_t*)dest; int gray; while (p) { gray = GRAY(s[0]); *(d++) = ng_lut_red[RED(gray,s[3])] | ng_lut_green[GREEN(gray,s[3],s[1])] | ng_lut_blue[BLUE(gray,s[1])]; gray = GRAY(s[2]); *(d++) = ng_lut_red[RED(gray,s[3])] | ng_lut_green[GREEN(gray,s[3],s[1])] | ng_lut_blue[BLUE(gray,s[1])]; s += 4; p -= 2; } } /* ------------------------------------------------------------------- */ /* planar yuv to gray / rgb */ static void yuv42xp_to_gray(void *h, struct ng_video_buf *out, struct ng_video_buf *in) { uint8_t* restrict y; uint8_t* restrict d; uint8_t* dp; unsigned int i,j; dp = out->data; y = in->data; for (i = 0; i < in->fmt.height; i++) { d = dp; for (j = 0; j < in->fmt.width; j++) { *d = GRAY(*y); d++,y++; } dp += out->fmt.bytesperline; } out->info = in->info; } static void yuv420p_to_rgb24(void *h, struct ng_video_buf *out, struct ng_video_buf *in) { uint8_t *restrict y, *restrict u, *restrict v, *restrict d; uint8_t *us,*vs; uint8_t *dp; unsigned int i,j; int gray; dp = out->data; y = in->data; u = y + in->fmt.width * in->fmt.height; v = u + in->fmt.width * in->fmt.height / 4; for (i = 0; i < in->fmt.height; i++) { d = dp; us = u; vs = v; for (j = 0; j < in->fmt.width; j+= 2) { gray = GRAY(*y); *(d++) = RED(gray,*v); *(d++) = GREEN(gray,*v,*u); *(d++) = BLUE(gray,*u); y++; gray = GRAY(*y); *(d++) = RED(gray,*v); *(d++) = GREEN(gray,*v,*u); *(d++) = BLUE(gray,*u); y++; u++; v++; } if (0 == (i % 2)) { u = us; v = vs; } dp += out->fmt.bytesperline; } out->info = in->info; } static void yuv422p_to_rgb24(void *h, struct ng_video_buf *out, struct ng_video_buf *in) { uint8_t *restrict y, *restrict u, *restrict v, *restrict d; uint8_t *dp; unsigned int i,j; int gray; dp = out->data; y = in->data; u = y + in->fmt.width * in->fmt.height; v = u + in->fmt.width * in->fmt.height / 2; for (i = 0; i < in->fmt.height; i++) { d = dp; for (j = 0; j < in->fmt.width; j+= 2) { gray = GRAY(*y); *(d++) = RED(gray,*v); *(d++) = GREEN(gray,*v,*u); *(d++) = BLUE(gray,*u); y++; gray = GRAY(*y); *(d++) = RED(gray,*v); *(d++) = GREEN(gray,*v,*u); *(d++) = BLUE(gray,*u); y++; u++; v++; } dp += out->fmt.bytesperline; } out->info = in->info; } uyvy_to_rgb24(void *h, struct ng_video_buf *out, struct ng_video_buf *in) { uint8_t *restrict s, *restrict d; uint8_t *dp; unsigned int i,j; int gray; dp = out->data; s = in->data; for (i = 0; i < in->fmt.height; i++) { d = dp; for (j = 0; j < in->fmt.width; j+= 2) { gray = GRAY(s[1]); d[0] = RED(gray,s[2]); d[1] = GREEN(gray,s[2],s[0]); d[2] = BLUE(gray,s[0]); gray = GRAY(s[3]); d[3] = RED(gray,s[2]); d[4] = GREEN(gray,s[2],s[0]); d[5] = BLUE(gray,s[0]); d += 6; s += 4; } dp += out->fmt.bytesperline; } out->info = in->info; } void ng_yuv420p_to_lut2(void *h, struct ng_video_buf *out, struct ng_video_buf *in) { uint8_t *restrict y, *restrict u, *restrict v; uint8_t *us,*vs; uint8_t *dp; uint16_t *restrict d; unsigned int i,j; int gray; dp = out->data; y = in->data; u = y + in->fmt.width * in->fmt.height; v = u + in->fmt.width * in->fmt.height / 4; for (i = 0; i < in->fmt.height; i++) { d = (uint16_t*) dp; us = u; vs = v; for (j = 0; j < in->fmt.width; j+= 2) { gray = GRAY(*y); *(d++) = ng_lut_red [ RED(gray,*v) ] | ng_lut_green [ GREEN(gray,*v,*u) ] | ng_lut_blue [ BLUE(gray,*u) ]; y++; gray = GRAY(*y); *(d++) = ng_lut_red [ RED(gray,*v) ] | ng_lut_green [ GREEN(gray,*v,*u) ] | ng_lut_blue [ BLUE(gray,*u) ]; y++; u++; v++; } if (0 == (i % 2)) { u = us; v = vs; } dp += out->fmt.bytesperline; } out->info = in->info; } void ng_yuv422p_to_lut2(void *h, struct ng_video_buf *out, struct ng_video_buf *in) { uint8_t *restrict y, *restrict u, *restrict v; uint8_t *dp; uint16_t *restrict d; unsigned int i,j; int gray; dp = out->data; y = in->data; u = y + in->fmt.width * in->fmt.height; v = u + in->fmt.width * in->fmt.height / 2; for (i = 0; i < in->fmt.height; i++) { d = (uint16_t*) dp; for (j = 0; j < in->fmt.width; j+= 2) { gray = GRAY(*y); *(d++) = ng_lut_red[RED(gray,*v)] | ng_lut_green[GREEN(gray,*v,*u)] | ng_lut_blue[BLUE(gray,*u)]; y++; gray = GRAY(*y); *(d++) = ng_lut_red[RED(gray,*v)] | ng_lut_green[GREEN(gray,*v,*u)] | ng_lut_blue[BLUE(gray,*u)]; y++; u++; v++; } dp += out->fmt.bytesperline; } out->info = in->info; } void ng_yuv420p_to_lut4(void *h, struct ng_video_buf *out, struct ng_video_buf *in) { uint8_t *restrict y, *restrict u, *restrict v; uint8_t *us,*vs; uint8_t *dp; uint32_t *restrict d; unsigned int i,j; int gray; dp = out->data; y = in->data; u = y + in->fmt.width * in->fmt.height; v = u + in->fmt.width * in->fmt.height / 4; for (i = 0; i < in->fmt.height; i++) { d = (uint32_t*) dp; us = u; vs = v; for (j = 0; j < in->fmt.width; j+= 2) { gray = GRAY(*y); *(d++) = ng_lut_red[RED(gray,*v)] | ng_lut_green[GREEN(gray,*v,*u)] | ng_lut_blue[BLUE(gray,*u)]; y++; gray = GRAY(*y); *(d++) = ng_lut_red[RED(gray,*v)] | ng_lut_green[GREEN(gray,*v,*u)] | ng_lut_blue[BLUE(gray,*u)]; y++; u++; v++; } if (0 == (i % 2)) { u = us; v = vs; } dp += out->fmt.bytesperline; } out->info = in->info; } void ng_yuv422p_to_lut4(void *h, struct ng_video_buf *out, struct ng_video_buf *in) { uint8_t *restrict y, *restrict u, *restrict v; uint8_t *dp; uint32_t *restrict d; unsigned int i,j; int gray; dp = out->data; y = in->data; u = y + in->fmt.width * in->fmt.height; v = u + in->fmt.width * in->fmt.height / 2; for (i = 0; i < in->fmt.height; i++) { d = (uint32_t*) dp; for (j = 0; j < in->fmt.width; j+= 2) { gray = GRAY(*y); *(d++) = ng_lut_red[RED(gray,*v)] | ng_lut_green[GREEN(gray,*v,*u)] | ng_lut_blue[BLUE(gray,*u)]; y++; gray = GRAY(*y); *(d++) = ng_lut_red[RED(gray,*v)] | ng_lut_green[GREEN(gray,*v,*u)] | ng_lut_blue[BLUE(gray,*u)]; y++; u++; v++; } dp += out->fmt.bytesperline; } out->info = in->info; } /* ------------------------------------------------------------------- */ /* planar -> packed pixel */ #if 0 /* untested */ static void yuv422p_to_yuv422(void *h, struct ng_video_buf *out, struct ng_video_buf *in) { uint8_t *restrict y, *restrict u, *restrict v; uint8_t *dp; uint8_t *restrict d; unsigned int i,j; dp = out->data; y = in->data; u = y + in->fmt.width * in->fmt.height; v = u + in->fmt.width * in->fmt.height / 2; for (i = 0; i < in->fmt.height; i++) { d = dp; for (j = 0; j < in->fmt.width; j+= 2) { *(d++) = *(y++); *(d++) = *(u++); *(d++) = *(y++); *(d++) = *(v++); } dp += out->fmt.bytesperline; } out->info = in->info; } #endif /* ------------------------------------------------------------------- */ static struct ng_video_conv conv_list[] = { { NG_GENERIC_PACKED, .fmtid_in = VIDEO_YUYV, .fmtid_out = VIDEO_RGB24, .priv = yuv422_to_rgb24, },{ NG_GENERIC_PACKED, .fmtid_in = VIDEO_YUYV, .fmtid_out = VIDEO_GRAY, .priv = yuv422_to_gray, },{ .init = ng_conv_nop_init, .p.mode = NG_MODE_TRIVIAL, .p.fini = ng_conv_nop_fini, .p.frame = uyvy_to_rgb24, .fmtid_in = VIDEO_UYVY, .fmtid_out = VIDEO_RGB24, },{ .init = ng_conv_nop_init, .p.mode = NG_MODE_TRIVIAL, .p.fini = ng_conv_nop_fini, .p.frame = yuv422p_to_rgb24, .fmtid_in = VIDEO_YUV422P, .fmtid_out = VIDEO_RGB24, },{ .init = ng_conv_nop_init, .p.mode = NG_MODE_TRIVIAL, .p.fini = ng_conv_nop_fini, .p.frame = yuv420p_to_rgb24, .fmtid_in = VIDEO_YUV420P, .fmtid_out = VIDEO_RGB24, },{ .init = ng_conv_nop_init, .p.mode = NG_MODE_TRIVIAL, .p.fini = ng_conv_nop_fini, .p.frame = yuv42xp_to_gray, .fmtid_in = VIDEO_YUV422P, .fmtid_out = VIDEO_GRAY, },{ .init = ng_conv_nop_init, .p.mode = NG_MODE_TRIVIAL, .p.fini = ng_conv_nop_fini, .p.frame = yuv42xp_to_gray, .fmtid_in = VIDEO_YUV420P, .fmtid_out = VIDEO_GRAY, #if 0 /* untested */ },{ .init = ng_conv_nop_init, .p.mode = NG_MODE_TRIVIAL, .p.fini = ng_conv_nop_fini, .p.frame = yuv422p_to_yuv422, .fmtid_in = VIDEO_YUV422P, .fmtid_out = VIDEO_YUYV, #endif } }; static const int nconv = sizeof(conv_list)/sizeof(struct ng_video_conv); /* ------------------------------------------------------------------- */ void yuv2rgb_init(void) { int i; /* init Lookup tables */ for (i = 0; i < 256; i++) { ng_yuv_gray[i] = i * LUN_MUL >> 8; ng_yuv_red[i] = (RED_ADD + i * RED_MUL) >> 8; ng_yuv_blue[i] = (BLUE_ADD + i * BLUE_MUL) >> 8; ng_yuv_g1[i] = (GREEN1_ADD + i * GREEN1_MUL) >> 8; ng_yuv_g2[i] = (GREEN2_ADD + i * GREEN2_MUL) >> 8; } for (i = 0; i < CLIP; i++) ng_clip[i] = 0; for (; i < CLIP + 256; i++) ng_clip[i] = i - CLIP; for (; i < 2 * CLIP + 256; i++) ng_clip[i] = 255; /* register stuff */ ng_conv_register(NG_PLUGIN_MAGIC,__FILE__,conv_list,nconv); } amsn-0.98.9/utils/linux/capture/pkgIndex.tcl0000644000175000017500000000034110545734571020621 0ustar billiobbilliob# Tcl package index file, version 1.0 if {[package vcompare [info tclversion] 8.4] < 0} return package ifneeded capture 0.5 "package require Tk; [list load [file join $dir capture.so] capture]; package provide capture 0.5" amsn-0.98.9/utils/linux/capture/capture.h0000644000175000017500000000764311550715353020166 0ustar billiobbilliob/* File : capture.h Description : Header file for the capture extension for tk. Author : Youness El Alaoui ( KaKaRoTo - kakaroto@user.sourceforge.net) */ #ifndef _CAPTURE #define _CAPTURE // Include files, must include windows.h before tk.h and tcl.h before tk.h or else compiling errors #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" /* #ifdef HAVE_SYS_VIDEODEV2_H # include #else # include #endif */ #include "grab-ng.h" // Defined as described in tcl.tk compiling extension help #ifndef STATIC_BUILD #if defined(_MSC_VER) # define EXPORT(a,b) __declspec(dllexport) a b # define DllEntryPoint DllMain #else # if defined(__BORLANDC__) # define EXPORT(a,b) a _export b # else # define EXPORT(a,b) a b # endif #endif #endif #define DLL_BUILD #define BUILD_CAPTURE #ifdef BUILD_CAPTURE # undef TCL_STORAGE_CLASS # define TCL_STORAGE_CLASS DLLEXPORT #endif #define min(a,b) (a<=b?a:b) #ifdef __cplusplus extern "C" #endif struct image_format { char *format_name; int width; int height; }; static const struct image_format formats_list[] = { \ { "SQCIF", 128, 96 }, \ { "QSIF", 160, 120 }, \ { "QCIF", 176, 144 }, \ { "SIF", 320, 240 }, \ { "CIF", 352, 288 }, \ { "VGA", 640, 480 }, \ { "SXGA", 1280, 960 }, \ { NULL, 0, 0 }, \ }; // Structures for the list struct capture_item { char captureName[32]; char devicePath[32]; int channel; struct image_format *requested_format; struct ng_devstate dev; struct ng_video_fmt fmt; struct ng_process_handle *handle; struct ng_video_buf *image_data; struct ng_video_buf *rgb_buffer; }; // Defines for compatibility with the list code.. #define g_list opened_devices #define data_item capture_item #define list_element_id captureName // Capture extension's Tcl command implementations EXTERN int Capture_ListResolutions _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Capture_ListDevices _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Capture_ListChannels _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Capture_GetGrabber _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Capture_ListGrabbers _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Capture_Grab _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Capture_Open _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Capture_ChangeResolution _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Capture_Close _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Capture_IsValid _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Capture_SetAttribute _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Capture_GetAttribute _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Capture_Debug _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); // Capture extension initialisation functions EXTERN int Capture_Init _ANSI_ARGS_((Tcl_Interp *interp)); EXTERN int Capture_SafeInit _ANSI_ARGS_((Tcl_Interp *interp)); # undef TCL_STORAGE_CLASS # define TCL_STORAGE_CLASS DLLIMPORT #endif /* _CAPTURE */ amsn-0.98.9/utils/linux/capture/structs/0000755000175000017500000000000011757711632020054 5ustar billiobbilliobamsn-0.98.9/utils/linux/capture/structs/struct-v4l.h0000644000175000017500000000133610246003435022242 0ustar billiobbilliobextern char *bits_vid_cap[32]; extern char *bits_chan_flags[32]; extern char *desc_chan_type[]; extern char *bits_tuner_flags[32]; extern char *desc_tuner_mode[]; extern char *desc_pict_palette[]; extern char *bits_audio_flags[32]; extern char *bits_audio_mode[32]; extern struct struct_desc desc_video_capability[]; extern struct struct_desc desc_video_channel[]; extern struct struct_desc desc_video_tuner[]; extern struct struct_desc desc_video_picture[]; extern struct struct_desc desc_video_audio[]; extern struct struct_desc desc_video_window[]; extern struct struct_desc desc_video_buffer[]; extern struct struct_desc desc_video_mmap[]; extern struct struct_desc desc_video_mbuf[]; extern struct ioctl_desc ioctls_v4l1[256]; amsn-0.98.9/utils/linux/capture/structs/struct-dump.h0000644000175000017500000000227610733772533022523 0ustar billiobbilliob enum desc_type { UINT64, SINT64, UINT32, SINT32, UINT16, SINT16, UINT8, SINT8, FOURCC, STRING, PTR, ENUM16, ENUM32, STRUCT, UNION, BITS16, BITS32, BITS64, VER, PADDING, }; struct struct_desc { enum desc_type type; char *name; unsigned int length; char **enums; char **bits; struct struct_desc *desc; struct { unsigned int value; char *name; struct struct_desc *desc; } u[16]; }; struct ioctl_desc { char *name; struct struct_desc *desc; }; /* ---------------------------------------------------------------------- */ extern struct struct_desc desc_int[]; extern struct struct_desc desc_long[]; extern struct struct_desc desc_timeval[]; /* ---------------------------------------------------------------------- */ int print_struct(FILE *fp, struct struct_desc *desc, void *data, char *prefix, int tab); int print_ioctl(FILE *fp, struct ioctl_desc *ioctls, char *prefix, int cmd, void *ptr); /* ---------------------------------------------------------------------- */ #ifdef __sun # include # define _IOC_NR(x) \ ((int)x & IOCPARM_MASK) #endif amsn-0.98.9/utils/linux/capture/structs/ioctl2desc0000644000175000017500000000044110246003435022014 0ustar billiobbilliob#!/usr/bin/perl use strict; my ($name,$type); while (<>) { ($name,$type) = m/\#define\s+(\w+)\s+_IO\w+\s*\([^,]+,\s*\d+,\s*(.*?)\)/ or next; $type =~ s/struct /desc_/; print "[_IOC_NR($name)] = {\n"; print "\t.name = \"$name\",\n"; print "\t.desc = $type,\n"; print "},\n"; } amsn-0.98.9/utils/linux/capture/structs/struct-v4l2.c0000644000175000017500000004761110733772533022342 0ustar billiobbilliob#include #include #include #include "config.h" #ifdef HAVE_SYS_VIDEODEV2_H # include #else #include #include "videodev2.h" #endif #include "struct-dump.h" #include "struct-v4l2.h" /* ---------------------------------------------------------------------- */ char *desc_v4l2_field[] = { [V4L2_FIELD_ANY] = "ANY", [V4L2_FIELD_NONE] = "NONE", [V4L2_FIELD_TOP] = "TOP", [V4L2_FIELD_BOTTOM] = "BOTTOM", [V4L2_FIELD_INTERLACED] = "INTERLACED", [V4L2_FIELD_SEQ_TB] = "SEQ_TB", [V4L2_FIELD_SEQ_BT] = "SEQ_BT", [V4L2_FIELD_ALTERNATE] = "ALTERNATE", }; char *desc_v4l2_buf_type[] = { [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "VIDEO_CAPTURE", [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "VIDEO_OUTPUT", [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "VIDEO_OVERLAY", [V4L2_BUF_TYPE_VBI_CAPTURE] = "VBI_CAPTURE", [V4L2_BUF_TYPE_VBI_OUTPUT] = "VBI_OUTPUT", [V4L2_BUF_TYPE_PRIVATE] = "PRIVATE", }; char *desc_v4l2_ctrl_type[] = { [V4L2_CTRL_TYPE_INTEGER] = "INTEGER", [V4L2_CTRL_TYPE_BOOLEAN] = "BOOLEAN", [V4L2_CTRL_TYPE_MENU] = "MENU", [V4L2_CTRL_TYPE_BUTTON] = "BUTTON", }; char *desc_v4l2_tuner_type[] = { [V4L2_TUNER_RADIO] = "RADIO", [V4L2_TUNER_ANALOG_TV] = "ANALOG_TV", }; char *desc_v4l2_memory[] = { [V4L2_MEMORY_MMAP] = "MMAP", [V4L2_MEMORY_USERPTR] = "USERPTR", [V4L2_MEMORY_OVERLAY] = "OVERLAY", }; char *desc_v4l2_colorspace[] = { [V4L2_COLORSPACE_SMPTE170M] = "SMPTE170M", [V4L2_COLORSPACE_SMPTE240M] = "SMPTE240M", [V4L2_COLORSPACE_REC709] = "REC709", [V4L2_COLORSPACE_BT878] = "BT878", [V4L2_COLORSPACE_470_SYSTEM_M] = "470_SYSTEM_M", [V4L2_COLORSPACE_470_SYSTEM_BG] = "470_SYSTEM_BG", [V4L2_COLORSPACE_JPEG] = "JPEG", [V4L2_COLORSPACE_SRGB] = "SRGB", }; char *bits_capabilities[32] = { "VIDEO_CAPTURE", "VIDEO_OUTPUT", "VIDEO_OVERLAY", "", "VBI_CAPTURE", "VBI_OUTPUT", "?","?", "RDS_CAPTURE", "?", "?", "?", "?", "?", "?", "?", "TUNER", "AUDIO", "?", "?", "?", "?", "?", "?", "READWRITE", "ASYNCIO", "STREAMING", "?", }; char *bits_standard[64] = { "PAL_B", "PAL_B1", "PAL_G", "PAL_H", "PAL_I", "PAL_D", "PAL_D1", "PAL_K", "PAL_M", "PAL_N", "PAL_Nc", "PAL_60", "NTSC_M", "NTSC_M_JP", "?", "?", "SECAM_B", "SECAM_D", "SECAM_G", "SECAM_H", "SECAM_K", "SECAM_K1", "SECAM_L", "?" "ATSC_8_VSB", "ATSC_16_VSB", }; char *bits_buf_flags[32] = { "MAPPED", "QUEUED", "DONE", "KEYFRAME", "PFRAME", "BFRAME", "?", "?", "TIMECODE", }; char *bits_fbuf_cap[32] = { "EXTERNOVERLAY", "CHROMAKEY", "LIST_CLIPPING", "BITMAP_CLIPPING", }; char *bits_fbuf_flags[32] = { "PRIMARY", "OVERLAY", "CHROMAKEY", }; char *desc_input_type[32] = { [ V4L2_INPUT_TYPE_TUNER ] = "TUNER", [ V4L2_INPUT_TYPE_CAMERA ] = "CAMERA", }; char *bits_input_status[32] = { "NO_POWER", "NO_SIGNAL", "NO_COLOR", "?", "?","?","?","?", "NO_H_LOCK", "COLOR_KILL", "?", "?", "?","?","?","?", "NO_SYNC", "NO_EQU", "NO_CARRIER", "?", "?","?","?","?", "MACROVISION", "NO_ACCESS", "VTR", "?", "?","?","?","?", }; char *bits_tuner_cap[32] = { "LOW", "NORM", "?", "?", "STEREO", "LANG2", "LANG1", "?", }; char *bits_tuner_rx[32] = { "MONO", "STEREO", "LANG2", "LANG1", }; char *desc_tuner2_mode[] = { [ V4L2_TUNER_MODE_MONO ] = "MONO", [ V4L2_TUNER_MODE_STEREO ] = "STEREO", [ V4L2_TUNER_MODE_LANG2 ] = "LANG2", [ V4L2_TUNER_MODE_LANG1 ] = "LANG1", }; /* ---------------------------------------------------------------------- */ struct struct_desc desc_v4l2_rect[] = {{ .type = SINT32, .name = "left", },{ .type = SINT32, .name = "top", },{ .type = SINT32, .name = "width", },{ .type = SINT32, .name = "height", },{ /* end of list */ }}; struct struct_desc desc_v4l2_fract[] = {{ .type = UINT32, .name = "numerator", },{ .type = UINT32, .name = "denominator", },{ /* end of list */ }}; struct struct_desc desc_v4l2_capability[] = {{ .type = STRING, .name = "driver", .length = 16, },{ .type = STRING, .name = "card", .length = 32, },{ .type = STRING, .name = "bus_info", .length = 32, },{ .type = VER, .name = "version", },{ .type = BITS32, .name = "capabilities", .bits = bits_capabilities, },{ /* end of list */ }}; struct struct_desc desc_v4l2_pix_format[] = {{ .type = UINT32, .name = "width", },{ .type = UINT32, .name = "height", },{ .type = FOURCC, .name = "pixelformat", },{ .type = ENUM32, .name = "field", .enums = desc_v4l2_field, .length = sizeof(desc_v4l2_field) / sizeof(char*), },{ .type = UINT32, .name = "bytesperline", },{ .type = UINT32, .name = "sizeimage", },{ .type = ENUM32, .name = "colorspace", .enums = desc_v4l2_colorspace, .length = sizeof(desc_v4l2_colorspace) / sizeof(char*), },{ .type = UINT32, .name = "priv", },{ /* end of list */ }}; struct struct_desc desc_v4l2_fmtdesc[] = {{ .type = UINT32, .name = "index", },{ .type = ENUM32, .name = "type", .enums = desc_v4l2_buf_type, .length = sizeof(desc_v4l2_buf_type) / sizeof(char*), },{ .type = UINT32, .name = "flags", },{ .type = STRING, .name = "description", .length = 32, },{ .type = FOURCC, .name = "pixelformat", },{ /* end of list */ }}; struct struct_desc desc_v4l2_timecode[] = {{ .type = UINT32, .name = "type", },{ .type = UINT32, .name = "flags", },{ .type = UINT8, .name = "frames", },{ .type = UINT8, .name = "seconds", },{ .type = UINT8, .name = "minutes", },{ .type = UINT8, .name = "hours", },{ .type = STRING, .name = "userbits", .length = 4, },{ /* end of list */ }}; struct struct_desc desc_v4l2_compression[] = {{ .type = UINT32, .name = "quality", },{ .type = UINT32, .name = "keyframerate", },{ .type = UINT32, .name = "pframerate", },{ /* end of list */ }}; struct struct_desc desc_v4l2_jpegcompression[] = {{ .type = SINT32, .name = "quality", },{ .type = SINT32, .name = "APPn", },{ .type = SINT32, .name = "APP_len", },{ .type = STRING, .name = "APP_data", .length = 60, },{ .type = SINT32, .name = "COM_len", },{ .type = STRING, .name = "COM_data", .length = 60, },{ .type = UINT32, .name = "jpeg_markers", },{ /* end of list */ }}; struct struct_desc desc_v4l2_requestbuffers[] = {{ .type = UINT32, .name = "count", },{ .type = ENUM32, .name = "type", .enums = desc_v4l2_buf_type, .length = sizeof(desc_v4l2_buf_type) / sizeof(char*), },{ .type = ENUM32, .name = "memory", .enums = desc_v4l2_memory, .length = sizeof(desc_v4l2_memory) / sizeof(char*), },{ /* end of list */ }}; struct struct_desc desc_v4l2_buffer[] = {{ .type = UINT32, .name = "index", },{ .type = ENUM32, .name = "type", .enums = desc_v4l2_buf_type, .length = sizeof(desc_v4l2_buf_type) / sizeof(char*), },{ .type = UINT32, .name = "bytesused", },{ .type = BITS32, .name = "flags", .bits = bits_buf_flags, },{ .type = ENUM32, .name = "field", .enums = desc_v4l2_field, .length = sizeof(desc_v4l2_field) / sizeof(char*), },{ .type = STRUCT, .name = "timestamp", .desc = desc_timeval, .length = sizeof(struct timeval), },{ .type = STRUCT, .name = "timecode", .desc = desc_v4l2_timecode, .length = sizeof(struct v4l2_timecode), },{ .type = UINT32, .name = "sequence", },{ .type = ENUM32, .name = "memory", .enums = desc_v4l2_memory, .length = sizeof(desc_v4l2_memory) / sizeof(char*), },{ /* FIXME ... */ /* end of list */ }}; struct struct_desc desc_v4l2_framebuffer[] = {{ .type = BITS32, .name = "capability", .bits = bits_fbuf_cap, },{ .type = BITS32, .name = "flags", .bits = bits_fbuf_flags, },{ .type = PTR, .name = "base", },{ .type = STRUCT, .name = "fmt", .desc = desc_v4l2_pix_format, .length = sizeof(struct v4l2_pix_format), },{ /* end of list */ }}; struct struct_desc desc_v4l2_clip[] = {{ .type = STRUCT, .name = "c", .desc = desc_v4l2_rect, .length = sizeof(struct v4l2_rect), },{ /* end of list */ }}; struct struct_desc desc_v4l2_window[] = {{ .type = STRUCT, .name = "w", .desc = desc_v4l2_rect, .length = sizeof(struct v4l2_rect), },{ .type = ENUM32, .name = "field", .enums = desc_v4l2_field, .length = sizeof(desc_v4l2_field) / sizeof(char*), },{ .type = UINT32, .name = "chromakey", },{ .type = PTR, .name = "clips", },{ .type = UINT32, .name = "clipcount", },{ .type = PTR, .name = "bitmap", },{ /* end of list */ }}; struct struct_desc desc_v4l2_captureparm[] = {{ .type = UINT32, .name = "capability", },{ .type = UINT32, .name = "capturemode", },{ .type = STRUCT, .name = "timeperframe", .desc = desc_v4l2_fract, .length = sizeof(struct v4l2_fract), },{ .type = UINT32, .name = "extendedmode", },{ .type = UINT32, .name = "readbuffers", },{ /* end of list */ }}; struct struct_desc desc_v4l2_outputparm[] = {{ .type = UINT32, .name = "capability", },{ .type = UINT32, .name = "outputmode", },{ .type = STRUCT, .name = "timeperframe", .desc = desc_v4l2_fract, .length = sizeof(struct v4l2_fract), },{ .type = UINT32, .name = "extendedmode", },{ .type = UINT32, .name = "writebuffers", },{ /* end of list */ }}; struct struct_desc desc_v4l2_cropcap[] = {{ .type = ENUM32, .name = "type", .enums = desc_v4l2_buf_type, .length = sizeof(desc_v4l2_buf_type) / sizeof(char*), },{ .type = STRUCT, .name = "bounds", .desc = desc_v4l2_rect, .length = sizeof(struct v4l2_rect), },{ .type = STRUCT, .name = "defrect", .desc = desc_v4l2_rect, .length = sizeof(struct v4l2_rect), },{ .type = STRUCT, .name = "pixelaspect", .desc = desc_v4l2_fract, .length = sizeof(struct v4l2_fract), },{ /* end of list */ }}; struct struct_desc desc_v4l2_crop[] = {{ .type = ENUM32, .name = "type", .enums = desc_v4l2_buf_type, .length = sizeof(desc_v4l2_buf_type) / sizeof(char*), },{ .type = STRUCT, .name = "c", .desc = desc_v4l2_rect, .length = sizeof(struct v4l2_rect), },{ /* end of list */ }}; struct struct_desc desc_v4l2_standard[] = {{ .type = UINT32, .name = "index", },{ .type = BITS64, .name = "id", .bits = bits_standard, },{ .type = STRING, .name = "name", .length = 24, },{ .type = STRUCT, .name = "frameperiod", .desc = desc_v4l2_fract, .length = sizeof(struct v4l2_fract), },{ .type = UINT32, .name = "framelines", },{ /* end of list */ }}; struct struct_desc desc_v4l2_input[] = {{ .type = UINT32, .name = "index", },{ .type = STRING, .name = "name", .length = 32, },{ .type = ENUM32, .name = "type", .enums = desc_input_type, .length = sizeof(desc_input_type) / sizeof(char*), },{ .type = UINT32, .name = "audioset", },{ .type = UINT32, .name = "tuner", },{ .type = BITS64, .name = "std", .bits = bits_standard },{ .type = BITS32, .name = "status", .bits = bits_input_status, },{ /* end of list */ }}; struct struct_desc desc_v4l2_output[] = {{ .type = UINT32, .name = "index", },{ .type = STRING, .name = "name", .length = 32, },{ .type = UINT32, .name = "type", },{ .type = UINT32, .name = "audioset", },{ .type = UINT32, .name = "modulator", },{ .type = BITS64, .name = "std", .bits = bits_standard },{ /* end of list */ }}; struct struct_desc desc_v4l2_control[] = {{ .type = UINT32, .name = "id", },{ .type = SINT32, .name = "value", },{ /* end of list */ }}; struct struct_desc desc_v4l2_queryctrl[] = {{ .type = UINT32, .name = "id", },{ .type = ENUM32, .name = "type", .enums = desc_v4l2_ctrl_type, .length = sizeof(desc_v4l2_buf_type) / sizeof(char*), },{ .type = STRING, .name = "name", .length = 32, },{ .type = SINT32, .name = "minimum", },{ .type = SINT32, .name = "maximum", },{ .type = SINT32, .name = "step", },{ .type = SINT32, .name = "default_value", },{ .type = UINT32, .name = "flags", },{ /* end of list */ }}; struct struct_desc desc_v4l2_querymenu[] = {{ .type = UINT32, .name = "id", },{ .type = UINT32, .name = "index", },{ .type = STRING, .name = "name", .length = 32, },{ .type = UINT32, .name = "reserved", },{ /* end of list */ }}; struct struct_desc desc_v4l2_tuner[] = {{ .type = UINT32, .name = "index", },{ .type = STRING, .name = "name", .length = 32, },{ .type = ENUM32, .name = "type", .enums = desc_v4l2_tuner_type, .length = sizeof(desc_v4l2_tuner_type) / sizeof(char*), },{ .type = BITS32, .name = "capability", .bits = bits_tuner_cap, },{ .type = UINT32, .name = "rangelow", },{ .type = UINT32, .name = "rangehigh", },{ .type = BITS32, .name = "rxsubchans", .bits = bits_tuner_rx, },{ .type = ENUM32, .name = "audmode", .enums = desc_tuner2_mode, .length = sizeof(desc_tuner2_mode) / sizeof(char*), },{ .type = SINT32, .name = "signal", },{ .type = SINT32, .name = "afc", },{ /* end of list */ }}; struct struct_desc desc_v4l2_modulator[] = {{ .type = UINT32, .name = "index", },{ .type = STRING, .name = "name", .length = 32, },{ .type = UINT32, .name = "capability", },{ .type = UINT32, .name = "rangelow", },{ .type = UINT32, .name = "rangehigh", },{ .type = UINT32, .name = "txsubchans", },{ /* end of list */ }}; struct struct_desc desc_v4l2_frequency[] = {{ .type = UINT32, .name = "tuner", },{ .type = ENUM32, .name = "type", .enums = desc_v4l2_tuner_type, .length = sizeof(desc_v4l2_tuner_type) / sizeof(char*), },{ .type = UINT32, .name = "frequency", },{ /* end of list */ }}; struct struct_desc desc_v4l2_audio[] = {{ .type = UINT32, .name = "index", },{ .type = STRING, .name = "name", .length = 32, },{ .type = UINT32, .name = "capability", },{ .type = UINT32, .name = "mode", },{ /* end of list */ }}; struct struct_desc desc_v4l2_audioout[] = {{ .type = UINT32, .name = "index", },{ .type = STRING, .name = "name", .length = 32, },{ .type = UINT32, .name = "capability", },{ .type = UINT32, .name = "mode", },{ /* end of list */ }}; struct struct_desc desc_v4l2_vbi_format[] = {{ .type = UINT32, .name = "sampling_rate", },{ .type = UINT32, .name = "offset", },{ .type = UINT32, .name = "samples_per_line", },{ .type = FOURCC, .name = "sample_format", },{ .type = UINT32, .name = "start[0]", },{ .type = UINT32, .name = "start[1]", },{ .type = UINT32, .name = "count[0]", },{ .type = UINT32, .name = "count[1]", },{ .type = UINT32, .name = "flags", },{ /* end of list */ }}; struct struct_desc desc_v4l2_format[] = {{ .type = ENUM32, .name = "type", .enums = desc_v4l2_buf_type, .length = sizeof(desc_v4l2_buf_type) / sizeof(char*), },{ .type = UNION, .name = "fmt", .u = {{ .value = V4L2_BUF_TYPE_VIDEO_CAPTURE, .name = "pix", .desc = desc_v4l2_pix_format, },{ .value = V4L2_BUF_TYPE_VIDEO_OVERLAY, .name = "win", .desc = desc_v4l2_window, },{ .value = V4L2_BUF_TYPE_VBI_CAPTURE, .name = "vbi", .desc = desc_v4l2_vbi_format, },{ /* end of list */ }}, },{ /* end of list */ }}; struct struct_desc desc_v4l2_streamparm[] = {{ .type = ENUM32, .name = "type", .enums = desc_v4l2_buf_type, .length = sizeof(desc_v4l2_buf_type) / sizeof(char*), },{ /* FIXME ... */ /* end of list */ }}; struct struct_desc desc_v4l2_std_id[] = {{ .type = BITS64, .name = "std", .bits = bits_standard, },{ /* end of list */ }}; /* ---------------------------------------------------------------------- */ struct ioctl_desc ioctls_v4l2[256] = { [_IOC_NR(VIDIOC_QUERYCAP)] = { .name = "VIDIOC_QUERYCAP", .desc = desc_v4l2_capability, }, [_IOC_NR(VIDIOC_ENUM_FMT)] = { .name = "VIDIOC_ENUM_FMT", .desc = desc_v4l2_fmtdesc, }, [_IOC_NR(VIDIOC_G_FMT)] = { .name = "VIDIOC_G_FMT", .desc = desc_v4l2_format, }, [_IOC_NR(VIDIOC_S_FMT)] = { .name = "VIDIOC_S_FMT", .desc = desc_v4l2_format, }, #if 0 [_IOC_NR(VIDIOC_G_COMP)] = { .name = "VIDIOC_G_COMP", .desc = desc_v4l2_compression, }, [_IOC_NR(VIDIOC_S_COMP)] = { .name = "VIDIOC_S_COMP", .desc = desc_v4l2_compression, }, #endif [_IOC_NR(VIDIOC_REQBUFS)] = { .name = "VIDIOC_REQBUFS", .desc = desc_v4l2_requestbuffers, }, [_IOC_NR(VIDIOC_QUERYBUF)] = { .name = "VIDIOC_QUERYBUF", .desc = desc_v4l2_buffer, }, [_IOC_NR(VIDIOC_G_FBUF)] = { .name = "VIDIOC_G_FBUF", .desc = desc_v4l2_framebuffer, }, [_IOC_NR(VIDIOC_S_FBUF)] = { .name = "VIDIOC_S_FBUF", .desc = desc_v4l2_framebuffer, }, [_IOC_NR(VIDIOC_OVERLAY)] = { .name = "VIDIOC_OVERLAY", .desc = desc_int, }, [_IOC_NR(VIDIOC_QBUF)] = { .name = "VIDIOC_QBUF", .desc = desc_v4l2_buffer, }, [_IOC_NR(VIDIOC_DQBUF)] = { .name = "VIDIOC_DQBUF", .desc = desc_v4l2_buffer, }, [_IOC_NR(VIDIOC_STREAMON)] = { .name = "VIDIOC_STREAMON", .desc = desc_int, }, [_IOC_NR(VIDIOC_STREAMOFF)] = { .name = "VIDIOC_STREAMOFF", .desc = desc_int, }, [_IOC_NR(VIDIOC_G_PARM)] = { .name = "VIDIOC_G_PARM", .desc = desc_v4l2_streamparm, }, [_IOC_NR(VIDIOC_S_PARM)] = { .name = "VIDIOC_S_PARM", .desc = desc_v4l2_streamparm, }, [_IOC_NR(VIDIOC_G_STD)] = { .name = "VIDIOC_G_STD", .desc = desc_v4l2_std_id, }, [_IOC_NR(VIDIOC_S_STD)] = { .name = "VIDIOC_S_STD", .desc = desc_v4l2_std_id, }, [_IOC_NR(VIDIOC_ENUMSTD)] = { .name = "VIDIOC_ENUMSTD", .desc = desc_v4l2_standard, }, [_IOC_NR(VIDIOC_ENUMINPUT)] = { .name = "VIDIOC_ENUMINPUT", .desc = desc_v4l2_input, }, [_IOC_NR(VIDIOC_G_CTRL)] = { .name = "VIDIOC_G_CTRL", .desc = desc_v4l2_control, }, [_IOC_NR(VIDIOC_S_CTRL)] = { .name = "VIDIOC_S_CTRL", .desc = desc_v4l2_control, }, [_IOC_NR(VIDIOC_G_TUNER)] = { .name = "VIDIOC_G_TUNER", .desc = desc_v4l2_tuner, }, [_IOC_NR(VIDIOC_S_TUNER)] = { .name = "VIDIOC_S_TUNER", .desc = desc_v4l2_tuner, }, [_IOC_NR(VIDIOC_G_AUDIO)] = { .name = "VIDIOC_G_AUDIO", .desc = desc_v4l2_audio, }, [_IOC_NR(VIDIOC_S_AUDIO)] = { .name = "VIDIOC_S_AUDIO", .desc = desc_v4l2_audio, }, [_IOC_NR(VIDIOC_QUERYCTRL)] = { .name = "VIDIOC_QUERYCTRL", .desc = desc_v4l2_queryctrl, }, [_IOC_NR(VIDIOC_QUERYMENU)] = { .name = "VIDIOC_QUERYMENU", .desc = desc_v4l2_querymenu, }, [_IOC_NR(VIDIOC_G_INPUT)] = { .name = "VIDIOC_G_INPUT", .desc = desc_int, }, [_IOC_NR(VIDIOC_S_INPUT)] = { .name = "VIDIOC_S_INPUT", .desc = desc_int, }, [_IOC_NR(VIDIOC_G_OUTPUT)] = { .name = "VIDIOC_G_OUTPUT", .desc = desc_int, }, [_IOC_NR(VIDIOC_S_OUTPUT)] = { .name = "VIDIOC_S_OUTPUT", .desc = desc_int, }, [_IOC_NR(VIDIOC_ENUMOUTPUT)] = { .name = "VIDIOC_ENUMOUTPUT", .desc = desc_v4l2_output, }, [_IOC_NR(VIDIOC_G_AUDOUT)] = { .name = "VIDIOC_G_AUDOUT", .desc = desc_v4l2_audioout, }, [_IOC_NR(VIDIOC_S_AUDOUT)] = { .name = "VIDIOC_S_AUDOUT", .desc = desc_v4l2_audioout, }, [_IOC_NR(VIDIOC_G_MODULATOR)] = { .name = "VIDIOC_G_MODULATOR", .desc = desc_v4l2_modulator, }, [_IOC_NR(VIDIOC_S_MODULATOR)] = { .name = "VIDIOC_S_MODULATOR", .desc = desc_v4l2_modulator, }, [_IOC_NR(VIDIOC_G_FREQUENCY)] = { .name = "VIDIOC_G_FREQUENCY", .desc = desc_v4l2_frequency, }, [_IOC_NR(VIDIOC_S_FREQUENCY)] = { .name = "VIDIOC_S_FREQUENCY", .desc = desc_v4l2_frequency, }, [_IOC_NR(VIDIOC_CROPCAP)] = { .name = "VIDIOC_CROPCAP", .desc = desc_v4l2_cropcap, }, [_IOC_NR(VIDIOC_G_CROP)] = { .name = "VIDIOC_G_CROP", .desc = desc_v4l2_crop, }, [_IOC_NR(VIDIOC_S_CROP)] = { .name = "VIDIOC_S_CROP", .desc = desc_v4l2_crop, }, [_IOC_NR(VIDIOC_G_JPEGCOMP)] = { .name = "VIDIOC_G_JPEGCOMP", .desc = desc_v4l2_jpegcompression, }, [_IOC_NR(VIDIOC_S_JPEGCOMP)] = { .name = "VIDIOC_S_JPEGCOMP", .desc = desc_v4l2_jpegcompression, }, [_IOC_NR(VIDIOC_QUERYSTD)] = { .name = "VIDIOC_QUERYSTD", .desc = desc_v4l2_std_id, }, [_IOC_NR(VIDIOC_TRY_FMT)] = { .name = "VIDIOC_TRY_FMT", .desc = desc_v4l2_format, }, }; /* ---------------------------------------------------------------------- */ /* * Local variables: * c-basic-offset: 8 * End: */ amsn-0.98.9/utils/linux/capture/structs/struct-v4l.c0000644000175000017500000001761710246003435022246 0ustar billiobbilliob#include #include #include "videodev.h" #include "struct-dump.h" #include "struct-v4l.h" /* ---------------------------------------------------------------------- */ char *bits_vid_cap[32] = { "CAPTURE", "TUNER", "TELETEXT", "OVERLAY", "CHROMAKEY", "CLIPPING", "FRAMERAM", "SCALES", "MONOCHROME", "SUBCAPTURE", "MPEG_DECODER", "MPEG_ENCODER", "MJPEG_DECODER", "MJPEG_ENCODER", }; char *bits_chan_flags[32] = { "TUNER", "AUDIO", }; char *desc_chan_type[] = { [ VIDEO_TYPE_TV ] = "TV", [ VIDEO_TYPE_CAMERA ] = "CAMERA", }; char *bits_tuner_flags[32] = { "PAL", "NTSC", "SECAM", "LOW", "NORM", "?", "?", "STEREO_ON", "RDS_ON", "MBS_ON", }; char *desc_tuner_mode[] = { [ VIDEO_MODE_PAL ] = "PAL", [ VIDEO_MODE_NTSC ] = "NTSC", [ VIDEO_MODE_SECAM ] = "SECAM", [ VIDEO_MODE_AUTO ] = "AUTO", }; char *desc_pict_palette[] = { [ VIDEO_PALETTE_GREY ] = "GREY", [ VIDEO_PALETTE_HI240 ] = "HI240", [ VIDEO_PALETTE_RGB565 ] = "RGB565", [ VIDEO_PALETTE_RGB24 ] = "RGB24", [ VIDEO_PALETTE_RGB32 ] = "RGB32", [ VIDEO_PALETTE_RGB555 ] = "RGB555", [ VIDEO_PALETTE_YUV422 ] = "YUV422", [ VIDEO_PALETTE_YUYV ] = "YUYV", [ VIDEO_PALETTE_UYVY ] = "UYVY", [ VIDEO_PALETTE_YUV420 ] = "YUV420", [ VIDEO_PALETTE_YUV411 ] = "YUV411", [ VIDEO_PALETTE_RAW ] = "RAW", [ VIDEO_PALETTE_YUV422P ] = "YUV422P", [ VIDEO_PALETTE_YUV411P ] = "YUV411P", [ VIDEO_PALETTE_YUV420P ] = "YUV420P", [ VIDEO_PALETTE_YUV410P ] = "YUV410P", }; char *bits_audio_flags[32] = { "MUTE", "MUTABLE", "VOLUME", "BASS", "TREBLE", "BALANCE", }; char *bits_audio_mode[32] = { "MONO", "STEREO", "LANG1", "LANG2", }; /* ---------------------------------------------------------------------- */ struct struct_desc desc_video_capability[] = {{ .type = STRING, .name = "name", .length = 32, },{ .type = BITS32, .name = "type", .bits = bits_vid_cap, },{ .type = SINT32, .name = "channels", },{ .type = SINT32, .name = "audios", },{ .type = SINT32, .name = "maxwidth", },{ .type = SINT32, .name = "maxheight", },{ .type = SINT32, .name = "minwidth", },{ .type = SINT32, .name = "minheight", },{ /* end of list */ }}; struct struct_desc desc_video_channel[] = {{ .type = SINT32, .name = "channel", },{ .type = STRING, .name = "name", .length = 32, },{ .type = SINT32, .name = "tuners", },{ .type = BITS32, .name = "flags", .bits = bits_chan_flags },{ .type = ENUM16, .name = "type", .enums = desc_chan_type, .length = sizeof(desc_chan_type) / sizeof(char*), },{ .type = UINT16, .name = "norm", },{ /* end of list */ }}; struct struct_desc desc_video_tuner[] = {{ .type = SINT32, .name = "tuner", },{ .type = STRING, .name = "name", .length = 32, },{ .type = UINT32, .name = "rangelow", },{ .type = UINT32, .name = "rangehigh", },{ .type = BITS32, .name = "flags", .bits = bits_tuner_flags, },{ .type = ENUM16, .name = "mode", .enums = desc_tuner_mode, .length = sizeof(desc_tuner_mode) / sizeof(char*), },{ .type = UINT16, .name = "signal", },{ /* end of list */ }}; struct struct_desc desc_video_picture[] = {{ .type = UINT16, .name = "brightness", },{ .type = UINT16, .name = "hue", },{ .type = UINT16, .name = "colour", },{ .type = UINT16, .name = "contrast", },{ .type = UINT16, .name = "whiteness", },{ .type = UINT16, .name = "depth", },{ .type = ENUM16, .name = "palette", .enums = desc_pict_palette, .length = sizeof(desc_pict_palette) / sizeof(char*), },{ /* end of list */ }}; struct struct_desc desc_video_audio[] = {{ .type = SINT32, .name = "audio", },{ .type = UINT16, .name = "volume", },{ .type = UINT16, .name = "bass", },{ .type = UINT16, .name = "treble", },{ .type = PADDING, .name = "pad", .length = 2, },{ .type = BITS32, .name = "flags", .bits = bits_audio_flags, },{ .type = STRING, .name = "name", .length = 16, },{ .type = BITS16, .name = "mode", .bits = bits_audio_mode, },{ .type = UINT16, .name = "balance", },{ .type = UINT16, .name = "step", },{ /* end of list */ }}; struct struct_desc desc_video_window[] = {{ .type = UINT32, .name = "x", },{ .type = UINT32, .name = "y", },{ .type = UINT32, .name = "width", },{ .type = UINT32, .name = "height", },{ .type = UINT32, .name = "chromakey", },{ .type = UINT32, .name = "flags", },{ /* end of list */ }}; struct struct_desc desc_video_buffer[] = {{ .type = PTR, .name = "base", },{ .type = SINT32, .name = "height", },{ .type = SINT32, .name = "width", },{ .type = SINT32, .name = "depth", },{ .type = SINT32, .name = "bytesperline", },{ /* end of list */ }}; struct struct_desc desc_video_mmap[] = {{ .type = UINT32, .name = "frame", },{ .type = SINT32, .name = "height", },{ .type = SINT32, .name = "width", },{ .type = UINT32, .name = "format", },{ /* end of list */ }}; struct struct_desc desc_video_mbuf[] = {{ .type = SINT32, .name = "size", },{ .type = SINT32, .name = "frames", },{ .type = SINT32, .name = "offsets", /* FIXME len=32 */ },{ /* end of list */ }}; /* ---------------------------------------------------------------------- */ struct ioctl_desc ioctls_v4l1[256] = { [_IOC_NR(VIDIOCGCAP)] = { .name = "VIDIOCGCAP", .desc = desc_video_capability, }, [_IOC_NR(VIDIOCGCHAN)] = { .name = "VIDIOCGCHAN", .desc = desc_video_channel, }, [_IOC_NR(VIDIOCSCHAN)] = { .name = "VIDIOCSCHAN", .desc = desc_video_channel, }, [_IOC_NR(VIDIOCGTUNER)] = { .name = "VIDIOCGTUNER", .desc = desc_video_tuner, }, [_IOC_NR(VIDIOCSTUNER)] = { .name = "VIDIOCSTUNER", .desc = desc_video_tuner, }, [_IOC_NR(VIDIOCGPICT)] = { .name = "VIDIOCGPICT", .desc = desc_video_picture, }, [_IOC_NR(VIDIOCSPICT)] = { .name = "VIDIOCSPICT", .desc = desc_video_picture, }, [_IOC_NR(VIDIOCCAPTURE)] = { .name = "VIDIOCCAPTURE", .desc = desc_int, }, [_IOC_NR(VIDIOCGWIN)] = { .name = "VIDIOCGWIN", .desc = desc_video_window, }, [_IOC_NR(VIDIOCSWIN)] = { .name = "VIDIOCSWIN", .desc = desc_video_window, }, [_IOC_NR(VIDIOCGFBUF)] = { .name = "VIDIOCGFBUF", .desc = desc_video_buffer, }, [_IOC_NR(VIDIOCSFBUF)] = { .name = "VIDIOCSFBUF", .desc = desc_video_buffer, }, [_IOC_NR(VIDIOCKEY)] = { .name = "VIDIOCKEY", // .desc = desc_video_key, }, [_IOC_NR(VIDIOCGFREQ)] = { .name = "VIDIOCGFREQ", .desc = desc_long, }, [_IOC_NR(VIDIOCSFREQ)] = { .name = "VIDIOCSFREQ", .desc = desc_long, }, [_IOC_NR(VIDIOCGAUDIO)] = { .name = "VIDIOCGAUDIO", .desc = desc_video_audio, }, [_IOC_NR(VIDIOCSAUDIO)] = { .name = "VIDIOCSAUDIO", .desc = desc_video_audio, }, [_IOC_NR(VIDIOCSYNC)] = { .name = "VIDIOCSYNC", .desc = desc_int, }, [_IOC_NR(VIDIOCMCAPTURE)] = { .name = "VIDIOCMCAPTURE", .desc = desc_video_mmap, }, [_IOC_NR(VIDIOCGMBUF)] = { .name = "VIDIOCGMBUF", .desc = desc_video_mbuf, }, [_IOC_NR(VIDIOCGUNIT)] = { .name = "VIDIOCGUNIT", // .desc = desc_video_unit, }, [_IOC_NR(VIDIOCGCAPTURE)] = { .name = "VIDIOCGCAPTURE", // .desc = desc_video_capture, }, [_IOC_NR(VIDIOCSCAPTURE)] = { .name = "VIDIOCSCAPTURE", // .desc = desc_video_capture, }, [_IOC_NR(VIDIOCSPLAYMODE)] = { .name = "VIDIOCSPLAYMODE", // .desc = desc_video_play_mode, }, [_IOC_NR(VIDIOCSWRITEMODE)] = { .name = "VIDIOCSWRITEMODE", .desc = desc_int, }, [_IOC_NR(VIDIOCGPLAYINFO)] = { .name = "VIDIOCGPLAYINFO", // .desc = desc_video_info, }, [_IOC_NR(VIDIOCSMICROCODE)] = { .name = "VIDIOCSMICROCODE", // .desc = desc_video_code, }, [_IOC_NR(VIDIOCGVBIFMT)] = { .name = "VIDIOCGVBIFMT", // .desc = desc_vbi_format, }, [_IOC_NR(VIDIOCSVBIFMT)] = { .name = "VIDIOCSVBIFMT", // .desc = desc_vbi_format, }, }; /* ---------------------------------------------------------------------- */ /* * Local variables: * c-basic-offset: 8 * End: */ amsn-0.98.9/utils/linux/capture/structs/struct-dump.c0000644000175000017500000001276710246003435022507 0ustar billiobbilliob#include #include #include #include #include #include #include "struct-dump.h" #ifndef PRId64 # warning Hmm, your C99 support is incomplete, will guess (should be ok for 32bit archs) # define PRId64 "lld" # define PRIx64 "llx" # define PRIu64 "llu" #endif /* ---------------------------------------------------------------------- */ struct struct_desc desc_int[] = {{ .type = SINT32, .name = "int", },{ /* end of list */ }}; struct struct_desc desc_long[] = {{ .type = SINT32, .name = "long", },{ /* end of list */ }}; struct struct_desc desc_timeval[] = {{ /* FIXME */ /* end of list */ }}; /* ---------------------------------------------------------------------- */ int print_struct(FILE *fp, struct struct_desc *desc, void *data, char *prefix, int tab) { char name[256]; unsigned char *ptr = data; uint64_t u64; int64_t s64; uint32_t u32; int32_t s32; uint16_t u16; int16_t s16; uint8_t u8; int8_t s8; int al = sizeof(long)-1; /* struct + union + 64bit alignment */ void *p; unsigned int i,j,first; for (i = 0; desc[i].name != NULL; i++) { sprintf(name,"%s%s",prefix,desc[i].name); if (STRUCT == desc[i].type) { strcat(name,"."); ptr = (void*)(((intptr_t)ptr + al) & ~al); print_struct(fp,desc[i].desc, ptr, name, tab); ptr += desc[i].length; if (!tab && desc[i+1].name != NULL) fprintf(fp,";"); continue; } if (UNION == desc[i].type) { u32 = *((uint32_t*)(ptr-4)); ptr = (void*)(((intptr_t)ptr + al) & ~al); for (j = 0; desc[i].u[j].name != NULL; j++) if (desc[i].u[j].value == u32) break; if (desc[i].u[j].name != NULL) { strcat(name,"."); strcat(name,desc[i].u[j].name); strcat(name,"."); print_struct(fp,desc[i].u[j].desc, ptr, name, tab); } return 0; /* FIXME */ } if (desc[i].type != PADDING) { if (tab) fprintf(fp,"\t%-24s: ",name); else fprintf(fp,"%s=",name); } switch (desc[i].type) { case STRING: fprintf(fp,"\"%-.*s\"",desc[i].length,ptr); ptr += desc[i].length; break; case PTR: p = *(void**)ptr; fprintf(fp,"%p",p); ptr += sizeof(p); break; case VER: u32 = *((uint32_t*)ptr); fprintf(fp,"%d.%d.%d", (u32 >> 16) & 0xff, (u32 >> 8) & 0xff, u32 & 0xff); ptr += 4; break; case FOURCC: u32 = *((uint32_t*)ptr); fprintf(fp,"0x%08x [%c%c%c%c]", u32, isprint(ptr[0]) ? ptr[0] : '.', isprint(ptr[1]) ? ptr[1] : '.', isprint(ptr[2]) ? ptr[2] : '.', isprint(ptr[3]) ? ptr[3] : '.'); ptr += 4; break; case ENUM16: u16 = *((uint16_t*)ptr); fprintf(fp,"%s", (u16 < desc[i].length && desc[i].enums[u16]) ? desc[i].enums[u16] : "unknown"); ptr += 2; break; case ENUM32: u32 = *((uint32_t*)ptr); fprintf(fp,"%s", (u32 < desc[i].length && desc[i].enums[u32]) ? desc[i].enums[u32] : "unknown"); ptr += 4; break; case BITS16: u16 = *((uint16_t*)ptr); first = 1; fprintf(fp,"0x%x [",u16); for (j = 0; j < 16; j++) { if (0 == (u16 & (1 << j))) continue; fprintf(fp,"%s%s", first ? "" : ",", desc[i].bits[j]); first = 0; } fprintf(fp,"]"); ptr += 2; break; case BITS32: u32 = *((uint32_t*)ptr); first = 1; fprintf(fp,"0x%x [",u32); for (j = 0; j < 32; j++) { if (0 == (u32 & (1 << j))) continue; fprintf(fp,"%s%s", first ? "" : ",", desc[i].bits[j]); first = 0; } fprintf(fp,"]"); ptr += 4; break; case BITS64: ptr = (void*)(((intptr_t)ptr + al) & ~al); u64 = *((uint64_t*)ptr); first = 1; fprintf(fp,"0x%" PRIx64 " [",u64); for (j = 0; j < 64; j++) { if (0 == (u64 & ((int64_t)1 << j))) continue; fprintf(fp,"%s%s", first ? "" : ",", desc[i].bits[j]); first = 0; } fprintf(fp,"]"); ptr += 8; break; case UINT64: ptr = (void*)(((intptr_t)ptr + al) & ~al); u64 = *((uint64_t*)ptr); fprintf(fp,"%" PRIu64,u64); ptr += 8; break; case SINT64: ptr = (void*)(((intptr_t)ptr + al) & ~al); s64 = *((int64_t*)ptr); fprintf(fp,"%" PRId64,s64); ptr += 8; break; case UINT32: u32 = *((uint32_t*)ptr); fprintf(fp,"%u",u32); ptr += 4; break; case SINT32: s32 = *((int32_t*)ptr); fprintf(fp,"%d",s32); ptr += 4; break; case UINT16: u16 = *((uint16_t*)ptr); fprintf(fp,"%u",u16); ptr += 2; break; case SINT16: s16 = *((int16_t*)ptr); fprintf(fp,"%d",s16); ptr += 2; break; case UINT8: u8 = *((uint8_t*)ptr); fprintf(fp,"%u",u8); ptr += 1; break; case SINT8: s8 = *((int8_t*)ptr); fprintf(fp,"%d",s8); ptr += 1; break; case PADDING: ptr += desc[i].length; break; case STRUCT: case UNION: /* shouldn't happen */ fprintf(fp,"FIXME [type=%d]\n",desc[i].type); exit(1); } if (tab) fprintf(fp,"\n"); else if (desc[i+1].name != NULL) fprintf(fp,";"); } return 0; } /* ---------------------------------------------------------------------- */ int print_ioctl(FILE *fp, struct ioctl_desc *ioctls, char *prefix, int cmd, void *ptr) { int index = _IOC_NR(cmd); char *name = ioctls[index].name; struct struct_desc *desc = ioctls[index].desc; fprintf(fp,"%s%s(", prefix, name ? name : "UNKNOWN"); if (desc) { print_struct(fp,desc,ptr,"",0); } else { fprintf(stderr,"%p",ptr); } fprintf(fp,")"); return 0; } /* ---------------------------------------------------------------------- */ /* * Local variables: * c-basic-offset: 8 * End: */ amsn-0.98.9/utils/linux/capture/structs/struct2desc0000644000175000017500000000323110246003435022226 0ustar billiobbilliob#!/usr/bin/perl use strict; my %mapit = ( "int" => "SINT32", "__s32" => "SINT32", "__u32" => "UINT32", "__s16" => "SINT16", "__u16" => "UINT16", "__s8" => "SINT8", "__u8" => "UINT8", ); my $struct = 0; my $enum = 0; while (my $line = <>) { # start of struct if ($line =~ m/^struct\s+(\w+)/) { die "--\n$line\nstruct is 1" if $struct == 1; $struct = 1; print "\n"; print "struct struct_desc desc_$1\[\] = {{\n"; next; } next if ($struct == 1 && $line =~ /^\{/); # end of struct if ($struct == 1 && $line =~ m/^\};/) { $struct = 0; print " .type = END_OF_LIST,\n"; print "}};\n"; next; } # struct elements if ($struct == 1 && $line =~ m/^\s+(int|__u32|__s32|__u16|__s16|__u8|__s8)\s+(\w+);/) { print " .type = $mapit{$1},\n"; print " .name = \"$2\",\n"; print "},{\n"; next; } if ($struct == 1 && $line =~ m/^\s+(char|__u8)\s+(\w+)\[(\d+)\];/) { print " .type = STRING,\n"; print " .name = \"$2\",\n"; print " .length = $3,\n"; print "},{\n"; next; } if ($struct == 1 && $line =~ m/^\s+enum\s+(\w+)\s+(\w+);/) { print " .type = ENUM,\n"; print " .name = \"$2\",\n"; print " .enums = desc_$1,\n"; print "},{\n"; next; } # start of enum if ($line =~ m/^enum\s+(\w+)/) { die "--\n$line\nenum is 1" if $enum == 1; $enum = 1; print "\n"; print "char desc_$1\[\] = {\n"; next; } # end of enum if ($enum == 1 && $line =~ m/^\};/) { $enum = 0; print "};\n"; next; } # enum elements if ($enum == 1 && $line =~ m/^\s+(\w+)/) { print " [$1] = \"$1\",\n"; next; } next if $line =~ m/#define/; next if $struct == 0; chomp $line; print "/* FIXME $line */\n"; } amsn-0.98.9/utils/linux/capture/structs/struct-v4l2.h0000644000175000017500000000403710246003435022325 0ustar billiobbilliobextern char *desc_v4l2_field[]; extern char *desc_v4l2_buf_type[]; extern char *desc_v4l2_ctrl_type[]; extern char *desc_v4l2_tuner_type[]; extern char *desc_v4l2_memory[]; extern char *desc_v4l2_colorspace[]; extern char *bits_capabilities[32]; extern char *bits_standard[64]; extern char *bits_buf_flags[32]; extern char *bits_fbuf_cap[32]; extern char *bits_fbuf_flags[32]; extern char *desc_input_type[32]; extern char *bits_input_status[32]; extern char *bits_tuner_cap[32]; extern char *bits_tuner_rx[32]; extern char *desc_tuner2_mode[]; extern struct struct_desc desc_v4l2_rect[]; extern struct struct_desc desc_v4l2_fract[]; extern struct struct_desc desc_v4l2_capability[]; extern struct struct_desc desc_v4l2_pix_format[]; extern struct struct_desc desc_v4l2_fmtdesc[]; extern struct struct_desc desc_v4l2_timecode[]; extern struct struct_desc desc_v4l2_compression[]; extern struct struct_desc desc_v4l2_jpegcompression[]; extern struct struct_desc desc_v4l2_requestbuffers[]; extern struct struct_desc desc_v4l2_buffer[]; extern struct struct_desc desc_v4l2_framebuffer[]; extern struct struct_desc desc_v4l2_clip[]; extern struct struct_desc desc_v4l2_window[]; extern struct struct_desc desc_v4l2_captureparm[]; extern struct struct_desc desc_v4l2_outputparm[]; extern struct struct_desc desc_v4l2_cropcap[]; extern struct struct_desc desc_v4l2_crop[]; extern struct struct_desc desc_v4l2_standard[]; extern struct struct_desc desc_v4l2_input[]; extern struct struct_desc desc_v4l2_output[]; extern struct struct_desc desc_v4l2_control[]; extern struct struct_desc desc_v4l2_queryctrl[]; extern struct struct_desc desc_v4l2_querymenu[]; extern struct struct_desc desc_v4l2_tuner[]; extern struct struct_desc desc_v4l2_modulator[]; extern struct struct_desc desc_v4l2_frequency[]; extern struct struct_desc desc_v4l2_audio[]; extern struct struct_desc desc_v4l2_audioout[]; extern struct struct_desc desc_v4l2_vbi_format[]; extern struct struct_desc desc_v4l2_format[]; extern struct struct_desc desc_v4l2_streamparm[]; extern struct ioctl_desc ioctls_v4l2[256]; amsn-0.98.9/utils/linux/capture/capture.c0000644000175000017500000007510711162202756020156 0ustar billiobbilliob#include "capture.h" // List management function prototypes static struct list_ptr* Capture_lstGetListItem(char *list_element_id); static struct data_item* Capture_lstAddItem(struct data_item* item); static struct data_item* Capture_lstGetItem(char *list_element_id); static struct data_item* Capture_lstDeleteItem(char *list_element_id); static struct list_ptr* opened_devices = NULL; /* List of TCL commands and their implementation */ static struct { char* command; Tcl_ObjCmdProc *proc; } proc_list[] = { { "::Capture::ListResolutions", Capture_ListResolutions }, { "::Capture::ListDevices", Capture_ListDevices }, { "::Capture::ListChannels", Capture_ListChannels }, { "::Capture::Open", Capture_Open }, { "::Capture::Close", Capture_Close }, { "::Capture::ChangeResolution", Capture_ChangeResolution }, { "::Capture::GetGrabber", Capture_GetGrabber }, { "::Capture::Grab", Capture_Grab }, { "::Capture::SetBrightness", Capture_SetAttribute }, { "::Capture::SetContrast", Capture_SetAttribute }, { "::Capture::SetHue", Capture_SetAttribute }, { "::Capture::SetColour", Capture_SetAttribute }, { "::Capture::GetBrightness", Capture_GetAttribute }, { "::Capture::GetContrast", Capture_GetAttribute }, { "::Capture::GetHue", Capture_GetAttribute }, { "::Capture::GetColour", Capture_GetAttribute }, { "::Capture::IsValid", Capture_IsValid }, { "::Capture::ListGrabbers", Capture_ListGrabbers }, { "::Capture::Debug", Capture_Debug }, { NULL, NULL } // If you like segfaults, remove this! }; /* Listhead structure */ struct list_ptr { struct list_ptr* prev_item; struct list_ptr* next_item; struct data_item* element; }; ///////////////////////////////////// // Functions to manage lists // ///////////////////////////////////// /* Get a pointer to the listhead struct of the item with the specified name */ static struct list_ptr* Capture_lstGetListItem(char *list_element_id) { struct list_ptr* item = g_list; while(item && strcmp(item->element->list_element_id, list_element_id)) item = item->next_item; return item; } /* Add an item to the list */ static struct data_item* Capture_lstAddItem(struct data_item* item) { struct list_ptr* newItem = NULL; if (!item) return NULL; if (Capture_lstGetListItem(item->list_element_id)) return NULL; newItem = (struct list_ptr *) calloc(1, sizeof(struct list_ptr)); if (newItem) { newItem->element = item; newItem->next_item = g_list; if (g_list) { g_list->prev_item = newItem; } g_list = newItem; return newItem->element; } else return NULL; } /* Get the item with the specified name */ static struct data_item* Capture_lstGetItem(char *list_element_id) { struct list_ptr* listitem = Capture_lstGetListItem(list_element_id); if (listitem) return listitem->element; else return NULL; } /* Remove the item with the specified name */ static struct data_item* Capture_lstDeleteItem(char *list_element_id) { struct list_ptr* item = Capture_lstGetListItem(list_element_id); struct data_item* element = NULL; if (item) { element = item->element; if(item->prev_item == NULL) // The first item g_list = item->next_item; else (item->prev_item)->next_item = item->next_item; if (item->next_item) (item->next_item)->prev_item = item->prev_item; free(item); } return element; } ////////////////////////////////////// // Other functions for internal use // ////////////////////////////////////// /* Function for getting a pointer to the video buffer */ static struct ng_video_buf* get_video_buf(void *handle, struct ng_video_fmt *fmt) { return ((struct capture_item*) handle)->rgb_buffer; } /* Select the correct colorspace to use with a device */ static int set_color_conv(struct capture_item* captureItem, struct image_format* image_size) { int i; unsigned int rw, rh; unsigned int w, h; unsigned int d, dmin = (unsigned int) -1; unsigned int bestfmtid; struct ng_video_conv *conv; struct ng_video_fmt gfmt; // Test if captureItem isn't NULL if(NULL == captureItem) return -1; rw = image_size->width; rh = image_size->height; // try native colorspace RGB24 captureItem->fmt.fmtid = VIDEO_RGB24; captureItem->fmt.width = rw; captureItem->fmt.height = rh; if (captureItem->dev.v->setformat(captureItem->dev.handle,&captureItem->fmt) == 0) { w = captureItem->fmt.width; h = captureItem->fmt.height; d = min(w, rw) * min(h, rh); d = w*h + rw*rh - 2*d; if (d == 0) //What do you want more ? return 0; else { if (d < dmin) { bestfmtid = captureItem->fmt.fmtid; dmin = d; } } } // If failed, try native BGR24 (mostly all webcams on LE systems) captureItem->fmt.fmtid = VIDEO_BGR24; captureItem->fmt.width = rw; captureItem->fmt.height = rh; if (captureItem->dev.v->setformat(captureItem->dev.handle,&captureItem->fmt) == 0) { w = captureItem->fmt.width; h = captureItem->fmt.height; d = min(w, rw) * min(h, rh); d = w*h + rw*rh - 2*d; if (d == 0) //What do you want more ? return 0; else { if (d < dmin) { bestfmtid = captureItem->fmt.fmtid; dmin = d; } } } // If it failed, try to find a converter to RGB24 captureItem->fmt.fmtid = VIDEO_RGB24; // check all available conversion functions captureItem->fmt.bytesperline = captureItem->fmt.width * ng_vfmt_to_depth[captureItem->fmt.fmtid] / 8; for (i = 0;;) { // Find a converter to RGB24 if ((conv = ng_conv_find_to(VIDEO_RGB24, &i)) == NULL) break; # ifdef DEBUG fprintf(stderr, "Trying converter from %s to %s\n", ng_vfmt_to_desc[conv->fmtid_in], ng_vfmt_to_desc[conv->fmtid_out]); # endif // Set the new capture format to the colorspace of the input from the converter captureItem->fmt.fmtid = conv->fmtid_in; captureItem->fmt.width = image_size->width; captureItem->fmt.height = image_size->height; captureItem->fmt.bytesperline = 0; // Check if webcam supports the input colorspace of that converter if (captureItem->dev.v->setformat(captureItem->dev.handle,&captureItem->fmt) == 0) { w = captureItem->fmt.width; h = captureItem->fmt.height; d = min(w, rw) * min(h, rh); d = w*h + rw*rh - 2*d; if (d == 0) { //What do you want more ? // Initialize the converter gfmt = captureItem->fmt; captureItem->fmt.fmtid = VIDEO_RGB24; captureItem->fmt.bytesperline = captureItem->fmt.width * ng_vfmt_to_depth[captureItem->fmt.fmtid] / 8; captureItem->handle = ng_conv_init(conv, &gfmt, &captureItem->fmt); return 0; } else { if (d < dmin) { bestfmtid = captureItem->fmt.fmtid; dmin = d; } } } } //If nothing was good we return -1 if (dmin == (unsigned int)-1) return -1; //If we are here, it's because we didn't manage to find a good support for the requested size : we will now use the best fmtid captureItem->fmt.fmtid = bestfmtid; captureItem->fmt.width = rw; captureItem->fmt.height = rh; //I assume it could only return 0 else why would we be here ? captureItem->dev.v->setformat(captureItem->dev.handle,&captureItem->fmt); switch(bestfmtid) { case VIDEO_RGB24: case VIDEO_BGR24: break; default: //I assume conv must be different of 0 else the format couldn't have been enumerated conv = ng_conv_find_match(bestfmtid,VIDEO_RGB24); gfmt = captureItem->fmt; captureItem->fmt.fmtid = VIDEO_RGB24; captureItem->fmt.bytesperline = captureItem->fmt.width * ng_vfmt_to_depth[captureItem->fmt.fmtid] / 8; captureItem->handle = ng_conv_init(conv, &gfmt, &captureItem->fmt); break; } return 0; } ///////////////////////////////////// // Tcl command implementations // ///////////////////////////////////// /* ::Capture::ListResolutions - List supported resolutions */ int Capture_ListResolutions _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { Tcl_Obj * lstResolutions = NULL; struct image_format* image_size = NULL; if (objc != 1) { Tcl_WrongNumArgs(interp, 1, objv, (char *)NULL); return TCL_ERROR; } lstResolutions=Tcl_NewListObj(0, NULL); for(image_size = formats_list; image_size->format_name != NULL; image_size++) { Tcl_ListObjAppendElement(interp,lstResolutions,Tcl_NewStringObj(image_size->format_name,-1)); } Tcl_SetObjResult(interp,lstResolutions); return TCL_OK; } /* ::Capture::ListDevices - List available capture devices */ int Capture_ListDevices _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { struct ng_devinfo * info = NULL; char name[50]; int i = 0; Tcl_HashTable table; int isNew; struct list_head *item; struct ng_vid_driver *drv; Tcl_Obj * device[2] = { NULL, NULL }; Tcl_Obj * lstDevice = NULL; Tcl_Obj * lstAll = NULL; if (objc != 1) { Tcl_WrongNumArgs(interp, 1, objv, (char *)NULL); return TCL_ERROR; } Tcl_InitHashTable(&table,TCL_STRING_KEYS); lstAll=Tcl_NewListObj(0, NULL); /* check all grabber drivers */ list_for_each(item,&ng_vid_drivers) { drv = list_entry(item, struct ng_vid_driver, list); if (ng_debug) fprintf(stderr,"vid-probe: trying: %s... \n", drv->name); info = drv->probe(ng_debug); if (info) { // loop on all found devices for (i = 0; info[i].device[0] != 0; i++) { # ifdef DEBUG fprintf(stderr, "Found %s at %s\n", info[i].name, info[i].device); # endif strcpy(name, drv->name); strcat(name, ": "); strcat(name, info[i].name); Tcl_CreateHashEntry(&table, info[i].device, &isNew); if(isNew) { //The device wasn't listed yet... device[0]=Tcl_NewStringObj(info[i].device,-1); device[1]=Tcl_NewStringObj(name,-1); lstDevice=Tcl_NewListObj(2,device); Tcl_ListObjAppendElement(interp,lstAll,lstDevice); } } } free(info); } Tcl_DeleteHashTable(&table); Tcl_SetObjResult(interp,lstAll); return TCL_OK; } /* ::Capture::ListChannels - List the channels available on a capture device */ int Capture_ListChannels _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { char * device = NULL; int i; struct ng_devstate dev; struct ng_attribute *attr = NULL; Tcl_Obj* channel[2] = {NULL,NULL}; Tcl_Obj* lstChannel = NULL; Tcl_Obj* lstAll = NULL; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "devicename"); return TCL_ERROR; } // Get the device name device = Tcl_GetStringFromObj(objv[1], NULL); // Init the device and let libng find the appropriate driver for it if (0 != ng_vid_init(&dev, device)) { # ifdef DEBUG fprintf(stderr,"no grabber device available\n"); # endif Tcl_SetResult (interp, "no grabber device available\n" , TCL_STATIC); return TCL_ERROR; } // Search for the ATTR_ID_INPUT (channel) ng_attribute struct attr = ng_attr_byid(&dev, ATTR_ID_INPUT); lstAll=Tcl_NewListObj(0, NULL); // Lists the channels const char * devName = NULL; for(i=0; (devName = ng_attr_getstr(attr,i)) != NULL; i++) { channel[0] = Tcl_NewIntObj(i); channel[1] = Tcl_NewStringObj(devName,-1); lstChannel = Tcl_NewListObj(2,channel); Tcl_ListObjAppendElement(interp,lstAll,lstChannel); } ng_dev_fini(&dev); if (attr != NULL) { Tcl_SetObjResult(interp,lstAll); return TCL_OK; } else { Tcl_SetResult (interp, "Error getting channels list\n" , TCL_STATIC); return TCL_ERROR; } } /* ::Capture::GetGrabber - Get the grabber for the specified device and channel */ int Capture_GetGrabber _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { char * dev = NULL; int channel; struct list_ptr* item = opened_devices; // Check number of arguments if(objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "device channel"); return TCL_ERROR; } // Get the device name dev = Tcl_GetStringFromObj(objv[1], NULL); // Get the channel if (Tcl_GetIntFromObj(interp, objv[2], &channel) == TCL_ERROR) { return TCL_ERROR; } // Find the correct grabber while (item) { if ((strcasecmp(dev,item->element->devicePath)==0) && (channel == item->element->channel)) { Tcl_SetResult(interp, item->element->captureName, TCL_VOLATILE); break; } item = item->next_item; } return TCL_OK; } /* ::Capture::ListGrabbers - List all available grabbers */ int Capture_ListGrabbers _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { struct list_ptr* item = opened_devices; Tcl_Obj* grabber[3] = { NULL, NULL, NULL }; Tcl_Obj* lstGrabber = NULL; Tcl_Obj* lstAll = NULL; if (objc != 1) { Tcl_WrongNumArgs(interp, 1, objv, (char *)NULL); return TCL_ERROR; } lstAll = Tcl_NewListObj(0, NULL); while (item) { # ifdef DEBUG fprintf(stderr, "Grabber : %s for device %s and channel %d\n", item->element->captureName, item->element->devicePath, item->element->channel); # endif grabber[0] = Tcl_NewStringObj(item->element->captureName, -1); grabber[1] = Tcl_NewStringObj(item->element->devicePath, -1); grabber[2] = Tcl_NewIntObj(item->element->channel); lstGrabber = Tcl_NewListObj(3, grabber); Tcl_ListObjAppendElement(interp, lstAll, lstGrabber); item = item->next_item; } Tcl_SetObjResult(interp,lstAll); return TCL_OK; } /* ::Capture::Open - Open a capture descriptor */ int Capture_Open _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { static int currentCaptureNumber = 0; char *device = NULL, *tmpRes = NULL; struct ng_attribute *attr = NULL; struct capture_item* captureItem = NULL; struct image_format* image_size = NULL; int channel; // Check the number of arguments if (objc != 4) { Tcl_WrongNumArgs(interp, 1, objv, "device channel resolution"); return TCL_ERROR; } // Get the argument values device = Tcl_GetStringFromObj(objv[1], NULL); if (Tcl_GetIntFromObj(interp, objv[2], &channel) == TCL_ERROR) { return TCL_ERROR; } tmpRes = Tcl_GetStringFromObj(objv[3], NULL); for(image_size = formats_list; image_size->format_name != NULL; image_size++) { if (!strcasecmp(image_size->format_name,tmpRes)) break; } if (image_size->format_name == NULL) { Tcl_SetResult(interp, "The resolution chosen is invalid", TCL_STATIC); return TCL_ERROR; } // Allocate memory for the capture descriptor captureItem = (struct capture_item *) calloc(1, sizeof(struct capture_item)); // Init the device and let libng find the appropriate driver for it if (0 != ng_vid_init(&captureItem->dev, device)) { # ifdef DEBUG fprintf(stderr,"no grabber device available\n"); # endif Tcl_SetResult (interp, "no grabber device available\n" , TCL_STATIC); return TCL_ERROR; } // Check if we can capture from it if (!(captureItem->dev.flags & CAN_CAPTURE)) { # ifdef DEBUG fprintf(stderr,"device doesn't support capture\n"); # endif Tcl_SetResult (interp, "device doesn't support capture\n" , TCL_STATIC); ng_dev_fini(&captureItem->dev); free(captureItem); return TCL_ERROR; } // If we get here, driver initialisation was sucessful // Now open the driver... ng_dev_open(&captureItem->dev); // Search for the ATTR_ID_INPUT (channel) ng_attribute struct attr = ng_attr_byid(&(captureItem->dev), ATTR_ID_INPUT); // Set the channel using ng_attribute->write function if (attr != NULL) { if (channel != -1) attr->write(attr, channel); } // Select the colorspace conversion to use, return an error if none is found (we can't do without!) if (set_color_conv(captureItem,image_size) != 0) { # ifdef DEBUG fprintf(stderr, "Your webcam uses a combination of palette/resolution that this extension does not support yet\n"); # endif Tcl_SetResult (interp, "Your webcam uses a combination of palette/resolution that this extension does not support yet" , TCL_STATIC); ng_dev_close(&captureItem->dev); ng_dev_fini(&captureItem->dev); free(captureItem); return TCL_ERROR; } captureItem->requested_format = image_size; // Add the capture descriptor to the list of open descriptors, return an error if this fails if (Capture_lstAddItem(captureItem) == NULL) { perror("lstAddItem"); ng_dev_close(&captureItem->dev); ng_dev_fini(&captureItem->dev); free(captureItem); return TCL_ERROR; } // Set the name, devicePath and channel properties of the capture descriptor sprintf(captureItem->captureName, "capture%d", currentCaptureNumber++); strcpy(captureItem->devicePath, device); captureItem->channel = channel; // If a converter was used, setup the converter and allocate a new rgb_buffer if (captureItem->handle) { // To setup the converter, you give it a proc and a handle. // The proc is used to return to the converter the output buffer where to store the result... ng_process_setup(captureItem->handle, get_video_buf, (void *)captureItem); captureItem->rgb_buffer = ng_malloc_video_buf(&captureItem->dev, &captureItem->fmt); } captureItem->dev.v->startvideo(captureItem->dev.handle, 25, 1); Tcl_SetResult(interp, captureItem->captureName, TCL_VOLATILE); return TCL_OK; } /* ::Capture::Close - Close a capture descriptor */ int Capture_Close _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { char *captureDescriptor = NULL; struct capture_item *capItem = NULL; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "capturedescriptor"); return TCL_ERROR; } captureDescriptor = Tcl_GetStringFromObj(objv[1], NULL); if ((capItem = Capture_lstGetItem(captureDescriptor)) == NULL) { Tcl_SetResult(interp, "Invalid capture descriptor.", TCL_STATIC); return TCL_ERROR; } capItem->dev.v->stopvideo(capItem->dev.handle); // If a converter was used, close it and release the rgb_buffer if (capItem->handle) { ng_process_fini(capItem->handle); ng_release_video_buf(capItem->rgb_buffer); } // Close the device, and free the device structure ng_dev_close(&capItem->dev); ng_dev_fini(&capItem->dev); Capture_lstDeleteItem(captureDescriptor); free(capItem); return TCL_OK; } /* ::Capture::ChangeResolution - Change the resolution of an opened device */ int Capture_ChangeResolution _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { char *captureDescriptor = NULL, *tmpRes = NULL; struct capture_item *capItem = NULL; struct image_format* image_size = NULL; unsigned int retVal = TCL_OK; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "capturedescriptor resolution"); return TCL_ERROR; } captureDescriptor = Tcl_GetStringFromObj(objv[1], NULL); if ((capItem = Capture_lstGetItem(captureDescriptor)) == NULL) { Tcl_SetResult(interp, "Invalid capture descriptor.", TCL_STATIC); return TCL_ERROR; } tmpRes = Tcl_GetStringFromObj(objv[2], NULL); for(image_size = formats_list; image_size->format_name != NULL; image_size++) { if (!strcasecmp(image_size->format_name,tmpRes)) break; } if (image_size->format_name == NULL) { Tcl_SetResult(interp, "The resolution chosen is invalid", TCL_STATIC); return TCL_ERROR; } if (image_size == capItem->requested_format) { Tcl_SetResult(interp, "The resolution is the same", TCL_STATIC); //Nothing to do return TCL_OK; } capItem->dev.v->stopvideo(capItem->dev.handle); // If a converter was used, close it and release the rgb_buffer if (capItem->handle) { ng_process_fini(capItem->handle); capItem->handle = NULL; ng_release_video_buf(capItem->rgb_buffer); capItem->rgb_buffer = NULL; } // Select the colorspace conversion to use, return an error if none is found (we can't do without!) if (set_color_conv(capItem,image_size) != 0) { # ifdef DEBUG fprintf(stderr, "Your webcam uses a combination of palette/resolution that this extension does not support yet\n"); # endif Tcl_SetResult (interp, "Your webcam uses a combination of palette/resolution that this extension does not support yet" , TCL_STATIC); retVal = TCL_ERROR; //Now we put back the old settings set_color_conv(capItem,capItem->requested_format); } else capItem->requested_format = image_size; // If a converter was used, setup the converter and allocate a new rgb_buffer if (capItem->handle) { // To setup the converter, you give it a proc and a handle. // The proc is used to return to the converter the output buffer where to store the result... ng_process_setup(capItem->handle, get_video_buf, (void *)capItem); capItem->rgb_buffer = ng_malloc_video_buf(&capItem->dev, &capItem->fmt); } capItem->dev.v->startvideo(capItem->dev.handle, 25, 1); return retVal; } /* ::Capture::Grab - Grab a frame */ int Capture_Grab _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { struct capture_item* capItem = NULL; char * captureDescriptor = NULL; char * image_name = NULL; char * tmpRes = NULL; int rw, rh; Tk_PhotoImageBlock block; Tk_PhotoHandle Photo; // Get command arguments and check their validity if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "capturedescriptor image_name"); return TCL_ERROR; } captureDescriptor = Tcl_GetStringFromObj(objv[1], NULL); image_name = Tcl_GetStringFromObj(objv[2], NULL); if ((Photo = Tk_FindPhoto(interp, image_name)) == NULL) { Tcl_SetResult(interp, "The image you specified is not a valid photo image", TCL_STATIC); return TCL_ERROR; } if ((capItem = Capture_lstGetItem(captureDescriptor)) == NULL) { Tcl_SetResult(interp, "Invalid capture descriptor. Please call Open first." , TCL_STATIC); return TCL_ERROR; } if ((capItem->image_data = capItem->dev.v->nextframe(capItem->dev.handle)) == NULL) { # ifdef DEBUG fprintf(stderr,"Capturing image failed at %dx%d\n", capItem->fmt.width, capItem->fmt.height); # endif Tcl_SetResult(interp, "Unable to capture from the device", TCL_STATIC); return TCL_ERROR; } // if a converter was used, put the frame into the converter and get it, once converted if (capItem->handle) { ng_process_put_frame(capItem->handle, capItem->image_data); capItem->rgb_buffer = ng_process_get_frame(capItem->handle); } else { capItem->rgb_buffer = capItem->image_data; } // We're not going to use this pointer any more. // No need to free it however: // - With a converter, libng freed it already. // - Without a converter, we still use it through capItem->rgb_buffer, which we free at the end of this function. capItem->image_data = NULL; // Setup block block.pixelPtr = capItem->rgb_buffer->data; block.width = capItem->rgb_buffer->fmt.width; block.height = capItem->rgb_buffer->fmt.height; block.pitch = block.width * 3; block.pixelSize = 3; block.offset[1] = 1; block.offset[3] = -1; // Check for RGB24 vs. BGR24 if (capItem->fmt.fmtid == VIDEO_RGB24) { block.offset[0] = 0; block.offset[2] = 2; } else { block.offset[0] = 2; block.offset[2] = 0; } Tk_PhotoSetSize( # if TK_MINOR_VERSION >= 5 interp, # endif Photo, capItem->requested_format->width, capItem->requested_format->height); Tk_PhotoBlank(Photo); Tk_PhotoPutBlock( # if TK_MINOR_VERSION >= 5 interp, #endif Photo, &block, 0, 0, block.width, block.height # if TK_MINOR_VERSION >= 4 //Overlay is useless as our image hasn't any alpha channel , TK_PHOTO_COMPOSITE_SET # endif ); Tcl_SetResult(interp, capItem->requested_format->format_name, TCL_VOLATILE); // Make sure to release the rgb_buffer if no converter is used so the next grab will not wait unnecessarily if (!capItem->handle) ng_release_video_buf(capItem->rgb_buffer); return TCL_OK; } /* ::Capture::SetBrightness - Set brightness * ::Capture::SetContrast - Set contrast * ::Capture::SetHue - Set Hue * ::Capture::SetColour - Set colour */ int Capture_SetAttribute _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { struct ng_attribute *attr; char *captureDescriptor = NULL; char *proc = NULL; struct capture_item *capItem = NULL; int new_value = 0; int attribute; int value; // Check number of arguments if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "capture_descriptor new_value"); return TCL_ERROR; } // Depending on the proc, choose the correct attribute to set proc = Tcl_GetStringFromObj(objv[0], NULL); if (!strcmp(proc, "::Capture::SetBrightness")) { attribute = ATTR_ID_BRIGHT; } else if (!strcmp(proc, "::Capture::SetContrast")) { attribute = ATTR_ID_CONTRAST; } else if (!strcmp(proc, "::Capture::SetHue")) { attribute = ATTR_ID_HUE; } else if (!strcmp(proc, "::Capture::SetColour")) { attribute = ATTR_ID_COLOR; } else { Tcl_SetResult(interp, "Wrong procedure name, should be either one of those: \n" \ "::Capture::SetBrightness, ::Capture::SetContrast, ::Capture::SetHue, ::Capture::SetColour\n" , TCL_STATIC); return TCL_ERROR; } // Get the capture descriptor and check its validity captureDescriptor = Tcl_GetStringFromObj(objv[1], NULL); if ((capItem = Capture_lstGetItem(captureDescriptor)) == NULL) { Tcl_SetResult (interp, "Invalid capture descriptor. Please call Open first." , TCL_STATIC); return TCL_ERROR; } // Get new_value and check its validity //2 conditions below modified to silently ignore erroneous value instead of throwing error if (Tcl_GetIntFromObj(interp, objv[2], &new_value) == TCL_ERROR) { return TCL_OK; } // Get the ng_attribute struct from the attribute id attr = ng_attr_byid(&(capItem->dev), attribute); // Set attribute value using attribute->write proc... if (attr != NULL) { if (new_value >= attr->min && new_value <= attr->max) attr->write(attr, new_value); } return TCL_OK; } /* ::Capture::GetBrightness - Get brightness * ::Capture::GetContrast - Get contrast * ::Capture::GetHue - Get Hue * ::Capture::GetColour - Get colour */ int Capture_GetAttribute _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { struct ng_attribute *attr; char *captureDescriptor = NULL; char *proc = NULL; char *bound = NULL; struct capture_item *capItem = NULL; enum { CURRENT = 0, MIN = 1, MAX = 2 } mode = CURRENT; int attribute; int value; // Check number of arguments if (objc != 2 && objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "capture_descriptor ?bound?"); return TCL_ERROR; } // Depending on the proc, choose the correct attribute to get proc = Tcl_GetStringFromObj(objv[0], NULL); if (!strcmp(proc, "::Capture::GetBrightness")) { attribute = ATTR_ID_BRIGHT; } else if (!strcmp(proc, "::Capture::GetContrast")) { attribute = ATTR_ID_CONTRAST; } else if (!strcmp(proc, "::Capture::GetHue")) { attribute = ATTR_ID_HUE; } else if (!strcmp(proc, "::Capture::GetColour")) { attribute = ATTR_ID_COLOR; } else { Tcl_SetResult(interp, "Wrong procedure name, should be either one of those: \n" \ "::Capture::GetBrightness, ::Capture::GetContrast, ::Capture::GetHue, ::Capture::GetColour" , TCL_STATIC); return TCL_ERROR; } if(objc == 3) { bound = Tcl_GetStringFromObj(objv[2], NULL); if (!strcmp(bound, "MAX")) { mode = MAX; } else if (!strcmp(bound, "MIN")) { mode = MIN; } else { Tcl_SetResult(interp, "The bound should be either \"MIN\" or \"MAX\"", TCL_STATIC); return TCL_ERROR; } } // Get the capture descriptor and check its validity captureDescriptor = Tcl_GetStringFromObj(objv[1], NULL); if ((capItem = Capture_lstGetItem(captureDescriptor)) == NULL) { Tcl_SetResult(interp, "Invalid capture descriptor. Please call Open first." , TCL_STATIC); return TCL_ERROR; } // Get attribute value if ((attr = ng_attr_byid(&(capItem->dev), attribute)) != NULL) { switch (mode) { case CURRENT: value = attr->read(attr); break; case MIN: value = attr->min; break; case MAX: value = attr->max; } Tcl_SetObjResult(interp, Tcl_NewIntObj(value)); } else { Tcl_SetObjResult(interp, Tcl_NewIntObj(0)); } return TCL_OK; } /* ::Capture::IsValid - Check the validity of a capture descriptor */ int Capture_IsValid _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { char *captureDescriptor = NULL; // Check the number of arguments if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "capture_descriptor"); return TCL_ERROR; } // Get captureDescriptor and determine if it is valid captureDescriptor = Tcl_GetStringFromObj(objv[1], NULL); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(Capture_lstGetItem(captureDescriptor) != NULL)); return TCL_OK; } /* ::Capture::Debug - Set the ng_debug flag */ int Capture_Debug _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) { // Check the number of arguments if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "flag"); return TCL_ERROR; } return Tcl_GetIntFromObj(interp, objv[1], &ng_debug); } /* Initialisation of the capture extension */ int Capture_Init (Tcl_Interp *interp ) { int i; // Check Tcl version if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) { return TCL_ERROR; } // Check TK version if (Tk_InitStubs(interp, TK_VERSION, 0) == NULL) { return TCL_ERROR; } // Make our commands known to the interpreter for (i = 0; proc_list[i].command != NULL && proc_list[i].proc != NULL; i++) { Tcl_CreateObjCommand(interp, proc_list[i].command, proc_list[i].proc, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); } // Initialise libng # ifdef DEBUG ng_debug = 1; # else ng_debug = 0; # endif ng_init(); // End of Initialisation return TCL_OK; } /* SafeInit dummy. Just points to Init */ int Capture_SafeInit (Tcl_Interp *interp ) { return Capture_Init(interp); } amsn-0.98.9/utils/linux/capture/test.tcl0000755000175000017500000002203510545601655020032 0ustar billiobbilliob#!/usr/bin/wish lappend auto_path [pwd] lappend auto_path "utils/linux/capture/" package require capture #puts "Device list : [::Capture::ListDevices]" #puts "[::Capture::ListChannels /dev/video]" #set grabber [::Capture::Open /dev/video 0] #puts "[::Capture::GetGrabber /dev/video 0]" set devices [::Capture::ListDevices] set ::grabber "" set ::preview "" set ::reslist [::Capture::ListResolutions] set ::res 0 wm protocol . WM_DELETE_WINDOW { if { [::Capture::IsValid $::grabber] } { ::Capture::Close $::grabber } if { [::Capture::IsValid $::preview] } { ::Capture::Close $::preview } exit } set img [image create photo] label .l -image $img button .r -text "Switch resolution" -command "SwitchResolution" button .s -text "Camera Settings" -command "ShowPropertiesPage $::grabber $img" button .c -text "Choose device" -command "ChooseDevice; .s configure -command \"ShowPropertiesPage \$::grabber $img\"; StartGrab \$::grabber $img" pack .l .r .s .c -side top proc SwitchResolution { } { incr ::res if { $::res == [llength $::reslist]} { set ::res 0 } puts "Changing to [lindex $::reslist $::res]" if { [::Capture::IsValid $::preview] } { puts [::Capture::ChangeResolution $::preview [lindex $::reslist $::res]] } if { [::Capture::IsValid $::grabber] } { puts [::Capture::ChangeResolution $::grabber [lindex $::reslist $::res]] } } proc ChooseDevice { } { set window .chooser set lists $window.lists set devs $lists.devices set chans $lists.channels set buttons $window.buttons set status $window.status set preview $window.preview set settings $window.settings destroy $window toplevel $window frame $lists frame $devs -relief sunken -borderwidth 3 label $devs.label -text "Devices" listbox $devs.list -yscrollcommand "$devs.ys set" -background \ white -relief flat -highlightthickness 0 -height 5 scrollbar $devs.ys -command "$devs.list yview" -highlightthickness 0 \ -borderwidth 1 -elementborderwidth 2 pack $devs.label $devs.list -side top -expand false -fill x pack $devs.ys -side right -fill y pack $devs.list -side left -expand true -fill both frame $chans -relief sunken -borderwidth 3 label $chans.label -text "Channels" listbox $chans.list -yscrollcommand "$chans.ys set" -background \ white -relief flat -highlightthickness 0 -height 5 -selectmode extended scrollbar $chans.ys -command "$chans.list yview" -highlightthickness 0 \ -borderwidth 1 -elementborderwidth 2 pack $chans.label $chans.list -side top -expand false -fill x pack $chans.ys -side right -fill y pack $chans.list -side left -expand true -fill both pack $devs $chans -side left label $status -text "Please choose a device" set img [image create photo] label $preview -image $img button $settings -text "Camera Settings" -command "ShowPropertiesPage $::preview $img" frame $buttons -relief sunken -borderwidth 3 button $buttons.ok -text "Ok" -command "Choose_Ok $window $devs.list $chans.list $img" button $buttons.cancel -text "Cancel" -command "destroy $window" wm protocol $window WM_DELETE_WINDOW "Choose_Cancel $window $img" pack $buttons.ok $buttons.cancel -side left pack $lists $status $preview $settings $buttons -side top bind $devs.list "FillChannels $devs.list $chans.list $status" bind $chans.list "StartPreview $devs.list $chans.list $status $preview $settings" foreach device $::devices { set dev [lindex $device 0] set name [lindex $device 1] if {$name == "" } { set name "Device $dev is busy" } $devs.list insert end $name } tkwait window $window } proc FillChannels { device_w chan_w status } { $chan_w delete 0 end if { [$device_w curselection] == "" } { $status configure -text "Please choose a device" return } set dev [$device_w curselection] set device [lindex $::devices $dev] set ::device [lindex $device 0] if { [catch {set channels [::Capture::ListChannels $::device]} res] } { $status configure -text $res return } foreach chan $channels { $chan_w insert end [lindex $chan 1] } $status configure -text "Please choose a Channel" } proc StartPreview { device_w chan_w status preview_w settings } { # if { [$device_w curselection] == "" } { # $status configure -text "Please choose a device" # return # } if { [$chan_w curselection] == "" } { $status configure -text "Please choose a Channel" return } set img [$preview_w cget -image] if {$img == "" } { return } set dev [$device_w curselection] set chan [$chan_w curselection] # set device [lindex $::devices $dev] # set device [lindex $device 0] if { [catch {set channels [::Capture::ListChannels $::device]} res] } { $status configure -text $res return } set channel [lindex $channels $chan] set channel [lindex $channel 0] if { [::Capture::IsValid $::preview] } { ::Capture::Close $::preview } if { [catch {set ::preview [::Capture::Open $::device $channel [lindex $::reslist $::res]]} res] } { $status configure -text $res return } $settings configure -command "ShowPropertiesPage $::preview $img" after 0 "StartGrab $::preview $img" } proc Choose_Ok { w device_w chan_w img} { if { [::Capture::IsValid $::preview] } { ::Capture::Close $::preview } image delete $img # if { [$device_w curselection] == "" } { # destroy $w # return # } if { [$chan_w curselection] == "" } { destroy $w return } set dev [$device_w curselection] set chan [$chan_w curselection] # set device [lindex $::devices $dev] # set device [lindex $device 0] if { [catch {set channels [::Capture::ListChannels $::device]} res] } { destroy $w return } set channel [lindex $channels $chan] set channel [lindex $channel 0] if { [catch {set temp [::Capture::Open $::device $channel [lindex $::reslist $::res]]} res] } { destroy $w return } if { [::Capture::IsValid $::grabber] } { ::Capture::Close $::grabber } set ::grabber $temp if { [winfo exists .properties_$::preview] } { destroy .properties_$::preview } destroy $w } proc Choose_Cancel { w img} { if { [::Capture::IsValid $::preview] } { ::Capture::Close $::preview } image delete $img if { [winfo exists .properties_$::preview] } { destroy .properties_$::preview } destroy $w } proc ShowPropertiesPage { capture_fd {img ""}} { if { ![::Capture::IsValid $capture_fd] } { return } set window .properties_$capture_fd set slides $window.slides set preview $window.preview set buttons $window.buttons set init_b [::Capture::GetBrightness $capture_fd] set init_c [::Capture::GetContrast $capture_fd] set init_h [::Capture::GetHue $capture_fd] set init_co [::Capture::GetColour $capture_fd] destroy $window toplevel $window frame $slides scale $slides.b -from 0 -to 65535 -resolution 1 -showvalue 1 -label "Brightness" -command "Properties_Set $slides.b b $capture_fd" -orient horizontal scale $slides.c -from 0 -to 65535 -resolution 1 -showvalue 1 -label "Contrast" -command "Properties_Set $slides.c c $capture_fd" -orient horizontal scale $slides.h -from 0 -to 65535 -resolution 1 -showvalue 1 -label "Hue" -command "Properties_Set $slides.h h $capture_fd" -orient horizontal scale $slides.co -from 0 -to 65535 -resolution 1 -showvalue 1 -label "Colour" -command "Properties_Set $slides.co co $capture_fd" -orient horizontal pack $slides.b $slides.c $slides.h $slides.co -side top -expand true -fill x frame $buttons -relief sunken -borderwidth 3 button $buttons.ok -text "Ok" -command "destroy $window" button $buttons.cancel -text "Cancel" -command "Properties_Cancel $window $capture_fd $init_b $init_c $init_h $init_co" wm protocol $window WM_DELETE_WINDOW "Properties_Cancel $window $capture_fd $init_b $init_c $init_h $init_co" pack $buttons.ok $buttons.cancel -side left if { $img == "" } { set img [image create photo] } label $preview -image $img after 0 "StartGrab $capture_fd $img" pack $slides $preview $buttons -side top $slides.b set $init_b $slides.c set $init_c $slides.h set $init_h $slides.co set $init_co return $window } proc Properties_Set { w property capture_fd new_value } { switch $property { b { ::Capture::SetBrightness $capture_fd $new_value set val [::Capture::GetBrightness $capture_fd] $w set $val } c { ::Capture::SetContrast $capture_fd $new_value set val [::Capture::GetContrast $capture_fd] $w set $val } h { ::Capture::SetHue $capture_fd $new_value set val [::Capture::GetHue $capture_fd] $w set $val } co { ::Capture::SetColour $capture_fd $new_value set val [::Capture::GetColour $capture_fd] $w set $val } } } proc Properties_Cancel { window capture_fd init_b init_c init_h init_co } { ::Capture::SetBrightness $capture_fd $init_b ::Capture::SetContrast $capture_fd $init_c ::Capture::SetHue $capture_fd $init_h ::Capture::SetColour $capture_fd $init_co destroy $window } proc StartGrab { grabber img } { set semaphore ::sem_$grabber set $semaphore 0 while { [::Capture::IsValid $grabber] && [lsearch [image names] $img] != -1 } { ::Capture::Grab $grabber $img after 10 "incr $semaphore" tkwait variable $semaphore } } amsn-0.98.9/utils/linux/capture/config.h.in0000644000175000017500000000423011550720041020350 0ustar billiobbilliob/* utils/linux/capture/config.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if you have the `dlopen' function. */ #undef HAVE_DLOPEN /* Define to 1 if you have the `fseeko' function. */ #undef HAVE_FSEEKO /* Define to 1 if you have the `ftello' function. */ #undef HAVE_FTELLO /* Define to 1 if you have the `getpt' function. */ #undef HAVE_GETPT /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_VIDEODEV2_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_VIDEODEV_H /* Define to 1 if you have the `memmem' function. */ #undef HAVE_MEMMEM /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the `strcasestr' function. */ #undef HAVE_STRCASESTR /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_VIDEODEV2_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define to 1 if the X Window System is missing or not being used. */ #undef X_DISPLAY_MISSING amsn-0.98.9/utils/linux/capture/Rules.mk0000644000175000017500000000113111755465524017770 0ustar billiobbilliobOBJS-capture := $(capture_dir)/capture.o TARGETS-capture := $(capture_dir)/capture.so $(OBJS-capture): CFLAGS+=-I$(capture_dir) -I$(capture_dir)/libng $(TARGETS-capture): MORE_LIBS=-L$(capture_dir)/libng -lng $(TARGETS-capture): LDFLAGS+=$(foreach rp,$(RPATH),"-Wl,-rpath=$(rp)/$(capture_dir)/libng") $(TARGETS-capture): $(OBJS-capture) | $(capture_dir)/libng/libng.so @$(echo_link_so) @$(link_so) all:: $(TARGETS-capture) check-capture: $(TARGETS-capture) wish $(capture_dir)/test.tcl check:: check-capture clean:: clean-capture clean-capture: rm -f $(OBJS-capture) $(TARGETS-capture) amsn-0.98.9/utils/linux/traydock/0000755000175000017500000000000011757711632016522 5ustar billiobbilliobamsn-0.98.9/utils/linux/traydock/README0000644000175000017500000000354010154074176017377 0ustar billiobbilliob*****INTRO***************** Ok here is the freedesktop dock brought to you in part byyy Angelo Grossini . We are very proud of mister Grossini for donating this nice little dock. Freedesktop means this dock will go in your gnome2 or kde3 notification area. This thing will give you a little icon to control amsn, it will also show a mail icon when you receive new mail, wich you can click on to open your inbox. This is a rushed release so it will probably have problems and stuff, let us know about it. ******INSTALLATION/COMPILATION*********** I fixed it all up and gave it a small configure script to compile. here is how it goes : - First you need to have Tcl/Tk Dev packages installed. - Second you need Imlib Dev packages Installed. Then you run ./configure If it says it can't find the tk/tcl stuff, try using ./configure --with-tcl=/path/to/tcl --with-tk=/path/to/tk once thats all nice and done it will create a Makefile, then we do : make If all goes well you will have a nice little libtray.so file :) This file has to stay in this directory of course ([amsndir]/utils/linux/traydock/) You'll need to enable de KDE3, or Gnome2 system tray applet, or the dock icon won't work. **********HELP IT DOSEN'T WORK****************** If for some wierd reason (dosen't really have to be wierd) nothing wants to configure and maketry doing it manually as follows ( subsitute the right paths for your system): gcc -pipe -c -O -fPIC -DUSE_TCL_STUBS -DUSE_TK_STUBS -DOSS -I/usr/X11R6/include -I/usr/include/tcl8.4 -I/usr/include/tcl8.4/tcl-private/generic -I/usr/include/tcl8.4/tk-private/generic -DTCL_81_API tray.c gcc -pipe -shared tray.o -lc -L/usr/lib -lImlib -ljpeg -ltiff -lungif -lpng -lz -L/usr/X11R6/lib -lSM -lICE -lXext -lX11 -ldl -lpthread -lieee -lm -L/usr/lib -ltclstub8.4 -L/usr/lib -ltkstub8.4 -o libtray.so Well enjoy! Laterz Burger amsn-0.98.9/utils/linux/traydock/pkgIndex.tcl0000644000175000017500000000033610344552773021001 0ustar billiobbilliob# Tcl package index file, version 1.0 if {[package vcompare [info tclversion] 8.4] < 0} return package ifneeded libtray 0.1 "package require Tk; [list load [file join $dir libtray.so] Tray]; package provide libtray 0.1" amsn-0.98.9/utils/linux/traydock/libtray.c0000644000175000017500000004312611527000315020322 0ustar billiobbilliob#include #include #include #include #include #include #include #include #include #include #define XEMBED_MAPPED (1 << 0) #define SYSTEM_TRAY_REQUEST_DOCK 0 #define SYSTEM_TRAY_BEGIN_MESSAGE 1 #define SYSTEM_TRAY_CANCEL_MESSAGE 2 #define IL_LAST(il) \ { \ if (il != NULL){ \ while (il->next != NULL) \ il=(TrayIcon *)il->next; \ } \ } #define IL_FIRST(il) \ { \ if (il != NULL){ \ while (il->prev != NULL) \ il=(TrayIcon *)il->prev; \ } \ } #define IL_APPEND(il,item) \ { \ if (il != NULL) \ { \ IL_LAST(il) \ il->next=(TrayIcon_ *)item; \ item->prev=(TrayIcon_ *)il; \ il=(TrayIcon *)il->next; \ }else{ \ il=item; \ } \ } #define IL_PREPEND(il,item) \ { \ if (il != NULL) \ { \ IL_FIRST(il) \ il->prev=(TrayIcon_ *)item; \ item->next=(TrayIcon_ *)il; \ il=(TrayIcon *)il->prev; \ }else{ \ il=item; \ } \ } typedef struct TrayIcon *TrayIcon_; typedef struct { Tk_Window win; Tk_PhotoHandle pixmap; int w,h; char tooltip[256]; char cmdCallback[768]; int mustUpdate; int width; int height; TrayIcon_ *prev; TrayIcon_ *next; } TrayIcon; static TrayIcon *iconlist=NULL; /* System tray window ID */ static Display *display; //static int msgid=0; Tcl_TimerToken timer=NULL; //static int tooltip=0; Tcl_Interp * globalinterp; static Window _GetSystemTray () { char buffer[256]; Atom a; snprintf (buffer, sizeof (buffer), "_NET_SYSTEM_TRAY_S%d", XScreenNumberOfScreen(Tk_Screen(Tk_MainWindow(globalinterp)))); /* Get the X11 Atom */ a=XInternAtom (display, buffer, False); /* And get the window ID associated to that atom */ return XGetSelectionOwner(display, a); } /* Set embed information */ static void xembed_set_info (Tk_Window window, unsigned long flags) { unsigned long buffer[2]; /* Get flags */ Atom xembed_info_atom = XInternAtom (display,"_XEMBED_INFO",0); buffer[0] = 0; /* Protocol version */ buffer[1] = flags; /* Change the property */ XChangeProperty (display, Tk_WindowId(window), xembed_info_atom, xembed_info_atom, 32, PropModeReplace, (unsigned char *)buffer, 2); } static void send_message (Display* dpy,Window w, Atom type,long message, long data1, long data2, long data3) { XEvent ev; memset(&ev, 0, sizeof(ev)); ev.xclient.type = ClientMessage; ev.xclient.window = w; ev.xclient.message_type = type; ev.xclient.format = 32; ev.xclient.data.l[0] = time(NULL); ev.xclient.data.l[1] = message; ev.xclient.data.l[2] = data1; ev.xclient.data.l[3] = data2; ev.xclient.data.l[4] = data3; //trap_errors(); XSendEvent(dpy, w, False, NoEventMask, &ev); XSync(dpy, False); //if (untrap_errors()) { /* Handle failure */ //printf("Handle failure\n"); //} } /* Procedure that Docks the icon */ static void DockIcon(ClientData clientData) { Window parent; unsigned int ret, atom; TrayIcon *icon= clientData; static const char *tray_name = "amsn-tray"; Tk_MakeWindowExist(icon->win); Tk_SetWindowBackgroundPixmap(icon->win, ParentRelative); xembed_set_info(icon->win,XEMBED_MAPPED); atom = XInternAtom(display, "_NET_SYSTEM_TRAY_OPCODE", False ); send_message(display, _GetSystemTray (), atom, SYSTEM_TRAY_REQUEST_DOCK, Tk_WindowId(icon->win),0,0); XChangeProperty(display, _GetSystemTray (), XInternAtom(display, "_NET_WM_NAME", False), XInternAtom(display, "UTF8_STRING", False), 8, PropModeReplace, (unsigned char *)tray_name, strlen(tray_name)+1); XStoreName(display, _GetSystemTray (), tray_name); XClassHint* classHint = XAllocClassHint(); if(classHint){ classHint->res_name = "amsn-window"; //TODO: Change classHint->res_class = "amsn-wm_class"; // those names? } XSetClassHint(display, Tk_WindowId(icon->win), classHint); XFree(classHint); } /* Draw the icon */ static void DrawIcon (ClientData clientData) { TrayIcon *icon=clientData; int x,y; unsigned int w,h,b,d; int widthImg, heightImg; Window r; char cmdBuffer[1024]; XSizeHints *hints = NULL; long supplied = 0; if( icon->win == NULL ) { return; } XGetGeometry(display, Tk_WindowId(icon->win), &r, &x, &y, &w, &h, &b, &d); XClearWindow(display, Tk_WindowId(icon->win)); /* * Here we get the window hints because in some cases the XGetGeometry * function returns the wrong width/height. We only check that * min_width <= width <= max_width and min_height <= height <= max_height */ hints = XAllocSizeHints(); XGetWMNormalHints(display, Tk_WindowId(icon->win), hints, &supplied); if( supplied & PMaxSize ) { w = (hints->max_width < w) ? hints->max_width : w; h = (hints->max_height < h) ? hints->max_height : h; } if( supplied & PMinSize ) { w = (hints->min_width > w) ? hints->min_width : w; h = (hints->min_height > h) ? hints->min_height : h; } if(hints) { XFree(hints); hints = NULL; } if (((icon->width != w) || (icon->height != h) || (icon->mustUpdate)) && (icon->cmdCallback[0] != '\0')) { snprintf(cmdBuffer,sizeof(cmdBuffer),"%s %u %u",icon->cmdCallback,w,h); Tcl_EvalEx(globalinterp,cmdBuffer,-1,TCL_EVAL_GLOBAL); icon->mustUpdate = False; icon->width = w; icon->height = h; } Tk_SizeOfImage(icon->pixmap, &widthImg, &heightImg); if (widthImg > w) widthImg = w; if (heightImg > h) heightImg = h; if( !Tk_IsMapped(icon->win) ) Tk_MapWindow(icon->win); Tk_RedrawImage(icon->pixmap, 0, 0, widthImg, heightImg, Tk_WindowId(icon->win), (w-widthImg)/2 , (h-heightImg)/2 ); } /*static void show_tooltip (ClientData clientdata) { TrayIcon *icon = (TrayIcon *)clientdata; if (icon->tooltip != NULL) { tooltip=1; // printf ("%s\n",icon->tooltip); } timer=NULL; } static void remove_tooltip (void) { if (tooltip == 1) { tooltip=0; } }*/ /* Callback function when a message arrives */ static int MessageEvent (Tk_Window tkwin, XEvent *eventPtr) { // printf("Message\n"); return 0; } /* Callback function when an event happens */ static void IconEvent (ClientData clientData, register XEvent *eventPtr) { TrayIcon *icon = (TrayIcon *)clientData; if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) { if (icon->win != NULL) /*horrible hack to redraw the icon when dragging the dock aroun the panels*/ Tcl_DoWhenIdle (DrawIcon, icon); goto redraw; } else if (eventPtr->type == ConfigureNotify || eventPtr->type == ResizeRequest) { icon->mustUpdate=True; goto redraw; } /*else if (eventPtr->type == EnterNotify) { if (timer == NULL) { timer = Tcl_CreateTimerHandler(500, show_tooltip, icon); } } else if (eventPtr->type == LeaveNotify) { if (tooltip==1) remove_tooltip(); if (timer != NULL) { Tcl_DeleteTimerHandler(timer); timer=NULL; } }*/ return; redraw: if ((icon->win != NULL)) { Tcl_DoWhenIdle(DrawIcon, (ClientData) icon); } } static void ImageChangedProc (ClientData clientData, int x, int y, int width, int height, int imageWidth, int imageHeight) { TrayIcon *icon = (TrayIcon *)clientData; icon->mustUpdate=True; Tcl_DoWhenIdle(DrawIcon, clientData); } /* New tray icon procedure (newti command) */ static int Tk_TrayIconNew (ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int n,found; char *arg,*pixmap=NULL; int length; Tk_Window mainw; unsigned int mask; TrayIcon *icon; XSizeHints *hint; char cmdBuffer[1024]; /* systemtray was not available in Init */ if (_GetSystemTray () == 0) { Tcl_AppendResult (interp, "cannot create a tray icon without a system tray", (char *) NULL); return TCL_ERROR; } /* Get memory for trayicon data and zero it*/ icon = (TrayIcon *) malloc(sizeof(TrayIcon)); memset((void *) icon, 0, (sizeof(TrayIcon))); icon->next = icon->prev=NULL; mainw=Tk_MainWindow(interp); /* Get the first argument string (object name) and check it */ arg=Tcl_GetStringFromObj(objv[1],(int *) &length); //printf("Arg: %s\n",arg); if (arg == NULL || length < 1 || strncmp(arg, ".", 1)) { Tcl_AppendResult (interp, "bad path name: ", arg , (char *) NULL); return TCL_ERROR; } /* Search in the list if that trayicon window name already exists */ //printf ("Searching for %s!!\n",arg); found=0; if (iconlist != NULL) { IL_FIRST(iconlist) while (1) { //printf ("Comparing with %s!!\n",Tk_PathName(iconlist->win)); if (!strcmp(Tk_PathName(iconlist->win),arg)) { found=1; break; } if (iconlist->next==NULL) break; iconlist=(TrayIcon *)iconlist->next; } if (found == 1) { Tcl_AppendResult (interp, "tray icon ",arg , " already exist", (char *) NULL); //printf ("Already exists error!!\n"); return TCL_ERROR; } } /* Parse options */ for (n=2;ntooltip,Tcl_GetStringFromObj(objv[n],(int *) &length)); } else if (!strncmp(arg,"-command",length)) { /* Copy command string */ n++; strcpy (icon->cmdCallback,Tcl_GetStringFromObj(objv[n],(int *) &length)); } else { Tcl_AppendResult (interp, "unknown ", arg, " option", (char *) NULL); return TCL_ERROR; } } else { Tcl_AppendResult (interp, "unknown ", arg, " option", (char *) NULL); return TCL_ERROR; } } /* If there's a pixmap file, load it */ if (pixmap != NULL) { /* Create the window */ icon->win=Tk_CreateWindowFromPath(interp,mainw, Tcl_GetStringFromObj(objv[1],(int *) &length),NULL); DockIcon((ClientData)icon); Tk_GeometryRequest( icon->win, 24, 24); icon->pixmap=Tk_GetImage(interp,icon->win,pixmap,ImageChangedProc, (ClientData)icon); /* Create callback function for event handling */ mask = StructureNotifyMask | ExposureMask | EnterWindowMask | LeaveWindowMask | PropertyChangeMask; Tk_CreateEventHandler(icon->win, mask, IconEvent, (ClientData) icon); Tk_CreateClientMessageHandler(MessageEvent); /* Set default icon size hint */ hint = XAllocSizeHints(); hint->flags |=PMinSize|PMaxSize; hint->min_width=24; hint->max_width=64; hint->min_height=24; hint->max_height=64; XSetWMNormalHints(display,Tk_WindowId(icon->win),hint); XFree(hint); snprintf(cmdBuffer,sizeof(cmdBuffer),"%s %u %u",icon->cmdCallback,24,24); if (Tcl_EvalEx(globalinterp,cmdBuffer,-1,TCL_EVAL_GLOBAL) == TCL_ERROR) return TCL_ERROR; }else{ Tcl_AppendResult (interp, "you must provide a pixmap file", (char *) NULL); return TCL_ERROR; } /* Append icon to the icon list */ IL_APPEND(iconlist,icon) /* Set result string and return OK */ Tcl_SetResult(interp, Tk_PathName(icon->win), TCL_STATIC); return TCL_OK; } /* configureti command */ static int Tk_ConfigureIcon (ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int n,found; char *arg,*pixmap=NULL; int length; /* Check path name */ arg=Tcl_GetStringFromObj(objv[1],(int *) &length); if (strncmp(arg,".",1)) { Tcl_AppendResult (interp, "bad path name: ",Tcl_GetStringFromObj(objv[1],(int *) &length) , (char *) NULL); return TCL_ERROR; } if (objc < 2) { Tcl_AppendResult (interp, "what do you want to configure?" , (char *) NULL); return TCL_ERROR; } /* Find icon in the list */ found=0; if (iconlist == NULL) { Tcl_AppendResult (interp, "create a tray icon first" , (char *) NULL); return TCL_ERROR; } IL_FIRST(iconlist) while (1) { if (!strcmp(Tk_PathName(iconlist->win),arg)) { found=1; break; } if (iconlist->next==NULL) break; iconlist=(TrayIcon *)iconlist->next; } if (found == 0) { Tcl_AppendResult (interp, "tray icon not found: ",arg , (char *) NULL); return TCL_ERROR; } /* Parse arguments */ for (n=2;ntooltip,Tcl_GetStringFromObj(objv[n],(int *) &length), 255); } else if (!strncmp(arg,"-command",length)) { n++; strcpy(iconlist->cmdCallback,Tcl_GetStringFromObj(objv[n],(int *) &length)); } else { Tcl_AppendResult (interp, "unknown ", arg, " option", (char *) NULL); return TCL_ERROR; } }else{ Tcl_AppendResult (interp, "unknown ", arg, " option", (char *) NULL); return TCL_ERROR; } } if (pixmap != NULL) { Tk_FreeImage(iconlist->pixmap); iconlist->pixmap=Tk_GetImage(interp,iconlist->win,pixmap,ImageChangedProc, (ClientData)iconlist); Tcl_DoWhenIdle(DrawIcon, (ClientData) iconlist); } return TCL_OK; } /*static int Tk_TrayIconBalloon (ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int found; char *arg=NULL; int length; arg=Tcl_GetStringFromObj(objv[1],(int *) &length); if (strncmp(arg,".",1)) { Tcl_AppendResult (interp, "bad path name: ",Tcl_GetStringFromObj(objv[1],(int *) &length) , (char *) NULL); return TCL_ERROR; } if (objc < 2) { Tcl_AppendResult (interp, "please give me a balloon message" , (char *) NULL); return TCL_ERROR; } found=0; if (iconlist == NULL) { Tcl_AppendResult (interp, "create a tray icon first" , (char *) NULL); return TCL_ERROR; } IL_FIRST(iconlist) while (1) { if (!strcmp(Tk_PathName(iconlist->win),arg)) { found=1; break; } if (iconlist->next==NULL) break; iconlist=(TrayIcon *)iconlist->next; } if (found == 0) { Tcl_AppendResult (interp, "tray icon not found: ",arg , (char *) NULL); return TCL_ERROR; } msgid++; arg = Tcl_GetStringFromObj(objv[2],(int *) &length); length--; send_message(display,systemtray,XInternAtom (display, "_NET_SYSTEM_TRAY_OPCODE", False ), SYSTEM_TRAY_BEGIN_MESSAGE,0,length,msgid); while (length > 0) { XClientMessageEvent ev; ev.type = ClientMessage; ev.window = Tk_WindowId(iconlist->win); ev.format = 8; ev.message_type = XInternAtom (display, "_NET_SYSTEM_TRAY_MESSAGE_DATA", False); if (length > 20) { memcpy (&ev.data, arg, 20); length -= 20; arg += 20; } else { memcpy (&ev.data, arg, length); length = 0; } XSendEvent (display, systemtray, False, NoEventMask, (XEvent *)&ev); XSync (display, False); } return TCL_OK; }*/ /* Removes the icon from the dock area */ static int Tk_RemoveIcon (ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int found; char *arg=NULL; int length; TrayIcon *tmp=NULL; /* Check path */ arg=Tcl_GetStringFromObj(objv[1],(int *) &length); if (strncmp(arg,".",1)) { Tcl_AppendResult (interp, "bad path name: ",Tcl_GetStringFromObj(objv[1],(int *) &length) , (char *) NULL); return TCL_ERROR; } /* Find icon in the list */ found=0; if (iconlist == NULL) { Tcl_AppendResult (interp, "create a tray icon first" , (char *) NULL); return TCL_ERROR; } IL_FIRST(iconlist) while (1) { if (!strcmp(Tk_PathName(iconlist->win),arg)) { found=1; break; } if (iconlist->next==NULL) break; iconlist=(TrayIcon *)iconlist->next; } if (found == 0) { Tcl_AppendResult (interp, "tray icon not found: ",arg , (char *) NULL); return TCL_OK; } Tk_FreeImage(iconlist->pixmap); iconlist->pixmap = NULL; Tk_DestroyWindow(iconlist->win); iconlist->win = NULL; Tcl_CancelIdleCall (DrawIcon, iconlist); /* Remove it from the list */ if (iconlist->next == NULL && iconlist->prev == NULL) { free(iconlist); iconlist=NULL; } else if (iconlist->next==NULL) { tmp = (TrayIcon *)iconlist->prev; tmp->next=NULL; iconlist->prev=iconlist->next=NULL; free(iconlist); iconlist=tmp; } else if (iconlist->prev==NULL) { tmp = (TrayIcon *)iconlist->next; tmp->prev=NULL; iconlist->prev=iconlist->next=NULL; free(iconlist); iconlist=tmp; } else { tmp = (TrayIcon *) iconlist->prev; tmp->next = iconlist->next; ((TrayIcon *)tmp->next)->prev=(TrayIcon_ *)tmp; iconlist->prev=iconlist->next=NULL; free(iconlist); iconlist=tmp; } return TCL_OK; } static int Tk_SystemTrayAvailable (ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { Tcl_Obj *result; if (_GetSystemTray () >0) result=Tcl_NewIntObj(1); else result=Tcl_NewIntObj(-1); Tcl_SetObjResult(interp, result); return TCL_OK; } /* Initialization procedure, called when loading the shared library */ int Tray_Init (Tcl_Interp *interp) { Tk_Window mainwin; globalinterp = interp; //Check TK version is 8.0 or higher if (Tk_InitStubs(interp, "8.0", 0) == NULL) { return TCL_ERROR; } //Get main window, and display display = Tk_Display(Tk_MainWindow(interp)); /* Create the new trayicon commands */ Tcl_CreateObjCommand(interp, "newti", Tk_TrayIconNew, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "configureti", Tk_ConfigureIcon, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "removeti", Tk_RemoveIcon, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "systemtray_exist", Tk_SystemTrayAvailable, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); /* Tcl_CreateObjCommand(interp, "tiballoon", Tk_TrayIconBalloon, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);*/ return TCL_OK; } amsn-0.98.9/utils/linux/traydock/Rules.mk0000644000175000017500000000026411755433160020142 0ustar billiobbilliobOBJS-tray := $(tray_dir)/libtray.o TARGETS-tray := $(tray_dir)/libtray.so $(TARGETS-tray): MORE_LIBS=${X_LIBS} all:: $(TARGETS-tray) clean:: rm -f $(TARGETS-tray) $(OBJS-tray) amsn-0.98.9/utils/linux/linflash/0000755000175000017500000000000011757711631016501 5ustar billiobbilliobamsn-0.98.9/utils/linux/linflash/flash.c0000644000175000017500000001706411755535346017757 0ustar billiobbilliob/* File : flash.cpp Description : Contains all functions for the Tk extension of flash windows This is an extension for Tk only for windows, it will make the window flash in the taskbar until it gets focus. MAN : NAME : winflash - Flashes the window taskbar and caption of a toplevel widget SYNOPSYS : winflash window_name DESCRIPTION : This command will make the taskbar of a toplevel window and it's caption flash under linux, the window_name argument must be the tk pathname of a toplevel widget (.window for example) Author : Youness El Alaoui (KaKaRoTo - kakaroto@users.sourceforge.net) Sander Hoentjen (Tjikkun) */ // Include the header file #include "flash.h" /* Function : Tk_FlashWindow Description : This is the function that does the whole job, it will flash the window as given in it's argument Arguments : ClienData clientdata : who knows what's that used for :P anways, it's set to NULL and it's not used Tcl_Interp *interp : This is the interpreter that called this function it will be used to get some info about the window used int objc : This is the number of arguments given to the function Tcl_Obj *CONST objv[] : This is the array that contains all arguments given to the function Return value : TCL_OK in case everything is ok, or TCL_ERROR in case there is an error Comments : http://standards.freedesktop.org/wm-spec/1.4/ar01s05.html#id2527339 */ int Tk_FlashWindow (ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { // We verify the arguments, we must have one arg, not more if( objc != 2) { Tcl_AppendResult (interp, "Wrong number of args.\nShould be \"linflash window_name\"" , (char *) NULL); return TCL_ERROR; } return flash_window(interp, objv[1], 1); } int Tk_UnFlashWindow (ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { // We verify the arguments, we must have one arg, not more if( objc != 2) { Tcl_AppendResult (interp, "Wrong number of args.\nShould be \"linunflash window_name\"" , (char *) NULL); return TCL_ERROR; } return flash_window(interp, objv[1], 0); } int flash_window (Tcl_Interp *interp, Tcl_Obj *CONST objv1, int flash) { // We declare our variables, we need one for every intermediate token we get, // so we can verify if one of the function calls returned NULL char * win = NULL; Tk_Window tkwin; Window window; Display * xdisplay; Window root, parent, *children; unsigned int n; unsigned int demandsSuccess = 0; // Get the first argument string (object name) and check it win = Tcl_GetStringFromObj(objv1, NULL); // We check if the pathname is valid, this means it must beguin with a "." // the strncmp(win, ".", 1) is used to compare the first char of the pathname if (strncmp(win,".",1)) { Tcl_AppendResult (interp, "Bad window path name : ", Tcl_GetStringFromObj(objv1, NULL) , (char *) NULL); return TCL_ERROR; } // Here we ge the long pathname (tk window name), from the short pathname, using the MainWindow from the interpreter tkwin = Tk_NameToWindow(interp, win, Tk_MainWindow(interp)); // Error check if ( tkwin == NULL) return TCL_ERROR; // We then get the windowId (the X token) of the window, from it's long pathname window = Tk_WindowId(tkwin); // Error check if ( window == NULL ) { Tcl_AppendResult (interp, "error while processing WindowId : Window probably not viewable", (char *) NULL); return TCL_ERROR; } xdisplay = Tk_Display(tkwin); /* We get the window id of the root toplevel window */ XQueryTree(xdisplay, window, &root, &parent, &children, &n); XFree(children); //Since under *nix Tk wraps all windows in another one to put a menu bar, we must use the parent window ID which is the top one demandsSuccess = demands_attention(xdisplay, root, parent, flash); // If we disable flash, we make sure the UrencyHint is really disabled // If either the WM doesn't support DEMANDS_ATTENTION or setting it failed, we use the Urgency flag if (!demandsSuccess || !flash) { setUrgencyHint(xdisplay, parent, flash); } //We return error to make the title change for really shitty/special WMs that don't support DEMANDS_ATTENTION //We can't get a reliable way to determine if Urgency failed so even if it was success we ensure that application will use a fallback return (demandsSuccess?TCL_OK:TCL_ERROR); } int demands_attention(Display *display, Window root, Window window, int flash) { static Atom demandsAttention, wmState, wmSupported; Atom type_return; Atom *curr_atom = NULL; int format_return; unsigned long nitems_return; unsigned long bytes_after_return; unsigned char *prop_return = NULL; int hasFlag = 0; XEvent e; memset(&e, 0, sizeof(e)); // We need Atom-s created only once, they don't change during runtime demandsAttention = XInternAtom(display, "_NET_WM_STATE_DEMANDS_ATTENTION", True); wmState = XInternAtom(display, "_NET_WM_STATE", True); wmSupported = XInternAtom(display, "_NET_SUPPORTED", True); if (demandsAttention == None || wmState == None || wmSupported == None) return 0; if( XGetWindowProperty( display, root, wmSupported, 0, 4096, False, XA_ATOM, &type_return, &format_return, &nitems_return, &bytes_after_return, &prop_return ) == Success && nitems_return ) { for( curr_atom = (Atom *)prop_return; nitems_return > 0; nitems_return--, curr_atom++) { if ( *curr_atom == demandsAttention) { hasFlag = 1; break; } } XFree( prop_return ); } e.xclient.type = ClientMessage; e.xclient.message_type = wmState; e.xclient.window = window; e.xclient.display = display; e.xclient.format = 32; e.xclient.data.l[0] = flash; e.xclient.data.l[1] = demandsAttention; e.xclient.data.l[2] = 0l; e.xclient.data.l[3] = 0l; e.xclient.data.l[4] = 0l; /* If the WM doesn't support the DEMANDS_ATTENTION, then we still send the event because some * WMs (like xfce) support it but they tell us they don't. And we return TCL_ERROR just to make sure * in case it *really* didn't support it, that the calling application does the fallback action. */ hasFlag = XSendEvent(display, root, False, (SubstructureRedirectMask | SubstructureNotifyMask), &e) && hasFlag; return hasFlag; } int setUrgencyHint(Display *display, Window window, int flash) { XWMHints *hints; hints = XGetWMHints(display, window); if (hints != NULL) { if (flash) hints->flags |= XUrgencyHint; else hints->flags &= ~XUrgencyHint; XSetWMHints(display, window, hints); XFree(hints); return 1; } return 0; } /* Function : Flash_Init Description : The Init function that will be called when the extension is loaded to your tk shell Arguments : Tcl_Interp *interp : This is the interpreter from which the load was made and to which we'll add the new command Return value : TCL_OK in case everything is ok, or TCL_ERROR in case there is an error (Tk version < 8.3) Comments : hummmm... not much, it's simple :) */ int Flash_Init (Tcl_Interp *interp ) { //Check TK version is 8.0 or higher if (Tk_InitStubs(interp, "8.3", 0) == NULL) { return TCL_ERROR; } // Create the new commands Tcl_CreateObjCommand(interp, "linflash", Tk_FlashWindow, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, "linunflash", Tk_UnFlashWindow, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); // end return TCL_OK; } amsn-0.98.9/utils/linux/linflash/pkgIndex.tcl0000644000175000017500000000033710410473515020750 0ustar billiobbilliob# Tcl package index file, version 1.0 if {[package vcompare [info tclversion] 8.4] < 0} return package ifneeded linflash 0.1 "package require Tk; [list load [file join $dir flash.so] flash]; package provide linflash 0.1" amsn-0.98.9/utils/linux/linflash/flash.h0000644000175000017500000000266310733772533017757 0ustar billiobbilliob/* File : flash.h Description : Header file for the flash window extension for tk Author : Youness El Alaoui ( KaKaRoTo - kakaroto@user.sourceforge.net) */ #ifndef _FLASH #define _FLASH // Include files, must include windows.h before tk.h and tcl.h before tk.h #include #include #include #include #include #include #include #include #include // Defined as described in tcl.tk compiling extension help #ifndef STATIC_BUILD #if defined(_MSC_VER) # define EXPORT(a,b) __declspec(dllexport) a b # define DllEntryPoint DllMain #else # if defined(__BORLANDC__) # define EXPORT(a,b) a _export b # else # define EXPORT(a,b) a b # endif #endif #endif #define DLL_BUILD #define BUILD_Flash #ifdef BUILD_Flash # undef TCL_STORAGE_CLASS # define TCL_STORAGE_CLASS DLLEXPORT #endif #ifdef __cplusplus extern "C" #endif // Prototype of my functions EXTERN int Flash_Init _ANSI_ARGS_((Tcl_Interp *interp)); EXTERN int Tk_FlashWindow (ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); EXTERN int Tk_UnFlashWindow (ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); EXTERN int flash_window (Tcl_Interp *interp, Tcl_Obj *CONST objv1, int flash); # undef TCL_STORAGE_CLASS # define TCL_STORAGE_CLASS DLLIMPORT #endif /* _FLASH */ amsn-0.98.9/utils/linux/linflash/Rules.mk0000644000175000017500000000036311755433160020122 0ustar billiobbilliobOBJS-linflash := $(linflash_dir)/flash.o TARGETS-linflash := $(linflash_dir)/flash.so $(TARGETS-linflash): MORE_LIBS=${X_LIBS} all:: $(TARGETS-linflash) clean:: clean-linflash clean-linflash:: rm -f $(TARGETS-linflash) $(OBJS-linflash) amsn-0.98.9/utils/asyncresolver/0000755000175000017500000000000011757711723016443 5ustar billiobbilliobamsn-0.98.9/utils/asyncresolver/ASYNCRESOLVER.dsw0000644000175000017500000000104711261753053021213 0ustar billiobbilliobMicrosoft Developer Studio Workspace File, Format Version 6.00 # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! ############################################################################### Project: "ASYNCRESOLVER"=".\ASYNCRESOLVER.dsp" - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Global: Package=<5> {{{ }}} Package=<3> {{{ }}} ############################################################################### amsn-0.98.9/utils/asyncresolver/pkgIndex.tcl0000644000175000017500000000016011047063772020711 0ustar billiobbilliobpackage ifneeded asyncresolver 0.1 \ "[list set dir $dir]; [list source [file join $dir asyncresolver.tcl]]" amsn-0.98.9/utils/asyncresolver/src/0000755000175000017500000000000011757711631017230 5ustar billiobbilliobamsn-0.98.9/utils/asyncresolver/src/asyncresolver.c0000644000175000017500000001411411265433634022272 0ustar billiobbilliob/* * hello.c -- A minimal Tcl C extension. */ #include #include #include #ifdef _WIN32 #include #include #include #define inet_ntop inet_ntop_win32 #else #include #include #include #include #endif #ifdef _WIN32 static const char *inet_ntop_win32(int af, const void *src, char *dst, socklen_t cnt) { if (af == AF_INET) { struct sockaddr_in in; memset(&in, 0, sizeof(in)); in.sin_family = AF_INET; memcpy(&in.sin_addr, src, sizeof(struct in_addr)); getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST); return dst; } return NULL; } #endif #ifdef _WIN32 static unsigned __stdcall #else static void #endif Resolver_Thread _ANSI_ARGS_((ClientData cdata)); static int Resolver_EventProc (Tcl_Event *evPtr, int flags); typedef struct { char *host; char *ip; Tcl_Interp *callback_interp; Tcl_Obj *callback; Tcl_ThreadId main_tid; } ResolverData; typedef struct { Tcl_Event header; ResolverData *data; } ResolverEvent; static void notify_callback(char *ip, Tcl_Interp *callback_interp, Tcl_Obj *callback) { Tcl_Obj *ip_obj = Tcl_NewStringObj (ip, -1); Tcl_Obj *eval = Tcl_NewStringObj ("eval", -1); Tcl_Obj *command[] = {eval, callback, ip_obj}; if (callback && callback_interp) { Tcl_IncrRefCount (eval); Tcl_IncrRefCount (ip_obj); if (Tcl_EvalObjv(callback_interp, 3, command, TCL_EVAL_GLOBAL) == TCL_ERROR) { Tcl_BackgroundError(callback_interp); } Tcl_DecrRefCount (ip_obj); Tcl_DecrRefCount (eval); } } static int Asyncresolve_Cmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[]) { ResolverData *data = NULL; Tcl_ThreadId tid; if (objc != 3) { Tcl_WrongNumArgs (interp, 1, objv, "callback host"); return TCL_ERROR; } data = (ResolverData *) ckalloc(sizeof(ResolverData)); data->callback = objv[1]; Tcl_IncrRefCount (data->callback); data->callback_interp = interp; data->main_tid = Tcl_GetCurrentThread(); data->host = strdup(Tcl_GetString(objv[2])); data->ip = strdup(""); if (Tcl_CreateThread(&tid, Resolver_Thread, data, TCL_THREAD_STACK_DEFAULT, TCL_THREAD_NOFLAGS) != TCL_OK) { notify_callback(data->host, data->callback_interp, data->callback); free(data->ip); free(data->host); Tcl_DecrRefCount (data->callback); ckfree(data); } return TCL_OK; } #ifdef _WIN32 static unsigned __stdcall #else static void #endif Resolver_Thread _ANSI_ARGS_((ClientData cdata)) { ResolverData *data = (ResolverData*) cdata; ResolverEvent *evPtr; struct addrinfo * result; char * ret; char ip[INET_ADDRSTRLEN]; int error; error = getaddrinfo(data->host, NULL, NULL, &result); if (error == 0 && result != NULL) { ret = inet_ntop (AF_INET, &((struct sockaddr_in *) result->ai_addr)->sin_addr, ip, INET_ADDRSTRLEN); if (ret != NULL) { free(data->ip); data->ip = strdup(ip); } freeaddrinfo(result); } evPtr = (ResolverEvent *)ckalloc(sizeof(ResolverEvent)); evPtr->header.proc = Resolver_EventProc; evPtr->header.nextPtr = NULL; evPtr->data = data; Tcl_ThreadQueueEvent(data->main_tid, (Tcl_Event *)evPtr, TCL_QUEUE_TAIL); Tcl_ThreadAlert(data->main_tid); #ifdef _WIN32 return 0; #endif } static int Resolver_EventProc (Tcl_Event *evPtr, int flags) { ResolverEvent *ev = (ResolverEvent*) evPtr; ResolverData *data = (ResolverData*) ev->data; notify_callback(data->ip, data->callback_interp, data->callback); free(data->ip); free(data->host); Tcl_DecrRefCount (data->callback); ckfree(data); return 1; } static int Sockname_Cmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[]) { #ifdef _WIN32 SOCKET sock; SOCKADDR_IN sockname; LPSOCKADDR pSockname = (LPSOCKADDR) &sockname; int size = sizeof(SOCKADDR_IN); #else int sock; struct sockaddr_in sockname; struct sockaddr * pSockname = (struct sockaddr *) &sockname; socklen_t size = sizeof(struct sockaddr_in); #endif Tcl_Channel *channel = NULL; char *channelName = NULL; int mode; if (objc != 2) { Tcl_WrongNumArgs (interp, 1, objv, "socket"); return TCL_ERROR; } channelName = Tcl_GetString (objv[1]); channel = Tcl_GetChannel (interp, channelName, &mode); if (channel == NULL) { return TCL_ERROR; } if (Tcl_GetChannelHandle (channel, mode, &sock) == TCL_OK) { if (getsockname(sock, pSockname, &size) >= 0) { Tcl_Obj *result = NULL; Tcl_Obj *ip = NULL; Tcl_Obj *port = NULL; result = Tcl_NewListObj (0, NULL); ip = Tcl_NewStringObj (inet_ntoa(sockname.sin_addr), -1); Tcl_ListObjAppendElement(interp, result, ip); port = Tcl_NewIntObj (ntohs(sockname.sin_port)); Tcl_ListObjAppendElement(interp, result, port); Tcl_SetObjResult (interp, result); return TCL_OK; } else { Tcl_AppendResult(interp, "can't get sockname: ", Tcl_PosixError(interp), NULL); return TCL_ERROR; } } else { Tcl_AppendResult (interp, "Could not get channel handle", (char *) NULL); return TCL_ERROR; } return TCL_OK; } int DLLEXPORT Asyncresolver_Init(Tcl_Interp *interp) { if (Tcl_InitStubs(interp, "8.4", 0) == NULL) { return TCL_ERROR; } /* changed this to check for an error - GPS */ if (Tcl_PkgProvide(interp, "asyncresolver", "0.1") == TCL_ERROR) { return TCL_ERROR; } Tcl_CreateObjCommand(interp, "::asyncresolver::asyncresolve", Asyncresolve_Cmd, NULL, NULL); Tcl_CreateObjCommand(interp, "::asyncresolver::sockname", Sockname_Cmd, NULL, NULL); return TCL_OK; } amsn-0.98.9/utils/asyncresolver/src/Rules.mk0000644000175000017500000000053611061002266020640 0ustar billiobbilliob OBJS-asyncresolver = $(async_dir)/src/asyncresolver.o TARGETS-asyncresolver = $(async_dir)/src/libasyncresolver.$(SHLIB_EXTENSION) all:: $(TARGETS-asyncresolver) $(TARGETS-asyncresolver): $(OBJS-asyncresolver) @$(echo_link_so) @$(link_so) clean:: clean-asyncresolver clean-asyncresolver:: rm -f $(OBJS-asyncresolver) $(TARGET-asyncresolver) amsn-0.98.9/utils/asyncresolver/ASYNCRESOLVER.dsp0000644000175000017500000001007611261753053021206 0ustar billiobbilliob# Microsoft Developer Studio Project File - Name="ASYNCRESOLVER" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 CFG=ASYNCRESOLVER - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "ASYNCRESOLVER.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "ASYNCRESOLVER.mak" CFG="ASYNCRESOLVER - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "ASYNCRESOLVER - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "ASYNCRESOLVER - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "ASYNCRESOLVER - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ASYNCRESOLVER_EXPORTS" /YX /FD /c # ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ASYNCRESOLVER_EXPORTS" /D "USE_TCL_STUBS" /YX /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x40c /d "NDEBUG" # ADD RSC /l 0x40c /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 # ADD LINK32 tclstub85.lib ws2_32.lib kernel32.lib /nologo /dll /machine:I386 /out:"libasyncresolver.dll" # SUBTRACT LINK32 /nodefaultlib !ELSEIF "$(CFG)" == "ASYNCRESOLVER - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ASYNCRESOLVER_EXPORTS" /YX /FD /GZ /c # ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ASYNCRESOLVER_EXPORTS" /YX /FD /GZ /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x40c /d "_DEBUG" # ADD RSC /l 0x40c /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept !ENDIF # Begin Target # Name "ASYNCRESOLVER - Win32 Release" # Name "ASYNCRESOLVER - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=.\src\asyncresolver.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project amsn-0.98.9/utils/asyncresolver/asyncresolver.tcl0000644000175000017500000000301111307716723022035 0ustar billiobbilliob load [file join $dir libasyncresolver[info sharedlibextension]] namespace eval ::asyncresolver { variable request_number 0 proc resolve { original arguments } { variable request_number if { [ lsearch $arguments -server ] == -1} { incr request_number set varname ::asyncresolver::_wait_$request_number ::asyncresolver::asyncresolve [list ::asyncresolver::_resolve_callback $varname] [lindex $arguments end-1] if {![info exists $varname]} {tkwait variable $varname} if { [set $varname] == "" } { error "couldn't open socket: host is unreachable (Name or service not known)" } set cmd [linsert [lreplace $arguments end-1 end-1 [set $varname]] 0 $original ] unset $varname return [eval $cmd] } else { return [eval [linsert $arguments 0 $original ] ] } } proc _resolve_callback { var {ip ""} } { set $var $ip } } rename fconfigure _fconfigure proc fconfigure { channel args } { if { [llength $args] == 1 && [lindex $args 0] == "-sockname" } { set sockname [::asyncresolver::sockname $channel] foreach {ip port} $sockname break return [list $ip [info hostname] $port] } else { return [eval [linsert $args 0 _fconfigure $channel] ] } } # rename socket _socket # proc socket { args } { # return [::asyncresolver::resolve _socket $args] # } # package require tls # if {[info commands ::tls::socket] == "::tls::socket"} { # rename ::tls::socket ::tls::_socket # proc ::tls::socket { args } { # return [::asyncresolver::resolve ::tls::_socket $args] # } # } amsn-0.98.9/utils/asyncresolver/Rules.mk0000644000175000017500000000053211061002266020045 0ustar billiobbilliob OBJS-asyncresolver = $(async_dir)/src/libasyncresolver.$(SHLIB_EXTENSION) TARGETS-asyncresolver = $(async_dir)/libasyncresolver.$(SHLIB_EXTENSION) all:: $(TARGETS-asyncresolver) $(TARGETS-asyncresolver): $(OBJS-asyncresolver) cp $< $@ clean:: clean-asyncresolver clean-asyncresolver:: rm -f $(OBJS-asyncresolver) $(TARGETS-asyncresolver) amsn-0.98.9/utils/framec/0000755000175000017500000000000011757711631014777 5ustar billiobbilliobamsn-0.98.9/utils/framec/framec.tcl0000644000175000017500000000711210401376713016732 0ustar billiobbilliob#----------------------------------------------------------------------- # TITLE: # framec.tcl # # AUTHOR: # Arieh Schneier # # DESCRIPTION: # Widget adaptor to add a coloured frame around a widget. # Default widget if not specified is a frame. # #----------------------------------------------------------------------- # SYNOPSIS: # framec pathName ?options? # STANDARD OPTIONS # (all options available to 'type') # WIDGET SPECIFIC OPTIONS # -background or -bg # -bordercolor or -bc # -borderwidth or -bw # -innerpadx # -innerpady # -type # STANDARD COMMANDS # (all commands available to 'type') # WIDGET SPECIFIC COMMANDS # pathname configure ?option? ?value? ... # pathname cget option # pathname getinnerframe # (other standard snit commands) #----------------------------------------------------------------------- package require snit package provide framec 0.2 snit::widget framec { component padding component inner option -bordercolor -default #000000 -cgetmethod getOption -configuremethod changeBorderColor option -bc -cgetmethod getOption -configuremethod changeBorderColor option -borderwidth -default 1 -cgetmethod getOption -configuremethod changeBorderWidth option -bd -cgetmethod getOption -configuremethod changeBorderWidth option -background -default #ffffff -cgetmethod getOption -configuremethod changeBackground option -bg -cgetmethod getOption -configuremethod changeBackground option -innerpadx -default 0 -cgetmethod getOption -configuremethod changePadWidthx option -innerpady -default 0 -cgetmethod getOption -configuremethod changePadWidthy option -class option -type delegate option * to inner except {-bordercolor -bc -borderwidth -bd -background -bg -padwidth -type -class} delegate method * to inner constructor {args} { #check for type and class set itstype frame set itsclass "" foreach {option value} $args { if { [string equal $option "-type"] } { set itstype $value } elseif { [string equal $option "-class"] } { set itsclass $value } } $hull configure -background $options(-bordercolor) -relief solid -borderwidth 0 install padding using frame $win.padding -background $options(-background) -relief solid -borderwidth 0 if { $itsclass == "" } { install inner using $itstype $win.inner -borderwidth 0 } else { install inner using $itstype $win.inner -class $itsclass -borderwidth 0 } pack $padding -padx $options(-borderwidth) -pady $options(-borderwidth) -expand true -fill both pack $inner -padx $options(-innerpadx) -pady $options(-innerpady) -expand true -fill both -in $padding # Apply any options passed at creation time. $self configurelist $args } method getOption {option} { if { [string equal $option "-bd"] } { set option "-borderwidth" } elseif { [string equal $option "-bg"] } { set option "-background" } elseif { [string equal $option "-bc"] } { set option "-bordercolor" } return $options($option) } method changeBorderColor {option value} { set options(-bordercolor) $value $hull configure -background $value } method changeBorderWidth {option value} { set options(-borderwidth) $value pack configure $padding -padx $value -pady $value } method changeBackground {option value} { set options(-background) $value $padding configure -background $value $inner configure -background $value } method changePadWidthx {option value} { set options(-innerpadx) $value pack configure $inner -padx $value } method changePadWidthy {option value} { set options(-innerpady) $value pack configure $inner -pady $value } method getinnerframe {} { return $inner } } amsn-0.98.9/utils/framec/pkgIndex.tcl0000644000175000017500000000011510167420140017233 0ustar billiobbilliobpackage ifneeded framec 0.2 \ [list source [file join $dir framec.tcl]] amsn-0.98.9/utils/sha1/0000755000175000017500000000000011757711631014376 5ustar billiobbilliobamsn-0.98.9/utils/sha1/sha1.tcl0000644000175000017500000002163710154253571015741 0ustar billiobbilliob################################################## # # sha1.tcl - SHA1 in Tcl # Author: Don Libes , May 2001 # Version 1.0.3 # # SHA1 defined by FIPS 180-1, "The SHA1 Message-Digest Algorithm", # http://www.itl.nist.gov/fipspubs/fip180-1.htm # HMAC defined by RFC 2104, "Keyed-Hashing for Message Authentication" # # Some of the comments below come right out of FIPS 180-1; That's why # they have such peculiar numbers. In addition, I have retained # original syntax, etc. from the FIPS. All remaining bugs are mine. # # HMAC implementation by D. J. Hagberg and # is based on C code in FIPS 2104. # # For more info, see: http://expect.nist.gov/sha1pure # # - Don ################################################## ### Code speedups by Donal Fellows who may well ### have added some extra bugs of his own... :^) ### Changed the code to use Trf if this package is present on the ### system requiring the sha1 package. Analogous to md5. package require Tcl 8.2 namespace eval ::sha1 { } if {![catch {package require Trf 2.0}] && ![catch {::sha1 -- test}]} { # Trf is available, so implement the functionality provided here # in terms of calls to Trf for speed. proc ::sha1::sha1 {msg} { string tolower [::hex -mode encode -- [::sha1 -- $msg]] } # hmac: hash for message authentication # SHA1 of Trf and SHA1 as defined by this package have slightly # different results. Trf returns the digest in binary, here we get # it as hex-string. In the computation of the HMAC the latter # requires back conversion into binary in some places. With Trf we # can use omit these. (Not all, the first place must not the changed, # see [x] proc ::sha1::hmac {key text} { # if key is longer than 64 bytes, reset it to SHA1(key). If shorter, # pad it out with null (\x00) chars. set keyLen [string length $key] if {$keyLen > 64} { set key [binary format H32 [sha1 $key]] # [x] set key [::sha1 -- $key] set keyLen [string length $key] } # ensure the key is padded out to 64 chars with nulls. set padLen [expr {64 - $keyLen}] append key [binary format "a$padLen" {}] # Split apart the key into a list of 16 little-endian words binary scan $key i16 blocks # XOR key with ipad and opad values set k_ipad {} set k_opad {} foreach i $blocks { append k_ipad [binary format i [expr {$i ^ 0x36363636}]] append k_opad [binary format i [expr {$i ^ 0x5c5c5c5c}]] } # Perform inner sha1, appending its results to the outer key append k_ipad $text #append k_opad [binary format H* [sha1 $k_ipad]] append k_opad [::sha1 -- $k_ipad] # Perform outer sha1 #sha1 $k_opad string tolower [::hex -mode encode -- [::sha1 -- $k_opad]] } } else { # Without Trf use the all-tcl implementation by Don Libes. namespace eval ::sha1 { variable K proc initK {} { variable K {} foreach t { 0x5A827999 0x6ED9EBA1 0x8F1BBCDC 0xCA62C1D6 } { for {set i 0} {$i < 20} {incr i} { lappend K [expr {int($t)}] } } } initK } # test sha1 # # This proc is not necessary during runtime and may be omitted if you # are simply inserting this file into a production program. # proc ::sha1::test {} { foreach {msg expected} { "abc" "a9993e364706816aba3e25717850c26c9cd0d89d" "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" "84983e441c3bd26ebaae4aa1f95129e5e54670f1" "[string repeat a 1000000]" "34aa973cd4c4daa4f61eeb2bdbad27316534016f" } { puts "testing: sha1 \"$msg\"" set msg [subst $msg] set msgLen [string length $msg] if {$msgLen > 10000} { puts "warning: msg length = $msgLen; this may take a while . . ." } set computed [sha1 $msg] puts "expected: $expected" puts "computed: $computed" if {0 != [string compare $computed $expected]} { puts "FAILED" } else { puts "SUCCEEDED" } } } # time sha1 # # This proc is not necessary during runtime and may be omitted if you # are simply inserting this file into a production program. # proc ::sha1::time {} { foreach len {10 50 100 500 1000 5000 10000} { set time [::time {sha1 [format %$len.0s ""]} 10] set msec [lindex $time 0] puts "input length $len: [expr {$msec/1000}] milliseconds per interation" } } proc ::sha1::sha1 {msg} { variable K # # 4. MESSAGE PADDING # # pad to 512 bits (512/8 = 64 bytes) set msgLen [string length $msg] # last 8 bytes are reserved for msgLen # plus 1 for "1" set padLen [expr {56 - $msgLen%64}] if {$msgLen % 64 >= 56} { incr padLen 64 } # 4a. and b. append single 1b followed by 0b's append msg [binary format "a$padLen" \200] # 4c. append 64-bit length # Our implementation obviously limits string length to 32bits. append msg \0\0\0\0[binary format "I" [expr {8*$msgLen}]] # # 7. COMPUTING THE MESSAGE DIGEST # # initial H buffer set H0 [expr {int(0x67452301)}] set H1 [expr {int(0xEFCDAB89)}] set H2 [expr {int(0x98BADCFE)}] set H3 [expr {int(0x10325476)}] set H4 [expr {int(0xC3D2E1F0)}] # # process message in 16-word blocks (64-byte blocks) # # convert message to array of 32-bit integers # each block of 16-words is stored in M($i,0-16) binary scan $msg I* words set blockLen [llength $words] for {set i 0} {$i < $blockLen} {incr i 16} { # 7a. Divide M[i] into 16 words W[0], W[1], ... set W [lrange $words $i [expr {$i+15}]] # 7b. For t = 16 to 79 let W[t] = .... set t 16 set t3 12 set t8 7 set t14 1 set t16 -1 for {} {$t < 80} {incr t} { set x [expr {[lindex $W [incr t3]] ^ [lindex $W [incr t8]] ^ \ [lindex $W [incr t14]] ^ [lindex $W [incr t16]]}] lappend W [expr {($x << 1) | (($x >> 31) & 1)}] } # 7c. Let A = H[0] .... set A $H0 set B $H1 set C $H2 set D $H3 set E $H4 # 7d. For t = 0 to 79 do for {set t 0} {$t < 20} {incr t} { set TEMP [expr {(($A << 5) | (($A >> 27) & 0x1f)) + \ (($B & $C) | ((~$B) & $D)) \ + $E + [lindex $W $t] + [lindex $K $t]}] set E $D set D $C set C [expr {($B << 30) | (($B >> 2) & 0x3fffffff)}] set B $A set A $TEMP } for {} {$t<40} {incr t} { set TEMP [expr {(($A << 5) | (($A >> 27) & 0x1f)) + \ ($B ^ $C ^ $D) \ + $E + [lindex $W $t] + [lindex $K $t]}] set E $D set D $C set C [expr {($B << 30) | (($B >> 2) & 0x3fffffff)}] set B $A set A $TEMP } for {} {$t<60} {incr t} { set TEMP [expr {(($A << 5) | (($A >> 27) & 0x1f)) + \ (($B & $C) | ($B & $D) | ($C & $D)) \ + $E + [lindex $W $t] + [lindex $K $t]}] set E $D set D $C set C [expr {($B << 30) | (($B >> 2) & 0x3fffffff)}] set B $A set A $TEMP } for {} {$t<80} {incr t} { set TEMP [expr {(($A << 5) | (($A >> 27) & 0x1f)) + \ ($B ^ $C ^ $D) \ + $E + [lindex $W $t] + [lindex $K $t]}] set E $D set D $C set C [expr {($B << 30) | (($B >> 2) & 0x3fffffff)}] set B $A set A $TEMP } set H0 [expr {int(($H0 + $A) & 0xffffffff)}] set H1 [expr {int(($H1 + $B) & 0xffffffff)}] set H2 [expr {int(($H2 + $C) & 0xffffffff)}] set H3 [expr {int(($H3 + $D) & 0xffffffff)}] set H4 [expr {int(($H4 + $E) & 0xffffffff)}] } return [format %0.8x%0.8x%0.8x%0.8x%0.8x $H0 $H1 $H2 $H3 $H4] } ### These procedures are either inlined or replaced with a normal [format]! # #proc ::sha1::f {t B C D} { # switch [expr {$t/20}] { # 0 { # expr {($B & $C) | ((~$B) & $D)} # } 1 - 3 { # expr {$B ^ $C ^ $D} # } 2 { # expr {($B & $C) | ($B & $D) | ($C & $D)} # } # } #} # #proc ::sha1::byte0 {i} {expr {0xff & $i}} #proc ::sha1::byte1 {i} {expr {(0xff00 & $i) >> 8}} #proc ::sha1::byte2 {i} {expr {(0xff0000 & $i) >> 16}} #proc ::sha1::byte3 {i} {expr {((0xff000000 & $i) >> 24) & 0xff}} # #proc ::sha1::bytes {i} { # format %0.2x%0.2x%0.2x%0.2x [byte3 $i] [byte2 $i] [byte1 $i] [byte0 $i] #} # hmac: hash for message authentication proc ::sha1::hmac {key text} { # if key is longer than 64 bytes, reset it to SHA1(key). If shorter, # pad it out with null (\x00) chars. set keyLen [string length $key] if {$keyLen > 64} { set key [binary format H32 [sha1 $key]] set keyLen [string length $key] } # ensure the key is padded out to 64 chars with nulls. set padLen [expr {64 - $keyLen}] append key [binary format "a$padLen" {}] # Split apart the key into a list of 16 little-endian words binary scan $key i16 blocks # XOR key with ipad and opad values set k_ipad {} set k_opad {} foreach i $blocks { append k_ipad [binary format i [expr {$i ^ 0x36363636}]] append k_opad [binary format i [expr {$i ^ 0x5c5c5c5c}]] } # Perform inner sha1, appending its results to the outer key append k_ipad $text append k_opad [binary format H* [sha1 $k_ipad]] # Perform outer sha1 sha1 $k_opad } } package provide sha1 1.0.3 amsn-0.98.9/utils/sha1/pkgIndex.tcl0000644000175000017500000000112410154253571016643 0ustar billiobbilliob# Tcl package index file, version 1.1 # This file is generated by the "pkg_mkIndex" command # and sourced either when an application starts up or # by a "package unknown" script. It invokes the # "package ifneeded" command to set up package-related # information so that packages will be loaded automatically # in response to "package require" commands. When this # script is sourced, the variable $dir must contain the # full path name of this file's directory. if {![package vsatisfies [package provide Tcl] 8.2]} {return} package ifneeded sha1 1.0.3 [list source [file join $dir sha1.tcl]] amsn-0.98.9/utils/scalable-bg/0000755000175000017500000000000011757711631015676 5ustar billiobbilliobamsn-0.98.9/utils/scalable-bg/scalable-bg.tcl0000644000175000017500000001236110403260215020521 0ustar billiobbilliobpackage require snit package provide scalable-bg 0.1 snit::type scalable-bg { option -border -default {0 0 0 0} -configuremethod setBorder option -n -configuremethod setOption -default 0 option -e -configuremethod setOption -default 0 option -s -configuremethod setOption -default 0 option -w -configuremethod setOption -default 0 option -resizemethod -default tile option -source -configuremethod setOption option -width -configuremethod setOption -default 1 option -height -configuremethod setOption -default 1 variable src variable base constructor { args } { $self configurelist $args # Create base image set base [image create photo] set src $options(-source) # Build up the image $self BuildImage } destructor { catch {image delete $base} } method BuildImage { } { # Check if requested size is too small set minwidth [expr {$options(-w) + $options(-e) + 1}] set minheight [expr {$options(-n) + $options(-s) + 1}] if { $options(-width) < $minwidth || \ $options(-height) < $minheight } { return {} } # Get src image width and height set srcwidth [image width $src] set srcheight [image height $src] set midvert [expr {$options(-height) - $options(-n) - $options(-s)}] set midhoriz [expr {$options(-width) - $options(-w) - $options(-e)}] set srcmidvert [expr {$srcheight - $options(-n) - $options(-s)}] set srcmidhoriz [expr {$srcwidth - $options(-w) - $options(-e)}] set bottomvert [expr {$options(-height) - $options(-s)}] set righthoriz [expr {$options(-width) - $options(-e)}] set srcbottomvert [expr {$srcheight - $options(-s)}] set srcrighthoriz [expr {$srcwidth - $options(-e)}] # Check values aren't below 1 foreach var { srcwidth srcheight midvert midhoriz srcmidvert srcmidhoriz bottomvert righthoriz srcbottomvert srcrighthoriz } { if { [set $var] < 1 } { set $var 1 } } # Create sub-images foreach img { top left centre right bottom } { set $img [image create photo] } # Are we scaling or tiling? set scaling [string equal $options(-resizemethod) scale] # Resize left section if { $options(-w) > 0 } { $left configure -width $options(-w) -height $srcmidvert $left blank $left copy $src -from 0 $options(-n) $options(-w) $srcbottomvert -to 0 0 if { $scaling } { ::CxImage::Resize $left $options(-w) $midvert } } # Resize middle section $centre configure -width $srcmidhoriz -height $srcmidvert $centre blank $centre copy $src -from $options(-w) $options(-n) $srcrighthoriz $srcbottomvert -to 0 0 if { $scaling } { ::CxImage::Resize $centre $midhoriz $midvert } # Resize right section if { $options(-e) > 0 } { $right configure -width $options(-e) -height $srcmidvert $right blank $right copy $src -from $srcrighthoriz $options(-n) $srcwidth $srcbottomvert -to 0 0 if { $scaling } { ::CxImage::Resize $right $options(-e) $midvert } } # Resize top section if { $options(-n) > 0 } { $top configure -width $srcmidhoriz -height $options(-n) $top blank $top copy $src -from $options(-w) 0 $srcrighthoriz $options(-n) if { $scaling } { ::CxImage::Resize $top $midhoriz $options(-n) } } # Resize bottom section if { $options(-s) > 0 } { $bottom configure -width $srcmidhoriz -height $options(-s) $bottom blank $bottom copy $src -from $options(-w) $srcbottomvert $srcrighthoriz $srcheight if { $scaling } { ::CxImage::Resize $bottom $midhoriz $options(-s) } } # Build up button image # Start with a clean slate... $base blank # ...of correct proportions $base configure -width $options(-width) -height $options(-height) # NW corner $base copy $src -from 0 0 $options(-w) $options(-n) -to 0 0 # N border $base copy $top -to $options(-w) 0 $righthoriz $options(-n) # NE corner $base copy $src -from $srcrighthoriz 0 $srcwidth $options(-n) -to $righthoriz 0 # W border $base copy $left -to 0 $options(-n) $options(-w) $bottomvert # Centre/Body $base copy $centre -to $options(-w) $options(-n) $righthoriz $bottomvert # E border $base copy $right -to $righthoriz $options(-n) $options(-width) $bottomvert # SW corner $base copy $src -from 0 $srcbottomvert $options(-w) $srcheight -to 0 $bottomvert # S border $base copy $bottom -to $options(-w) $bottomvert $righthoriz $options(-height) # SE corner $base copy $src -from $srcrighthoriz $srcbottomvert $srcwidth $srcheight -to $righthoriz $bottomvert # Delete sub-images foreach img { top left centre right bottom } { image delete [set $img] } } # Set's the borders for the image method setBorder { option value } { set options(-border) $value foreach { n e s w } $value { $self configure -n $n $self configure -e $e $self configure -s $s $self configure -w $w } } # Generic option setting method setOption { option value } { if { [string equal $options($option) $value] } { return {} } set options($option) $value # Check we have everythgin we need to build the image if { [info exists src] && [info exists base] } { set src $options(-source) $self BuildImage } } # Returns the name of the tk image used by this scalable-bg method name { } { return $base } } amsn-0.98.9/utils/scalable-bg/pkgIndex.tcl0000644000175000017500000000012710252125705020141 0ustar billiobbilliobpackage ifneeded scalable-bg 0.1 \ [list source [file join $dir scalable-bg.tcl]] amsn-0.98.9/utils/scalable-bg/test.tcl0000644000175000017500000000061710252125705017353 0ustar billiobbillioblappend auto_path "../" package require scalable-bg wm geometry . 100x80 image create photo image1 -file "../pixmapbutton/button.gif" scalable-bg bg -image image1 -n 6 -e 6 -s 6 -w 6 -width 100 -height 100 canvas .c -bg white -highlightthickness 0 .c create image 0 0 -anchor nw -image [bg getBase] -tag img pack .c -expand true -fill both bind .c "bg configure -width %w -height %h" amsn-0.98.9/utils/pixmapbutton/0000755000175000017500000000000011757711631016274 5ustar billiobbilliobamsn-0.98.9/utils/pixmapbutton/button_focus.gif0000644000175000017500000000146510260275445021477 0ustar billiobbilliobGIF89a8]uyuuyy}}!1))9))99BB9J9RRRBBZRBZZZckZJckkcZkks{s{{k{{kÄÌ{ǔkDŽǔǜӄsόϭה׭ӭלӵ׭ۜ۵۽!Created with The GIMP! ,8]SA0&6JZY@+T]W*#048<:7:<72)N6%L3 UM,D1[]+R/p82#ۆġɉ`  I2W% 8\9D H`R$( H*  ό X Q -TbG41j)DQpEH$z] 0d-Dt)Bx-B"hV>@-AV` !Bt:g9͙S{ΰ`VAlaIknmO}{ɸANV@@ |£?.}.;B ;amsn-0.98.9/utils/pixmapbutton/icon2.gif0000644000175000017500000000111210244356705017765 0ustar billiobbilliobGIF89ac!$1!(1!0B)09!4B101!4J141189)&*LT\"I GR1PO^$F0,/1 M:]\4)N- SB7@9Ï'#(I0aR XRі~d$^;amsn-0.98.9/utils/pixmapbutton/radiobutton.tcl0000644000175000017500000002005610260277125021326 0ustar billiobbilliobpackage require snit snit::widgetadaptor pixmapradiobutton { typevariable widgetlist typevariable loadimagecommand typevariable normal typevariable hover typevariable disabled typevariable normalpress typevariable hoverpress typevariable disabledpress typevariable selected option -activeforeground -configuremethod SetActiveForeground option -activefg -configuremethod SetActiveForeground option -command option -font -configuremethod SetFont option -foreground -configuremethod SetForeground option -fg -configuremethod SetForeground option -indicatoron -default 1 -configuremethod SetIndicatorOn option -offvalue option -onvalue option -state -default normal -configuremethod SetState option -takefocus -default 1 option -text -configuremethod SetText option -variable typeconstructor { $type SetImageCommand "$type loadimage" $type reloadimages 1 } constructor { args } { lappend widgetlist $self installhull using canvas -bg white -relief flat -highlightthickness 0 $hull create image 0 0 -image $normal -disabledimage $disabled -anchor nw -tag button $hull create text 0 0 -anchor w -tag label $hull coords label [image width $normal] [expr [image height $normal] / 2] $self configure -variable [lindex $args [expr [lsearch $args -variable] + 1]] set selected($options(-variable)) "" $self configurelist $args $self UpdateVariable 0 $hull configure -width [expr [$self MeasureText $options(-text) w] + [image width $normal]] set ih [image height $normal] set th [$self MeasureText $options(-text) h] if { $ih > $th } { $hull configure -height $ih } else { $hull configure -height $th } bind $self "$self ButtonHovered" bind $self "$self ButtonUnhovered" bind $self "$self select" bind $self "$self select" bind $self "$self select" bind $self "$self select" } #//////////////////////////////////////////////////////////////// # PUBLIC COMMANDS / # deselect / # flash / # invoke / # select / # toggle / #//////////////////////////////////////////////////////////////// method invoke { } { if { $options(-state) != "disabled" } { eval $options(-command) } } method flash { } { if { $options(-state) != "disabled" } { after 250 $self toggle after 500 $self toggle after 750 $self toggle after 1000 $self toggle } } method select { } { if { $selected($options(-variable)) != $self } { if { $selected($options(-variable)) != "" } { $selected($options(-variable)) deselect } set selected($options(-variable)) $self } if { $options(-state) != "disabled" } { if { $options(-variable) != "" } { $self UpdateVariable $options(-onvalue) } $hull itemconfigure button -image $normalpress -disabledimage $disabledpress $self invoke } } method deselect { } { if { $options(-state) != "disabled" } { if { $options(-variable) != "" } { $self UpdateVariable $options(-offvalue) } $hull itemconfigure button -image $normal -disabledimage $disabled } } #//////////////////////////////////////////////////////// # PRIVATE COMMANDS / #//////////////////////////////////////////////////////// method ButtonHovered { } { if { $options(-state) != "disabled" } { $self configure -state active } } method ButtonUnhovered { } { if { $options(-state) != "disabled" } { $self configure -state normal } } method SetActiveForeground { option value } { set options(-activeforeground) $value set options(-activefg) $value $hull itemconfigure label -activefill $value } method SetForeground { option value } { set options(-foreground) $value set options(-fg) $value $hull itemconfigure label -fill $value } method SetFont { option value } { set options(-font) $value $hull itemconfigure label -font $value } method SetIndicatorOn { option value } { set options(-indicatoron) $value if { !$value } { $hull delete button $hull coords label 0 [expr [image height $normal] / 2] } else { switch $selected($options(-variable)) { $self { $hull create image 0 0 -image $normalpress -disabledimage $disabledpress -anchor nw -tag button } default { $hull create image 0 0 -image $normal -disabledimage $disabled -anchor nw -tag button } } $hull coords label [image width $normal] [expr [image height $normal] / 2] switch $options(-state) { disabled { $hull itemconfigure button -state disabled } default { $hull itemconfigure button -state normal } } } } method SetState { option value } { set options(-state) $value switch $value { normal { if { $selected($options(-variable)) == $self } { $hull itemconfigure button -image $normalpress } else { $hull itemconfigure button -image $normal } } active { if { $selected($options(-variable)) == $self } { $hull itemconfigure button -image $hoverpress } else { $hull itemconfigure button -image $hover } } disabled { $hull itemconfigure button -state disabled } } } method SetText { option value } { set options(-text) $value $hull itemconfigure label -text $value } method UpdateVariable { value } { uplevel #0 "set $options(-variable) $value" } method MeasureText { text dimension } { if { $dimension == "w" } { if { $options(-font) != "" } { set idx [expr [string first "\n" $text] - 1] if { $idx < 0 } { set idx end } set m [font measure $options(-font) -displayof $self [string range $text \ 0 $idx]] return $m } else { set idx [expr [string first "\n" $text] - 1] if { $idx < 0 } { set idx end } set f [font create -family helvetica -size 12 -weight normal] set m [font measure $f -displayof $self [string range $text \ 0 $idx]] font delete $f return $m } } elseif { $dimension == "h" } { if { $options(-font) != "" } { #Get number of lines set n [$self NumberLines $text] #Multiply font size by no. lines and add gap between lines * (no. lines - 1). return [expr $n * [font configure $options(-font) -size] + (($n - 1) * 7)] } else { #Get number of lines set n [$self NumberLines $text] #Multiply font size by no. lines and add gap between lines * (no. lines - 1). return [expr ($n * 12) + (($n - 1) * 7)] } } } method NumberLines { string } { for { set n 0; set idx 0 } { [string first "\n" $string $idx] != -1} { incr n 1 } { set idx [expr [string first "\n" $string $idx] +1] } if { $n < 1 } { set n 1 } return $n } #///////////////////////////////////////////////////// #///////////////////////////////////////////////////// # Image (re)loading methods # # # #///////////////////////////////////////////////////// typemethod loadimage { imagename } { return [image create photo -file $imagename.gif] } typemethod SetImageCommand { command } { set loadimagecommand $command } typemethod reloadimages { init } { if { !$init } { image delete $normal image delete $hover image delete $disabled image delete $normalpress image delete $hoverpress image delete $disabledpress } set normal [eval "$loadimagecommand radio"] set hover [eval "$loadimagecommand radiohover"] set disabled [eval "$loadimagecommand radiodisabled"] set normalpress [eval "$loadimagecommand radiopress"] set hoverpress [eval "$loadimagecommand radiohoverpress"] set disabledpress [eval "$loadimagecommand radiodisabledpress"] if { !$init } { foreach widget $widgetlist { if { $selected([$widget cget -variable]) == $widget } { ::hull1$widget itemconfigure button -image $normalpress -disabledimage $disabledpress } else { ::hull1$widget itemconfigure button -image $normal -disabledimage $disabled } $widget configure -width [expr [$widget MeasureText [$widget cget -text] w] + [image width $normal]] set ih [image height $normal] set th [$self MeasureText $options(-text) h] if { $ih > $th } { $hull configure -height $ih } else { $hull configure -height $th } } } } }amsn-0.98.9/utils/pixmapbutton/checkdisabled.gif0000644000175000017500000000032110260277125021515 0ustar billiobbilliobGIF89a!,HDDDDDHDDDDDHDDDD#("""CDH$(DD!DDBDH$(DD!DDBDH$(DD!DDBDH4""""8DDDDDHDDDDDHDDDDDHDDDDDHD;amsn-0.98.9/utils/pixmapbutton/radiodisabledpress.gif0000644000175000017500000000054410260277125022622 0ustar billiobbilliobGIF89a!,4M4M4M4M4M4M4M44M4MSs p44M4MSB J6JL4MӔI$4M  T44MG B!-4M4,  4L4N$ $4MH  H0Mt,R! 4MM!I $4MӔ(I$IG2M4MSR,-E2M4M4M1L4M4M4M4M44M4M4M4M4;amsn-0.98.9/utils/pixmapbutton/radiohover.gif0000644000175000017500000000024010260277125021112 0ustar billiobbilliobGIF89a X!,MIx"@ q4pVHĸ N10,Ex!egCIBJMj385/Ni3;amsn-0.98.9/utils/pixmapbutton/button_disabled.gif0000644000175000017500000000335110260274201022110 0ustar billiobbilliobGIF89a7ȗƗɗȗǗǕʗȗǗʕǘˑȔʗɏȕ̐ɘȖˑɑȗɔɗɕʐțʔȜɗʘɘ˓ʖəʗɚʕ˛ɛʗʘ˓̎Γʛ˛˚˝͗͘Ε͖͞ˡϔ͗͘͠ΓϑΕΘϛϗ΢ΟϛΥΦјқӜӚњќҚҙԜҜҚӝқЦҜԚѢҞԜҟӚӛӜӝӞԜԚԛԜ՚ҫөӫԪդӱԮؠձ֯׵׸۪۪ٵٹܪܭ!Created with The GIMP! ,7 nl΢ö0Ckr6i׸YV آ:wSknjӜ)&TADY'#耢(p~@ & P v*}2"*`(e,)` (N"K+blE +ZnibG2 T7) 8H5+._j,WZ(5K3Yn l,_aEԦ8=`DR'0 \+6cĆ;6aʼnCgyslj-o|8+G@rzMA3N Yrϋw>1Cנiӌ,b{$L~_2A~AHtǰCπR!~jv(b(b2 j tL\rh0 !+Q̂&ַt@ƨx ua#XnjKx!xXjǓPGsL"5\0`~l1@!`pGwm{170x##1#'袆,5sar nwq&ɤs 2q7]r-w(jpuAA"l GrYᕊ`u2"JO A Gҧ%[']12ib/{8 #B\U ސkN"Xm,mļhdk0J3 a֊ksԩbDG*>pЌ;jǵ^uaw%ݾɸsJ$:re~Qֽ"I 4:0C ,Y-2.Ԓ.[hn67hlb)q &7!CJ81Zt[HKOT![fDTtAEa%щb)Ì&rSB tA$BQ?<0@O@ETΧpBn`:* T9|t8!93M7Tc6Ds4D35@SD)RHF9q;amsn-0.98.9/utils/pixmapbutton/button_pressed.gif0000644000175000017500000000202410260274201022002 0ustar billiobbilliobGIF89a7]yy}}"**3"*;*D;DLUU;]DUD]]LfUfoowU]wo]fĈđęfɈɑəΈwΙoΡ֑֫ڙޙڻ޳޻!Created with The GIMP! ,7]P5'AY]R /]0)8:8:Ĺ2[ILNNONMMO8$NF}ְoa6}m{.O9q?m$Уɽ<Ԇ#k4PԴltYrPt@RKBl谪ԛ4QjߓJ -?r֚€cĶۢʜjNf6\P ,|;ྀ6Lq}|p:`~ 1͈!朹h,~;_Mұswe*fشŽ[kܳs6(ЈP9hu־t}cT0Da96[kڞ#6Q ?tǮqiAZ AAka ~AX`΍\Qp@LQA7f Ha(b_Hp(EA ? AGZi$I"$F&%MyV q T`,W"bfycflA rE9p +g'{ih' ( >@E(;amsn-0.98.9/utils/pixmapbutton/checkhoverpress.gif0000644000175000017500000000051310260277125022151 0ustar billiobbilliobGIF89a ),)JMJRURkikkmkX!,u]u]u]u]u]u]u]uu]qqDZ\u]AAu]UUUUbu]UUUAXu]u@UUMXu]u@ $ Pq]uPUq]uPdTu\u]TIHTu\u]ZeYeu]rqq,u]x]u]u]u]u]u]u]u]u]u]u]u]W;amsn-0.98.9/utils/pixmapbutton/radio.gif0000644000175000017500000000033410260277125020052 0ustar billiobbilliobGIF89a! ,Y'diKz,p4Rؑp FEs( TJ]R!1Tt(lAHR+-/O)'!;amsn-0.98.9/utils/pixmapbutton/test.tcl0000644000175000017500000000266710260274201017753 0ustar billiobbilliob#!/usr/bin/env wish lappend auto_path "../" package require TkCximage package require pixmapbutton source checkbutton.tcl source radiobutton.tcl #wm attributes wm title . "button test" #wm geometry . 350x100 . config -bg white update font create plain -family helvetica -size 12 -weight normal font create massive -family helvetica -size 32 image create photo icon -file icon.gif image create photo icon2 -file icon2.gif pixmapbutton .b1 -text "Buttons can\nhave multiline\ntext!" \ -foreground red \ -font massive \ -command [list puts "b1 clicked"] \ -activeforeground blue pixmapbutton .b2 -text "Or they can have very long \nstupid text like this..." \ -font plain \ -command [list puts "b2 clicked"] pixmapbutton .b3 -text "..or short :)" \ -anchor w \ -command [list puts "b3 clicked"] pixmapbutton .b4 -text "This button invokes every second when you hold it down" \ -repeatdelay 1000 \ -repeatinterval 1000 \ -command [list puts repeat_button] pixmapradiobutton .b5 -text "Disable buttons" \ -command "disable_all" pixmapradiobutton .b6 -text "Enable buttons" \ -command "enable_all" pack .b1 .b2 .b3 .b4 .b5 .b6 -padx 10 -pady 5 -side top proc disable_all { } { .b1 configure -state disabled .b2 configure -state disabled .b3 configure -state disabled .b4 configure -state disabled } proc enable_all { } { .b1 configure -state normal .b2 configure -state normal .b3 configure -state normal .b4 configure -state normal }amsn-0.98.9/utils/pixmapbutton/checkpress.gif0000644000175000017500000000033010260277125021102 0ustar billiobbilliobGIF89a ),)JMJRURkikkmk! ,U'di悬,$Pbݤخ1~dp ((QJV#5PHjP!;amsn-0.98.9/utils/pixmapbutton/icon.gif0000644000175000017500000000120510247420020017667 0ustar billiobbilliobGIF89an9 9,)k$J41{${$R81{(J<9Z81R<9s0!JA9,{4!0!ZA9,4!0!cA90RIJ4!ZIBRMJ4!RQJ8!4!ZQJA1sIBcQJE1A1E9<)cURE9<)8!A)8!I97]kePKflmRJ;Yjg=5@hlMGF% XimgH8< bkV#4-( ZgM,0 UckhED$6Q_ld34+"AP^la!-+C@\gk[ 2)\eB/<LqTh900 2a)T(h( (&?tK+ PA,. J,|Qc(^R%ٜ #F!5a|f͚v֤IC);amsn-0.98.9/utils/pixmapbutton/button.tcl0000644000175000017500000002001710260274201020274 0ustar billiobbilliobpackage require snit package require scalable-bg package provide pixmapbutton 0.8 snit::widget pixmapbutton { typevariable widgetlist typevariable loadimagecommand typevariable normal typevariable hover typevariable pressed typevariable disabled typevariable focus variable afterid variable potent option -activeforeground option -background -configuremethod SetBackground -default #fff option -bg -configuremethod SetBackground option -command option -default -configuremethod SetDefault option -drawbg option -drawbgonhover option -foreground -configuremethod SetForeground option -fg -configuremethod SetForeground option -repeatdelay option -repeatinterval option -state -configuremethod SetState option -text -configuremethod SetText -cgetmethod GetText #Let Tk's button handle all options except these: delegate option * to button except { -image -highlightthickness -borderwidth -bd -relief -bg -padx -pady } typeconstructor { set widgetlist "" $type SetImageCommand "$type loadimage" $type reloadimages 1 } constructor { args } { #Create scalable backgrounds for the button: scalable-bg $self.normal -source $normal -n 6 -e 6 -s 6 -w 6 -width 1 -height 1 -resizemethod scale scalable-bg $self.hover -source $hover -n 6 -e 6 -s 6 -w 6 -width 1 -height 1 -resizemethod scale scalable-bg $self.pressed -source $pressed -n 6 -e 6 -s 6 -w 6 -width 1 -height 1 -resizemethod scale scalable-bg $self.disabled -source $disabled -n 6 -e 6 -s 6 -w 6 -width 1 -height 1 -resizemethod scale scalable-bg $self.focus -source $focus -n 6 -e 6 -s 6 -w 6 -width 1 -height 1 -resizemethod scale #Record the button's name in the list of good, law abiding buttons: lappend widgetlist $self #Create the 'button' component, using a label (no movement on click) install button using label $self.l -image [$self.normal name] \ -highlightthickness 0 \ -borderwidth 0 \ -relief sunken \ -compound center -padx 0 -pady 0 #Parse and apply arguments $self configurelist $args #Button is not potent yet: set potent 0 #Pack 'button' component pack $self.l # Bindings: # binding is used to check when text/packing resizes the widget, and calls the Resize method to update the size of the scalable backgrounds. bind $self "$self Resize %w %h" bind $self.l "$self ButtonHovered" bind $self.l "$self ButtonUnhovered" bind $self.l "$self ButtonPressed" bind $self.l "$self ButtonReleased" bind $self.l "focus $self.l" bind $self.l "focus $self.l" bind $self.l "$self DrawFocus" bind $self.l "$self RemoveFocus" bind $self.l "$self invoke" #Not sure how this should be properly implemented yet... #bind $self "$self invoke" } method invoke { } { if { $options(-state) != "disabled" } { eval $options(-command) } } method CancelRepeat { } { after cancel $afterid } method RepeatInvoke { repeat } { eval $options(-command) if { $repeat == "initial" } { set afterid [after $options(-repeatdelay) $self RepeatInvoke again] } elseif { $repeat == "again" } { set afterid [after $options(-repeatinterval) $self RepeatInvoke again] } } method DrawFocus { } { if { $options(-state) != "disabled" } { [$self.normal name] copy [$self.focus name] -to 0 0 [$self.hover name] copy [$self.focus name] -to 0 0 [$self.pressed name] copy [$self.focus name] -to 0 0 #$self ReassociateImages #$self.l configure -image [$self.normal name] } } method RemoveFocus { } { $type reloadimages 0 } method ButtonHovered { } { if { $options(-state) == "disabled" } { return } if { $options(-activeforeground) != "" } { $self.l configure -foreground $options(-activeforeground) } if { $potent == "maybe" } { set potent "yes" $self.l configure -image [$self.pressed name] } else { $self.l configure -image [$self.hover name] } } method ButtonUnhovered { } { if { $options(-state) == "disabled" } { return } if { $options(-activeforeground) != "" } { $self.l configure -foreground $options(-foreground) } if { $potent == "yes" } { set potent "maybe" } else { set potent "no" } $self.l configure -image [$self.normal name] } method ButtonPressed { } { if { $options(-state) == "disabled" } { return } set potent "yes" $self.l configure -image [$self.pressed name] if { $options(-repeatdelay) != "" && $options(-repeatinterval) != "" } { set afterid [after $options(-repeatdelay) $self RepeatInvoke again] } } method ButtonReleased { } { if { $options(-state) == "disabled" } { return } if { $options(-repeatdelay) != "" && $options(-repeatinterval) != "" } { $self CancelRepeat } if { $potent == "yes" } { $self.l configure -image [$self.hover name] set potent "no" if { $options(-repeatdelay) == "" && $options(-repeatinterval) == "" } { $self invoke } } else { set potent "no" $self.l configure -image [$self.normal name] } } method SetBackground { option value } { set options(-background) $value set options(-bg) $value $self.l configure -bg $value $self.l configure -activebackground $value $self.l configure -highlightbackground $value $self.l configure -highlightcolor $value } method SetDefault { option value } { set options(-default) $value switch $value { "normal" { $self SetState -state normal } "active" { focus $self } "disabled" { $self SetState -state disabled } } } method SetForeground { option value } { set options(-foreground) $value set options(-fg) $value $self.l configure -foreground $value } method SetState { option value } { set options(-state) $value switch $value { normal { $self.l configure -image [$self.normal name] } active { $self.l configure -image [$self.hover name] } disabled { $self.l configure -image [$self.disabled name] } } $self.l configure -state $value } method GetText { option } { return [string range $options(-text) 2 end-2] } method SetText { option value } { set value " $value " set options(-text) $value $self.l configure -text $value } #///////////////////////////////////////////////// # Resize method. # Makes sure the button isn't too small, then # configures the scalable backgrounds' widths and heights #///////////////////////////////////////////////// method Resize { w h } { set iw [image width $normal] set ih [image height $normal] if { $w < $iw } { set w $iw unset iw } if { $h < $ih } { set h $ih unset ih } $self.normal configure -width $w -height $h $self.hover configure -width $w -height $h $self.pressed configure -width $w -height $h $self.disabled configure -width $w -height $h $self.focus configure -width $w -height $h } #////////////////////////////////////////////////// # ReassociateImages method. # Links the loaded background images with the # scalable-bg image objects. Called by reloadimages. #////////////////////////////////////////////////// method ReassociateImages { } { $self.normal configure -source $normal $self.hover configure -source $hover $self.pressed configure -source $pressed $self.disabled configure -source $disabled $self.focus configure -source $focus } #////////////////////////////////////////////////// # Reloading images methods #///////////////////////////////////////////////// typemethod loadimage { imagename } { return [image create photo -file $imagename.gif] } typemethod SetImageCommand { command } { set loadimagecommand $command } typemethod reloadimages { init } { set normal [eval "$loadimagecommand button"] set hover [eval "$loadimagecommand button_hover"] set pressed [eval "$loadimagecommand button_pressed"] set disabled [eval "$loadimagecommand button_disabled"] set focus [eval "$loadimagecommand button_focus"] foreach widget $widgetlist { #$widget Resize $widget ReassociateImages } } } #rename button ::tk::button #rename pixmapbutton buttonamsn-0.98.9/utils/pixmapbutton/pkgIndex.tcl0000644000175000017500000000012310252124362020531 0ustar billiobbilliobpackage ifneeded pixmapbutton 0.1 \ [list source [file join $dir button.tcl]] amsn-0.98.9/utils/pixmapbutton/checkbutton.tcl0000644000175000017500000002065410260277125021311 0ustar billiobbilliobpackage require snit snit::widgetadaptor pixmapcheckbutton { typevariable widgetlist typevariable loadimagecommand typevariable blank typevariable normal typevariable hover typevariable disabled typevariable normalpress typevariable hoverpress typevariable disabledpress variable selected option -activeforeground -configuremethod SetActiveForeground option -activefg -configuremethod SetActiveForeground option -command option -font -configuremethod SetFont option -foreground -configuremethod SetForeground option -fg -configuremethod SetForeground option -indicatoron -default 1 -configuremethod SetIndicatorOn option -offvalue option -onvalue option -selected option -state -default normal -configuremethod SetState option -takefocus -default 1 option -text -configuremethod SetText option -variable typeconstructor { $type SetImageCommand "$type loadimage" $type reloadimages 1 } constructor { args } { lappend widgetlist $self installhull using canvas -bg white -relief flat -highlightthickness 0 $hull create image 0 0 -image $normal -activeimage $hover -disabledimage $disabled -anchor nw -tag button $hull create text 0 0 -anchor w -tag label $hull coords label [image width $normal] [expr [image height $normal] / 2] set selected "no" $self configurelist $args $self SetState -state $options(-state) $self configure -selected "no" $self UpdateVariable 0 $hull configure -width [expr [$self MeasureText $options(-text) w] + [image width $normal]] set ih [image height $normal] set th [$self MeasureText $options(-text) h] if { $ih > $th } { $hull configure -height $ih } else { $hull configure -height $th } bind $self "$self ButtonHovered" bind $self "$self ButtonUnhovered" bind $self "$self toggle" bind $self "$self toggle" bind $self "$self select" bind $self "$self select" bind $self "$self deselect" } #//////////////////////////////////////////////////////////////// # PUBLIC COMMANDS / # deselect / # flash / # invoke / # select / # toggle / #//////////////////////////////////////////////////////////////// method toggle { } { if { $options(-state) != "disabled" } { switch $options(-selected) { no { $self select } yes { $self deselect } } } } method invoke { } { if { $options(-state) != "disabled" } { eval $options(-command) } } method flash { } { if { $options(-state) != "disabled" } { after 250 $self toggle after 500 $self toggle after 750 $self toggle after 1000 $self toggle } } method select { } { $self configure -selected "yes" if { $options(-state) != "disabled" } { if { $options(-variable) != "" } { $self UpdateVariable $options(-onvalue) } $hull itemconfigure button -image $normalpress -disabledimage $disabledpress $self invoke } } method deselect { } { $self configure -selected "no" if { $options(-state) != "disabled" } { if { $options(-variable) != "" } { $self UpdateVariable $options(-offvalue) } $hull itemconfigure button -image $normal -disabledimage $disabled } } #//////////////////////////////////////////////////////// # PRIVATE COMMANDS / #//////////////////////////////////////////////////////// method ButtonHovered { } { if { $options(-state) != "disabled" } { if { $options(-selected) == "yes" } { $hull itemconfigure button -image $hoverpress } else { $hull itemconfigure button -image $hover } } } method ButtonUnhovered { } { if { $options(-state) != "disabled" } { if { $options(-selected) == "yes" } { $hull itemconfigure button -image $normalpress } else { $hull itemconfigure button -image $normal } } } method SetFont { option value } { set options(-font) $value $hull itemconfigure label -font $value } method SetActiveForeground { option value } { set options(-activeforeground) $value set options(-activefg) $value $hull itemconfigure label -activefill $value } method SetForeground { option value } { set options(-foreground) $value set options(-fg) $value $hull itemconfigure label -fill $value } method SetIndicatorOn { option value } { set options(-indicatoron) $value if { !$value } { $hull delete button $hull coords label 0 [expr [image height $normal] / 2] } else { switch $options(-selected) { yes { $hull create image 0 0 -image $normalpress -disabledimage $disabledpress -anchor nw -tag button } no { $hull create image 0 0 -image $normal -disabledimage $disabled -anchor nw -tag button } } $hull coords label [image width $normal] [expr [image height $normal] / 2] switch $options(-state) { disabled { $hull itemconfigure button -state disabled } default { $hull itemconfigure button -state normal } } } } method SetState { option value } { set options(-state) $value switch $value { normal { switch $options(-selected) { yes { $hull itemconfigure button -image $normalpress } no { $hull itemconfigure button -image $normal } } } active { switch $options(-selected) { yes { $hull itemconfigure button -image $hoverpress } no { $hull itemconfigure button -image $hover } } } disabled { $hull itemconfigure button -state disabled } } } method SetText { option value } { set options(-text) $value $hull itemconfigure label -text $value $hull configure -width [expr [$self MeasureText $options(-text) w] + [image width $normal]] set ih [image height $normal] set th [$self MeasureText $options(-text) h] if { $ih > $th } { $hull configure -height $ih } else { $hull configure -height $th } } method UpdateVariable { value } { uplevel #0 "set $options(-variable) $value" } method MeasureText { text dimension } { if { $dimension == "w" } { if { $options(-font) != "" } { set idx [expr [string first "\n" $text] - 1] if { $idx < 0 } { set idx end } set m [font measure $options(-font) -displayof $self [string range $text \ 0 $idx]] return $m } else { set idx [expr [string first "\n" $text] - 1] if { $idx < 0 } { set idx end } set f [font create -family helvetica -size 12 -weight normal] set m [font measure $f -displayof $self [string range $text \ 0 $idx]] font delete $f return $m } } elseif { $dimension == "h" } { if { $options(-font) != "" } { #Get number of lines set n [$self NumberLines $text] #Multiply font size by no. lines and add gap between lines * (no. lines - 1). return [expr $n * [font configure $options(-font) -size] + (($n - 1) * 7)] } else { #Get number of lines set n [$self NumberLines $text] #Multiply font size by no. lines and add gap between lines * (no. lines - 1). return [expr ($n * 12) + (($n - 1) * 7)] } } } method NumberLines { string } { for { set n 0; set idx 0 } { [string first "\n" $string $idx] != -1} { incr n 1 } { set idx [expr [string first "\n" $string $idx] +1] } if { $n < 1 } { set n 1 } return $n } #///////////////////////////////////////////////////// #///////////////////////////////////////////////////// # Image (re)loading methods # # # #///////////////////////////////////////////////////// typemethod loadimage { imagename } { return [image create photo -file $imagename.gif] } typemethod SetImageCommand { command } { set loadimagecommand $command } typemethod reloadimages { init } { set normal [eval "$loadimagecommand check"] set hover [eval "$loadimagecommand checkhover"] set disabled [eval "$loadimagecommand checkdisabled"] set normalpress [eval "$loadimagecommand checkpress"] set hoverpress [eval "$loadimagecommand checkhoverpress"] set disabledpress [eval "$loadimagecommand checkdisabledpress"] if { !$init } { foreach widget $widgetlist { if { [$widget cget -selected] == "no" } { ::hull1$widget itemconfigure button -image $normal -disabledimage $disabled } else { ::hull1$widget itemconfigure button -image $normalpress -disabledimage $disabledpress } $widget configure -width [expr [$widget MeasureText [$widget cget -text] w] + [image width $normal]] set ih [image height $normal] set th [$self MeasureText $options(-text) h] if { $ih > $th } { $hull configure -height $ih } else { $hull configure -height $th } } } } }amsn-0.98.9/utils/pixmapbutton/radiodisabled.gif0000644000175000017500000000042610260277125021544 0ustar billiobbilliobGIF89a ! ,P)RJ)J)RJ)TJ)RJ3')RJ)I!RJ) !AJAT"!BR'B0RJB!BJ)% !BA(!B!RB!QJTB!B(I):B)RPB J)bTJ)RJ)RJ)RJ)RJ)T;amsn-0.98.9/utils/pixmapbutton/checkdisabledpress.gif0000644000175000017500000000033010260277125022572 0ustar billiobbilliobGIF89a ),)JMJRURkikkmk! ,U'di悬,$Pbݤخ1~dp ((QJV#5PHjP!;amsn-0.98.9/utils/pixmapbutton/checkhover.gif0000644000175000017500000000016110260277125021073 0ustar billiobbilliobGIF89aX!,6xNIhGD!19*hK:Ҋ㽁aHJi:;amsn-0.98.9/utils/pixmapbutton/radiohoverpress.gif0000644000175000017500000000054410260277125022176 0ustar billiobbilliobGIF89a )()),)141989BEBJMJRUR{y{X!,m۶m۶m۶m۶m۶m۶m۶۶m۶m[(T۶m۶m[@RVm۶m)ԕi)ѶmV)h98T۶mOd5F$M϶mL, l۶)VF0!ʶmbiHBAhmLS@6=۶miB )նm)iiJm۶m[LMJm۶mmգ(Sm۶m۶m۶m۶m۶۶m۶m۶m۶m۶;amsn-0.98.9/utils/pixmapbutton/button_hover.gif0000644000175000017500000000202110260274201021455 0ustar billiobbilliobGIF89a7]yy}}"**3"*;*D;DLUU;]DUD]]LfUfoowU]wo]fĈđęfɈɑəΈwΙoΡ֑֫ڙޙڻ޳޻!Created with The GIMP! ,7]WE9+'++*',>P\]W#A]E1?HDDGHýľGB7(&S7UVXUVXH .,拸s"LT(Cq?s$Q #ҖAƂ ]sڴXaM+)2em&l:N ~1K2b4 WXR뽆V|P&M$'SV4kө[F=u h-6mټc wāw ϵf<:qc[w[7S϶zxyⴇ gݼF=@_|zi멟^ޤ"Pvv^mpep }e|5` ( i(j7_%lF@ I@]` Jg^z T W`)NeRRSRNI:'R,ٙhl9 E @ vBAy Az' hNpBY|;amsn-0.98.9/utils/pixmapbutton/check.gif0000644000175000017500000000016110260277125020027 0ustar billiobbilliobGIF89a! ,6x.Iih`!D19*hK:Ҋ=AaHJi:;amsn-0.98.9/utils/pixmapbutton/button.gif0000644000175000017500000000203410260274201020256 0ustar billiobbilliobGIF89a7luyuuy}y}}!))!1)9)9BB9BJJRR9RRBZBZZJccRckksRZs{{kZ{cc{ÄÌ{ÔkDŽsǔkǜόϥ{ϥӔ۔הӵ׭ߜۜ׵ߌۥߜ߽۽,7llkcQC40/4244/02/045G[hlc+"MlQ&;JTPPSTOSSKA1 .i_AabdabdT(8)>w eĆ*llPOB ɀt7R侒<2ِ JCHO̓5iJf̈p];;T()y4e>LNÑÏh&\ iH>K}cC*=zGOyw = `UĆ&:z0cVƔ#R6Zŀ9Yh-l-\f뮽[ ޷uΝ,!h{xÛ } # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. Neither the name of the Growl project nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. package require growl set curdir [file dirname [info script]] growl register ExampleTclApp "warning error" ${curdir}/pwrdLogo75.gif growl post warning "TclGrowl launched" "Hi there!" after 10000 growl post error "TclGrowl quitting" "Bye!" \ ${curdir}/../../images/icons/growl-icon-(png).png amsn-0.98.9/utils/macosx/growl1.0/pkgIndex.tcl0000644000175000017500000000103110154100537020640 0ustar billiobbilliob# Tcl package index file, version 1.1 # This file is generated by the "pkg_mkIndex" command # and sourced either when an application starts up or # by a "package unknown" script. It invokes the # "package ifneeded" command to set up package-related # information so that packages will be loaded automatically # in response to "package require" commands. When this # script is sourced, the variable $dir must contain the # full path name of this file's directory. package ifneeded growl 1.0 [list load [file join $dir libgrowl.dylib]] amsn-0.98.9/utils/macosx/growl1.0/src/0000755000175000017500000000000011757711630017173 5ustar billiobbilliobamsn-0.98.9/utils/macosx/growl1.0/src/GrowlPathway.h0000644000175000017500000000130010737553652021773 0ustar billiobbilliob// // GrowlNotificationServer.h // Growl // // Created by Ingmar Stein on 15.11.04. // Copyright 2004-2005 The Growl Project. All rights reserved. // // This file is under the BSD License, refer to License.txt for details #import @protocol GrowlNotificationProtocol - (oneway void) registerApplicationWithDictionary:(bycopy NSDictionary *)dict; - (oneway void) postNotificationWithDictionary:(bycopy NSDictionary *)notification; - (bycopy NSString *) growlVersion; @end @interface GrowlPathway : NSObject { } - (void) registerApplicationWithDictionary:(NSDictionary *)dict; - (void) postNotificationWithDictionary:(NSDictionary *)dict; @end amsn-0.98.9/utils/macosx/growl1.0/src/GrowlDefines.h0000644000175000017500000003255110737553652021747 0ustar billiobbilliob// // GrowlDefines.h // #ifndef _GROWLDEFINES_H #define _GROWLDEFINES_H #ifdef __OBJC__ #define XSTR(x) (@x) #define STRING NSString * #else #define XSTR CFSTR #define STRING CFStringRef #endif /*! @header GrowlDefines.h * @abstract Defines all the notification keys. * @discussion Defines all the keys used for registration with Growl and for * Growl notifications. * * Most applications should use the functions or methods of Growl.framework * instead of posting notifications such as those described here. * @updated 2004-01-25 */ // UserInfo Keys for Registration #pragma mark UserInfo Keys for Registration /*! @group Registration userInfo keys */ /* @abstract Keys for the userInfo dictionary of a GROWL_APP_REGISTRATION distributed notification. * @discussion The values of these keys describe the application and the * notifications it may post. * * Your application must register with Growl before it can post Growl * notifications (and have them not be ignored). However, as of Growl 0.6, * posting GROWL_APP_REGISTRATION notifications directly is no longer the * preferred way to register your application. Your application should instead * use Growl.framework's delegate system. * See +[GrowlApplicationBridge setGrowlDelegate:] or Growl_SetDelegate for * more information. */ /*! @defined GROWL_APP_NAME * @abstract The name of your application. * @discussion The name of your application. This should remain stable between * different versions and incarnations of your application. * For example, "SurfWriter" is a good app name, whereas "SurfWriter 2.0" and * "SurfWriter Lite" are not. */ #define GROWL_APP_NAME XSTR("ApplicationName") /*! @defined GROWL_APP_ICON * @abstract The image data for your application's icon. * @discussion Image data representing your application's icon. This may be * superimposed on a notification icon as a badge, used as the notification * icon when a notification-specific icon is not supplied, or ignored * altogether, depending on the display. Must be in a format supported by * NSImage, such as TIFF, PNG, GIF, JPEG, BMP, PICT, or PDF. * * Optional. Not supported by all display plugins. */ #define GROWL_APP_ICON XSTR("ApplicationIcon") /*! @defined GROWL_NOTIFICATIONS_DEFAULT * @abstract The array of notifications to turn on by default. * @discussion These are the names of the notifications that should be enabled * by default when your application registers for the first time. If your * application reregisters, Growl will look here for any new notification * names found in GROWL_NOTIFICATIONS_ALL, but ignore any others. */ #define GROWL_NOTIFICATIONS_DEFAULT XSTR("DefaultNotifications") /*! @defined GROWL_NOTIFICATIONS_ALL * @abstract The array of all notifications your application can send. * @discussion These are the names of all of the notifications that your * application may post. See GROWL_NOTIFICATION_NAME for a discussion of good * notification names. */ #define GROWL_NOTIFICATIONS_ALL XSTR("AllNotifications") /*! @defined GROWL_TICKET_VERSION * @abstract The version of your registration ticket. * @discussion Include this key in a ticket plist file that you put in your * application bundle for auto-discovery. The current ticket version is 1. */ #define GROWL_TICKET_VERSION XSTR("TicketVersion") // UserInfo Keys for Notifications #pragma mark UserInfo Keys for Notifications /*! @group Notification userInfo keys */ /* @abstract Keys for the userInfo dictionary of a GROWL_NOTIFICATION distributed notification. * @discussion The values of these keys describe the content of a Growl * notification. * * Not all of these keys are supported by all displays. Only the name, title, * and description of a notification are universal. Most of the built-in * displays do support all of these keys, and most other visual displays * probably will also. But, as of 0.6, the Log, MailMe, and Speech displays * support only textual data. */ /*! @defined GROWL_NOTIFICATION_NAME * @abstract The name of the notification. * @discussion The name of the notification. This should be human-readable, as * it's shown in the prefpane, in the list of notifications your application * supports. */ #define GROWL_NOTIFICATION_NAME XSTR("NotificationName") /*! @defined GROWL_NOTIFICATION_TITLE * @abstract The title to display in the notification. * @discussion The title of the notification. Should be very brief. * The title usually says what happened, e.g. "Download complete". */ #define GROWL_NOTIFICATION_TITLE XSTR("NotificationTitle") /*! @defined GROWL_NOTIFICATION_DESCRIPTION * @abstract The description to display in the notification. * @discussion The description should be longer and more verbose than the title. * The description usually tells the subject of the action, * e.g. "Growl-0.6.dmg downloaded in 5.02 minutes". */ #define GROWL_NOTIFICATION_DESCRIPTION XSTR("NotificationDescription") /*! @defined GROWL_NOTIFICATION_ICON * @discussion Image data for the notification icon. Must be in a format * supported by NSImage, such as TIFF, PNG, GIF, JPEG, BMP, PICT, or PDF. * * Optional. Not supported by all display plugins. */ #define GROWL_NOTIFICATION_ICON XSTR("NotificationIcon") /*! @defined GROWL_NOTIFICATION_APP_ICON * @discussion Image data for the application icon, in case GROWL_APP_ICON does * not apply for some reason. Must be in a format supported by NSImage, such * as TIFF, PNG, GIF, JPEG, BMP, PICT, or PDF. * * Optional. Not supported by all display plugins. */ #define GROWL_NOTIFICATION_APP_ICON XSTR("NotificationAppIcon") /*! @defined GROWL_NOTIFICATION_PRIORITY * @discussion The priority of the notification as an integer number from * -2 to +2 (+2 being highest). * * Optional. Not supported by all display plugins. */ #define GROWL_NOTIFICATION_PRIORITY XSTR("NotificationPriority") /*! @defined GROWL_NOTIFICATION_STICKY * @discussion A Boolean number controlling whether the notification is sticky. * * Optional. Not supported by all display plugins. */ #define GROWL_NOTIFICATION_STICKY XSTR("NotificationSticky") /*! @defined GROWL_NOTIFICATION_CLICK_CONTEXT * @abstract Identifies which notification was clicked. * @discussion An identifier for the notification for clicking purposes. * * This will be passed back to the application when the notification is * clicked. It must be plist-encodable (a data, dictionary, array, number, or * string object), and it should be unique for each notification you post. * A good click context would be a UUID string returned by NSProcessInfo or * CFUUID. * * Optional. Not supported by all display plugins. */ #define GROWL_NOTIFICATION_CLICK_CONTEXT XSTR("NotificationClickContext") /*! @defined GROWL_DISPLAY_PLUGIN * @discussion The name of a display plugin which should be used for this notification. * Optional. If this key is not set or the specified display plugin does not * exist, the display plugin stored in the application ticket is used. This key * allows applications to use different default display plugins for their * notifications. The user can still override those settings in the preference * pane. */ #define GROWL_DISPLAY_PLUGIN XSTR("NotificationDisplayPlugin") /*! @defined GROWL_NOTIFICATION_IDENTIFIER * @abstract An identifier for the notification for coalescing purposes. * Notifications with the same identifier fall into the same class; only * the last notification of a class is displayed on the screen. If a * notification of the same class is currently being displayed, it is * replaced by this notification. * * Optional. Not supported by all display plugins. */ #define GROWL_NOTIFICATION_IDENTIFIER XSTR("GrowlNotificationIdentifier") /*! @defined GROWL_APP_PID * @abstract The process identifier of the process which sends this * notification. If this field is set, the application will only receive * clicked and timed out notifications which originate from this process. * * Optional. */ #define GROWL_APP_PID XSTR("ApplicationPID") // Notifications #pragma mark Notifications /*! @group Notification names */ /* @abstract Names of distributed notifications used by Growl. * @discussion These are notifications used by applications (directly or * indirectly) to interact with Growl, and by Growl for interaction between * its components. * * Most of these should no longer be used in Growl 0.6 and later, in favor of * Growl.framework's GrowlApplicationBridge APIs. */ /*! @defined GROWL_APP_REGISTRATION * @abstract The distributed notification for registering your application. * @discussion This is the name of the distributed notification that can be * used to register applications with Growl. * * The userInfo dictionary for this notification can contain these keys: *
    *
  • GROWL_APP_NAME
  • *
  • GROWL_APP_ICON
  • *
  • GROWL_NOTIFICATIONS_ALL
  • *
  • GROWL_NOTIFICATIONS_DEFAULT
  • *
* * No longer recommended as of Growl 0.6. An alternate method of registering * is to use Growl.framework's delegate system. * See +[GrowlApplicationBridge setGrowlDelegate:] or Growl_SetDelegate for * more information. */ #define GROWL_APP_REGISTRATION XSTR("GrowlApplicationRegistrationNotification") /*! @defined GROWL_APP_REGISTRATION_CONF * @abstract The distributed notification for confirming registration. * @discussion The name of the distributed notification sent to confirm the * registration. Used by the Growl preference pane. Your application probably * does not need to use this notification. */ #define GROWL_APP_REGISTRATION_CONF XSTR("GrowlApplicationRegistrationConfirmationNotification") /*! @defined GROWL_NOTIFICATION * @abstract The distributed notification for Growl notifications. * @discussion This is what it all comes down to. This is the name of the * distributed notification that your application posts to actually send a * Growl notification. * * The userInfo dictionary for this notification can contain these keys: *
    *
  • GROWL_NOTIFICATION_NAME (required)
  • *
  • GROWL_NOTIFICATION_TITLE (required)
  • *
  • GROWL_NOTIFICATION_DESCRIPTION (required)
  • *
  • GROWL_NOTIFICATION_ICON
  • *
  • GROWL_NOTIFICATION_APP_ICON
  • *
  • GROWL_NOTIFICATION_PRIORITY
  • *
  • GROWL_NOTIFICATION_STICKY
  • *
  • GROWL_NOTIFICATION_CLICK_CONTEXT
  • *
  • GROWL_APP_NAME (required)
  • *
* * No longer recommended as of Growl 0.6. Three alternate methods of posting * notifications are +[GrowlApplicationBridge notifyWithTitle:description:notificationName:iconData:priority:isSticky:clickContext:], * Growl_NotifyWithTitleDescriptionNameIconPriorityStickyClickContext, and * Growl_PostNotification. */ #define GROWL_NOTIFICATION XSTR("GrowlNotification") /*! @defined GROWL_SHUTDOWN * @abstract The distributed notification name that tells Growl to shutdown. * @discussion The Growl preference pane posts this notification when the * "Stop Growl" button is clicked. */ #define GROWL_SHUTDOWN XSTR("GrowlShutdown") /*! @defined GROWL_PING * @abstract A distributed notification to check whether Growl is running. * @discussion This is used by the Growl preference pane. If it receives a * GROWL_PONG, the preference pane takes this to mean that Growl is running. */ #define GROWL_PING XSTR("Honey, Mind Taking Out The Trash") /*! @defined GROWL_PONG * @abstract The distributed notification sent in reply to GROWL_PING. * @discussion GrowlHelperApp posts this in reply to GROWL_PING. */ #define GROWL_PONG XSTR("What Do You Want From Me, Woman") /*! @defined GROWL_IS_READY * @abstract The distributed notification sent when Growl starts up. * @discussion GrowlHelperApp posts this when it has begin listening on all of * its sources for new notifications. GrowlApplicationBridge (in * Growl.framework), upon receiving this notification, reregisters using the * registration dictionary supplied by its delegate. */ #define GROWL_IS_READY XSTR("Lend Me Some Sugar; I Am Your Neighbor!") /*! @defined GROWL_NOTIFICATION_CLICKED * @abstract The distributed notification sent when a supported notification is clicked. * @discussion When a Growl notification with a click context is clicked on by * the user, Growl posts this distributed notification. * The GrowlApplicationBridge responds to this notification by calling a * callback in its delegate. */ #define GROWL_NOTIFICATION_CLICKED XSTR("GrowlClicked!") #define GROWL_NOTIFICATION_TIMED_OUT XSTR("GrowlTimedOut!") /*! @group Other symbols */ /* Symbols which don't fit into any of the other categories. */ /*! @defined GROWL_KEY_CLICKED_CONTEXT * @abstract Used internally as the key for the clickedContext passed over DNC. * @discussion This key is used in GROWL_NOTIFICATION_CLICKED, and contains the * click context that was supplied in the original notification. */ #define GROWL_KEY_CLICKED_CONTEXT XSTR("ClickedContext") /*! @defined GROWL_REG_DICT_EXTENSION * @abstract The filename extension for registration dictionaries. * @discussion The GrowlApplicationBridge in Growl.framework registers with * Growl by creating a file with the extension of .(GROWL_REG_DICT_EXTENSION) * and opening it in the GrowlHelperApp. This happens whether or not Growl is * running; if it was stopped, it quits immediately without listening for * notifications. */ #define GROWL_REG_DICT_EXTENSION XSTR("growlRegDict") #endif //ndef _GROWLDEFINES_H amsn-0.98.9/utils/macosx/growl1.0/src/GrowlDefinesInternal.h0000644000175000017500000003562110737553652023445 0ustar billiobbilliob// // GrowlDefinesInternal.h // Growl // // Created by Karl Adam on Mon May 17 2004. // Copyright (c) 2004 the Growl Project. All rights reserved. // #ifndef _GROWL_GROWLDEFINESINTERNAL_H #define _GROWL_GROWLDEFINESINTERNAL_H #include #ifdef __OBJC__ #define XSTR(x) (@x) #else /* !__OBJC__ */ #define XSTR CFSTR #endif /* __OBJC__ */ /*! @header GrowlDefinesInternal.h * @abstract Defines internal Growl macros and types. * @ignore ATTRIBUTE_PACKED * @discussion These constants are used both by GrowlHelperApp and by plug-ins. * * Notification keys (used in GrowlHelperApp, in GrowlApplicationBridge, and * by applications that don't use GrowlApplicationBridge) are defined in * GrowlDefines.h. */ /*! @defined GROWL_TCP_PORT * @abstract The TCP listen port for Growl notification servers. */ #define GROWL_TCP_PORT 23052 /*! @defined GROWL_UDP_PORT * @abstract The UDP listen port for Growl notification servers. */ #define GROWL_UDP_PORT 9887 /*! @defined GROWL_PROTOCOL_VERSION * @abstract The current version of the Growl network-notifications protocol (without encryption). */ #define GROWL_PROTOCOL_VERSION 1 /*! @defined GROWL_PROTOCOL_VERSION_AES128 * @abstract The current version of the Growl network-notifications protocol (with AES-128 encryption). */ #define GROWL_PROTOCOL_VERSION_AES128 2 /*! @defined GROWL_TYPE_REGISTRATION * @abstract The packet type of registration packets with MD5 authentication. */ #define GROWL_TYPE_REGISTRATION 0 /*! @defined GROWL_TYPE_NOTIFICATION * @abstract The packet type of notification packets with MD5 authentication. */ #define GROWL_TYPE_NOTIFICATION 1 /*! @defined GROWL_TYPE_REGISTRATION_SHA256 * @abstract The packet type of registration packets with SHA-256 authentication. */ #define GROWL_TYPE_REGISTRATION_SHA256 2 /*! @defined GROWL_TYPE_NOTIFICATION_SHA256 * @abstract The packet type of notification packets with SHA-256 authentication. */ #define GROWL_TYPE_NOTIFICATION_SHA256 3 /*! @defined GROWL_TYPE_REGISTRATION_NOAUTH * @abstract The packet type of registration packets without authentication. */ #define GROWL_TYPE_REGISTRATION_NOAUTH 4 /*! @defined GROWL_TYPE_NOTIFICATION_NOAUTH * @abstract The packet type of notification packets without authentication. */ #define GROWL_TYPE_NOTIFICATION_NOAUTH 5 #define ATTRIBUTE_PACKED __attribute((packed)) /*! @struct GrowlNetworkPacket * @abstract This struct is a header common to all incoming Growl network * packets which identifies the type and version of the packet. */ struct GrowlNetworkPacket { unsigned char version; unsigned char type; } ATTRIBUTE_PACKED; /*! * @struct GrowlNetworkRegistration * @abstract The format of a registration packet. * @discussion A Growl client that wants to register with a Growl server sends * a packet in this format. * @field common The Growl packet header. * @field appNameLen The name of the application that is registering. * @field numAllNotifications The number of notifications in the list. * @field numDefaultNotifications The number of notifications in the list that are enabled by default. * @field data Variable-sized data. */ struct GrowlNetworkRegistration { struct GrowlNetworkPacket common; /* This name is used both internally and in the Growl * preferences. * * The application name should remain stable between different versions * and incarnations of your application. * For example, "SurfWriter" is a good app name, whereas "SurfWriter 2.0" * and "SurfWriter Lite" are not. * * In addition to being unsigned, the application name length is in * network byte order. */ unsigned short appNameLen; /* These names are used both internally and in the Growl * preferences. For this reason, they should be human-readable. */ unsigned char numAllNotifications; unsigned char numDefaultNotifications; /* The variable-sized data of a registration is: * - The application name, in UTF-8 encoding, for appNameLen bytes. * - The list of all notification names. * - The list of default notifications, as 8-bit unsigned indices into the list of all notifications. * - The MD5/SHA256 checksum of all the data preceding the checksum. * * Each notification name is encoded as: * - Length: two bytes, unsigned, network byte order. * - Name: As many bytes of UTF-8-encoded text as the length says. * And there are numAllNotifications of these. */ unsigned char data[]; } ATTRIBUTE_PACKED; /*! * @struct GrowlNetworkNotification * @abstract The format of a notification packet. * @discussion A Growl client that wants to post a notification to a Growl * server sends a packet in this format. * @field common The Growl packet header. * @field flags The priority number and the sticky bit. * @field nameLen The length of the notification name. * @field titleLen The length of the notification title. * @field descriptionLen The length of the notification description. * @field appNameLen The length of the application name. * @field data Variable-sized data. */ struct GrowlNetworkNotification { struct GrowlNetworkPacket common; /*! * @struct GrowlNetworkNotificationFlags * @abstract Various flags. * @discussion This 16-bit packed structure contains the priority as a * signed 3-bit integer from -2 to +2, and the sticky flag as a single bit. * The high 12 bits of the structure are reserved for future use. * @field reserved reserved for future use. * @field priority the priority as a signed 3-bit integer from -2 to +2. * @field sticky the sticky flag. */ struct GrowlNetworkNotificationFlags { unsigned reserved: 12; signed priority: 3; unsigned sticky: 1; } ATTRIBUTE_PACKED flags; //size = 16 (12 + 3 + 1) /* In addition to being unsigned, the notification name length * is in network byte order. */ unsigned short nameLen; /* @discussion In addition to being unsigned, the title length is in * network byte order. */ unsigned short titleLen; /* In addition to being unsigned, the description length is in * network byte order. */ unsigned short descriptionLen; /* In addition to being unsigned, the application name length * is in network byte order. */ unsigned short appNameLen; /* The variable-sized data of a notification is: * - Notification name, in UTF-8 encoding, for nameLen bytes. * - Title, in UTF-8 encoding, for titleLen bytes. * - Description, in UTF-8 encoding, for descriptionLen bytes. * - Application name, in UTF-8 encoding, for appNameLen bytes. * - The MD5/SHA256 checksum of all the data preceding the checksum. */ unsigned char data[]; } ATTRIBUTE_PACKED; /*! @defined GrowlEnabledKey * @abstract Preference key controlling whether Growl is enabled. * @discussion If this is false, then when GrowlHelperApp is launched to open * a Growl registration dictionary file, GrowlHelperApp will quit when it has * finished processing the file instead of listening for notifications. */ #define GrowlEnabledKey XSTR("GrowlEnabled") /*! @defined GROWL_SCREENSHOT_MODE * @abstract Preference and notification key controlling whether to save a screenshot of the notification. * @discussion This is for GHA's private usage. If your application puts this * key into a notification dictionary, GHA will clobber it. This key is only * allowed in the notification dictionaries GHA passes to displays. * * If this key contains an object whose boolValue is not NO, the display is * asked to save a screenshot of the notification to * ~/Library/Application\ Support/Growl/Screenshots. */ #define GROWL_SCREENSHOT_MODE XSTR("ScreenshotMode") /*! @defined GROWL_APP_LOCATION * @abstract The location of this application. * @discussion Contains either the POSIX path to the application, or a file-data dictionary (as used by the Dock). * contains the file's alias record and its pathname. */ #define GROWL_APP_LOCATION XSTR("AppLocation") #endif //ndef _GROWL_GROWLDEFINESINTERNAL_H /* --- These following macros are intended for plug-ins --- */ /*Since anything that needs the include guards won't be using these macros, we * don't need the include guards here. */ #ifdef __OBJC__ /*! @function SYNCHRONIZE_GROWL_PREFS * @abstract Synchronizes Growl prefs so they're up-to-date. * @discussion This macro is intended for use by GrowlHelperApp and by * plug-ins (when the prefpane is selected). */ #define SYNCHRONIZE_GROWL_PREFS() CFPreferencesAppSynchronize(CFSTR("com.Growl.GrowlHelperApp")) /*! @function UPDATE_GROWL_PREFS * @abstract Tells GrowlHelperApp to update its prefs. * @discussion This macro is intended for use by plug-ins. * It sends a notification to tell GrowlHelperApp to update its preferences. */ #define UPDATE_GROWL_PREFS() do { \ SYNCHRONIZE_GROWL_PREFS(); \ NSNumber *pid = [[NSNumber alloc] initWithInt:[[NSProcessInfo processInfo] processIdentifier]];\ NSDictionary *userInfo = [[NSDictionary alloc] initWithObjectsAndKeys:\ pid, @"pid",\ nil];\ [pid release];\ [[NSDistributedNotificationCenter defaultCenter]\ postNotificationName:@"GrowlPreferencesChanged" object:@"GrowlUserDefaults" userInfo:userInfo];\ [userInfo release];\ } while(0) /*! @function READ_GROWL_PREF_VALUE * @abstract Reads the given pref value from the plug-in's preferences. * @discussion This macro is intended for use by plug-ins. It reads the value for the * given key from the plug-in's preferences (which are stored in a dictionary inside of * GrowlHelperApp's prefs). * @param key The preference key to read the value of. * @param domain The bundle ID of the plug-in. * @param type The type of the result expected. * @param result A pointer to an id. Set to the value if exists, left unchanged if not. * * If the value is set, you are responsible for releasing it. */ #define READ_GROWL_PREF_VALUE(key, domain, type, result) do {\ CFDictionaryRef prefs = (CFDictionaryRef)CFPreferencesCopyAppValue((CFStringRef)domain, \ CFSTR("com.Growl.GrowlHelperApp")); \ if (prefs) {\ if (CFDictionaryContainsKey(prefs, key)) {\ *result = (type)CFDictionaryGetValue(prefs, key); \ CFRetain(*result); \ } \ CFRelease(prefs); } \ } while(0) /*! @function WRITE_GROWL_PREF_VALUE * @abstract Writes the given pref value to the plug-in's preferences. * @discussion This macro is intended for use by plug-ins. It writes the given * value to the plug-in's preferences. * @param key The preference key to write the value of. * @param value The value to write to the preferences. It should be either a * CoreFoundation type or toll-free bridged with one. * @param domain The bundle ID of the plug-in. */ #define WRITE_GROWL_PREF_VALUE(key, value, domain) do {\ CFDictionaryRef staticPrefs = (CFDictionaryRef)CFPreferencesCopyAppValue((CFStringRef)domain, \ CFSTR("com.Growl.GrowlHelperApp")); \ CFMutableDictionaryRef prefs; \ if (staticPrefs == NULL) {\ prefs = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); \ } else {\ prefs = CFDictionaryCreateMutableCopy(NULL, 0, staticPrefs); \ CFRelease(staticPrefs); \ }\ CFDictionarySetValue(prefs, key, value); \ CFPreferencesSetAppValue((CFStringRef)domain, prefs, CFSTR("com.Growl.GrowlHelperApp")); \ CFRelease(prefs); } while(0) /*! @function READ_GROWL_PREF_BOOL * @abstract Reads the given Boolean from the plug-in's preferences. * @discussion This is a wrapper around READ_GROWL_PREF_VALUE() intended for * use with Booleans. * @param key The preference key to read the Boolean from. * @param domain The bundle ID of the plug-in. * @param result A pointer to a Boolean type. Left unchanged if the value doesn't exist. */ #define READ_GROWL_PREF_BOOL(key, domain, result) do {\ CFBooleanRef boolValue = NULL; \ READ_GROWL_PREF_VALUE(key, domain, CFBooleanRef, &boolValue); \ if (boolValue) {\ *result = CFBooleanGetValue(boolValue); \ CFRelease(boolValue); \ } } while(0) /*! @function WRITE_GROWL_PREF_BOOL * @abstract Writes the given Boolean to the plug-in's preferences. * @discussion This is a wrapper around WRITE_GROWL_PREF_VALUE() intended for * use with Booleans. * @param key The preference key to write the Boolean for. * @param value The Boolean value to write to the preferences. * @param domain The bundle ID of the plug-in. */ #define WRITE_GROWL_PREF_BOOL(key, value, domain) do {\ CFBooleanRef boolValue; \ if (value) {\ boolValue = kCFBooleanTrue; \ } else {\ boolValue = kCFBooleanFalse; \ }\ WRITE_GROWL_PREF_VALUE(key, boolValue, domain); } while(0) /*! @function READ_GROWL_PREF_INT * @abstract Reads the given integer from the plug-in's preferences. * @discussion This is a wrapper around READ_GROWL_PREF_VALUE() intended for * use with integers. * @param key The preference key to read the integer from. * @param domain The bundle ID of the plug-in. * @param result A pointer to an integer. Leaves unchanged if the value doesn't exist. */ #define READ_GROWL_PREF_INT(key, domain, result) do {\ CFNumberRef intValue = NULL; \ READ_GROWL_PREF_VALUE(key, domain, CFNumberRef, &intValue); \ if (intValue) {\ CFNumberGetValue(intValue, kCFNumberIntType, result); \ CFRelease(intValue); \ } } while(0) /*! @function WRITE_GROWL_PREF_INT * @abstract Writes the given integer to the plug-in's preferences. * @discussion This is a wrapper around WRITE_GROWL_PREF_VALUE() intended for * use with integers. * @param key The preference key to write the integer for. * @param value The integer value to write to the preferences. * @param domain The bundle ID of the plug-in. */ #define WRITE_GROWL_PREF_INT(key, value, domain) do {\ CFNumberRef intValue = CFNumberCreate(NULL, kCFNumberIntType, &value); \ WRITE_GROWL_PREF_VALUE(key, intValue, domain); \ CFRelease(intValue); } while(0) /*! @function READ_GROWL_PREF_FLOAT * @abstract Reads the given float from the plug-in's preferences. * @discussion This is a wrapper around READ_GROWL_PREF_VALUE() intended for * use with floats. * @param key The preference key to read the float from. * @param domain The bundle ID of the plug-in. * @param result A pointer to a float. Leaves unchanged if the value doesn't exist. */ #define READ_GROWL_PREF_FLOAT(key, domain, result) do {\ CFNumberRef floatValue = NULL; \ READ_GROWL_PREF_VALUE(key, domain, CFNumberRef, &floatValue); \ if (floatValue) {\ CFNumberGetValue(floatValue, kCFNumberFloatType, result); \ CFRelease(floatValue); \ } } while(0) /*! @function WRITE_GROWL_PREF_FLOAT * @abstract Writes the given float to the plug-in's preferences. * @discussion This is a wrapper around WRITE_GROWL_PREF_VALUE() intended for * use with floats. * @param key The preference key to write the float for. * @param value The float value to write to the preferences. * @param domain The bundle ID of the plug-in. */ #define WRITE_GROWL_PREF_FLOAT(key, value, domain) do {\ CFNumberRef floatValue = CFNumberCreate(NULL, kCFNumberFloatType, &value); \ WRITE_GROWL_PREF_VALUE(key, floatValue, domain); \ CFRelease(floatValue); } while(0) #endif /* __OBJC__ */ amsn-0.98.9/utils/macosx/growl1.0/src/TclGrowler.h0000644000175000017500000000362010737553652021436 0ustar billiobbilliob/* * TclGrowler.h * * Copyright (c) 2005, Toby Peterson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Growl project nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef __TclGrowler_h__ #define __TclGrowler_h__ @interface TclGrowler : NSObject { NSString *appName; NSData *appIcon; NSArray *allNotifications; } - (id)initWithName:(NSString *)aName notifications:(NSArray *)notes icon:(NSImage *)aIcon; @end #endif /* __TclGrowler_h__ */ amsn-0.98.9/utils/macosx/growl1.0/src/Rules.mk0000644000175000017500000000103710747207165020620 0ustar billiobbilliobTARGETS-growl = $(macosx_dir)/growl1.0/src/libgrowl.dylib OBJS-growl = $(macosx_dir)/growl1.0/src/GrowlPathUtil.o $(macosx_dir)/growl1.0/src/GrowlApplicationBridge.o $(macosx_dir)/growl1.0/src/CFGrowlAdditions.o $(macosx_dir)/growl1.0/src/TclGrowler.o $(macosx_dir)/growl1.0/src/growl.o $(macosx_dir)/growl1.0/src/NSURLAdditions.o CFLAGS += --std=c99 LDFLAGS += -framework Cocoa all:: $(TARGETS-growl) $(TARGETS-growl): $(OBJS-growl) @$(echo_link_so) @$(link_so) clean:: clean-growl clean-growl:: rm -f $(OBJS-growl) $(TARGET-growl) amsn-0.98.9/utils/macosx/growl1.0/src/GrowlPathUtil.m0000644000175000017500000001330210737553652022122 0ustar billiobbilliob// // GrowlPathUtil.m // Growl // // Created by Ingmar Stein on 17.04.05. // Copyright 2005 The Growl Project. All rights reserved. // // This file is under the BSD License, refer to License.txt for details #import "GrowlPathUtil.h" #define HelperAppBundleIdentifier @"com.Growl.GrowlHelperApp" #define GROWL_PREFPANE_BUNDLE_IDENTIFIER @"com.growl.prefpanel" #define GROWL_PREFPANE_NAME @"Growl.prefPane" #define PREFERENCE_PANES_SUBFOLDER_OF_LIBRARY @"PreferencePanes" #define PREFERENCE_PANE_EXTENSION @"prefPane" static NSBundle *helperAppBundle; static NSBundle *prefPaneBundle; @implementation GrowlPathUtil + (NSBundle *) growlPrefPaneBundle { NSArray *librarySearchPaths; NSString *path; NSString *bundleIdentifier; NSEnumerator *searchPathEnumerator; NSBundle *bundle; if (prefPaneBundle) { return prefPaneBundle; } static const unsigned bundleIDComparisonFlags = NSCaseInsensitiveSearch | NSBackwardsSearch; //Find Library directories in all domains except /System (as of Panther, that's ~/Library, /Library, and /Network/Library) librarySearchPaths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSAllDomainsMask & ~NSSystemDomainMask, YES); /*First up, we'll have a look for Growl.prefPane, and if it exists, check * whether it is our prefPane. *This is much faster than having to enumerate all preference panes, and * can drop a significant amount of time off this code. */ searchPathEnumerator = [librarySearchPaths objectEnumerator]; while ((path = [searchPathEnumerator nextObject])) { path = [path stringByAppendingPathComponent:PREFERENCE_PANES_SUBFOLDER_OF_LIBRARY]; path = [path stringByAppendingPathComponent:GROWL_PREFPANE_NAME]; if ([[NSFileManager defaultManager] fileExistsAtPath:path]) { bundle = [NSBundle bundleWithPath:path]; if (bundle) { bundleIdentifier = [bundle bundleIdentifier]; if (bundleIdentifier && ([bundleIdentifier compare:GROWL_PREFPANE_BUNDLE_IDENTIFIER options:bundleIDComparisonFlags] == NSOrderedSame)) { prefPaneBundle = bundle; return prefPaneBundle; } } } } /*Enumerate all installed preference panes, looking for the Growl prefpane * bundle identifier and stopping when we find it. *Note that we check the bundle identifier because we should not insist * that the user not rename his preference pane files, although most users * of course will not. If the user wants to mutilate the Info.plist file * inside the bundle, he/she deserves to not have a working Growl * installation. */ searchPathEnumerator = [librarySearchPaths objectEnumerator]; while ((path = [searchPathEnumerator nextObject])) { NSString *bundlePath; NSDirectoryEnumerator *bundleEnum; path = [path stringByAppendingPathComponent:PREFERENCE_PANES_SUBFOLDER_OF_LIBRARY]; bundleEnum = [[NSFileManager defaultManager] enumeratorAtPath:path]; while ((bundlePath = [bundleEnum nextObject])) { if ([[bundlePath pathExtension] isEqualToString:PREFERENCE_PANE_EXTENSION]) { bundle = [NSBundle bundleWithPath:[path stringByAppendingPathComponent:bundlePath]]; if (bundle) { bundleIdentifier = [bundle bundleIdentifier]; if (bundleIdentifier && ([bundleIdentifier compare:GROWL_PREFPANE_BUNDLE_IDENTIFIER options:bundleIDComparisonFlags] == NSOrderedSame)) { prefPaneBundle = bundle; return prefPaneBundle; } } [bundleEnum skipDescendents]; } } } return nil; } #pragma mark - #pragma mark Important file-system objects + (NSBundle *) helperAppBundle { if (!helperAppBundle) { NSBundle *bundle = [NSBundle mainBundle]; if ([[bundle bundleIdentifier] isEqualToString:HelperAppBundleIdentifier]) { //we are running in GHA. helperAppBundle = bundle; } else { //look in the prefpane bundle. bundle = [NSBundle bundleForClass:[GrowlPathUtil class]]; if (![[bundle bundleIdentifier] isEqualToString:GROWL_PREFPANE_BUNDLE_IDENTIFIER]) { bundle = [GrowlPathUtil growlPrefPaneBundle]; } NSString *helperAppPath = [bundle pathForResource:@"GrowlHelperApp" ofType:@"app"]; helperAppBundle = [NSBundle bundleWithPath:helperAppPath]; } } return helperAppBundle; } + (NSString *) growlSupportDir { NSString *supportDir; NSArray *searchPath = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, /* expandTilde */ YES); supportDir = [searchPath objectAtIndex:0U]; supportDir = [supportDir stringByAppendingPathComponent:@"Application Support/Growl"]; return supportDir; } #pragma mark - + (NSString *) screenshotsDirectory { NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Application Support/Growl/Screenshots"]; [[NSFileManager defaultManager] createDirectoryAtPath:path attributes:nil]; return path; } + (NSString *) nextScreenshotName { NSFileManager *mgr = [NSFileManager defaultManager]; NSString *directory = [GrowlPathUtil screenshotsDirectory]; NSString *filename = nil; NSArray *origContents = [mgr directoryContentsAtPath:directory]; NSMutableSet *directoryContents = [[NSMutableSet alloc] initWithCapacity:[origContents count]]; NSEnumerator *filesEnum = [origContents objectEnumerator]; NSString *existingFilename; while ((existingFilename = [filesEnum nextObject])) { existingFilename = [directory stringByAppendingPathComponent:[existingFilename stringByDeletingPathExtension]]; [directoryContents addObject:existingFilename]; } for (unsigned long i = 1UL; i < ULONG_MAX; ++i) { [filename release]; filename = [[NSString alloc] initWithFormat:@"Screenshot %lu", i]; NSString *path = [directory stringByAppendingPathComponent:filename]; if (![directoryContents containsObject:path]) { break; } } [directoryContents release]; return [filename autorelease]; } @end amsn-0.98.9/utils/macosx/growl1.0/src/NSURLAdditions.m0000644000175000017500000000735410737553652022131 0ustar billiobbilliob// // NSURLAdditions.m // Growl // // Created by Karl Adam on Fri May 28 2004. // Copyright 2004-2005 The Growl Project. All rights reserved. // // This file is under the BSD License, refer to License.txt for details #import "NSURLAdditions.h" #define _CFURLAliasDataKey @"_CFURLAliasData" #define _CFURLStringKey @"_CFURLString" #define _CFURLStringTypeKey @"_CFURLStringType" @implementation NSURL (GrowlAdditions) //'alias' as in the Alias Manager. + (NSURL *) fileURLWithAliasData:(NSData *)aliasData { NSParameterAssert(aliasData != nil); NSURL *url = nil; AliasHandle alias = NULL; OSStatus err = PtrToHand([aliasData bytes], (Handle *)&alias, [aliasData length]); if (err != noErr) { NSLog(@"in +[NSURL(GrowlAdditions) fileURLWithAliasData:]: Could not allocate an alias handle from %u bytes of alias data (data follows) because PtrToHand returned %li\n%@", [aliasData length], aliasData, (long)err); } else { NSString *path = nil; /* * FSResolveAlias mounts disk images or network shares to resolve * aliases, thus we resort to FSCopyAliasInfo. */ err = FSCopyAliasInfo(alias, /* targetName */ NULL, /* volumeName */ NULL, (CFStringRef *)&path, /* whichInfo */ NULL, /* info */ NULL); if (err != noErr) { if (err != fnfErr) { //ignore file-not-found; it's harmless NSLog(@"in +[NSURL(GrowlAdditions) fileURLWithAliasData:]: Could not resolve alias (alias data follows) because FSResolveAlias returned %li - will try path\n%@", (long)err, aliasData); } } else if (path) { url = [NSURL fileURLWithPath:path]; } else { NSLog(@"in +[NSURL(GrowlAdditions) fileURLWithAliasData:]: FSCopyAliasInfo returned a nil path"); } } return url; } - (NSData *) aliasData { //return nil for non-file: URLs. if ([[self scheme] caseInsensitiveCompare:@"file"] != NSOrderedSame) return nil; NSData *aliasData = nil; FSRef fsref; if (CFURLGetFSRef((CFURLRef)self, &fsref)) { AliasHandle alias = NULL; OSStatus err = FSNewAlias(/*fromFile*/ NULL, &fsref, &alias); if (err != noErr) { NSLog(@"in -[NSURL(GrowlAdditions) dockDescription]: FSNewAlias for %@ returned %li", self, (long)err); } else { HLock((Handle)alias); aliasData = [NSData dataWithBytes:*alias length:GetHandleSize((Handle)alias)]; HUnlock((Handle)alias); DisposeHandle((Handle)alias); } } return aliasData; } //these are the type of external representations used by Dock.app. + (NSURL *) fileURLWithDockDescription:(NSDictionary *)dict { NSURL *URL = nil; NSString *path = [dict objectForKey:_CFURLStringKey]; NSData *aliasData = [dict objectForKey:_CFURLAliasDataKey]; if (aliasData) URL = [self fileURLWithAliasData:aliasData]; if (!URL) { if (path) { NSNumber *pathStyleNum = [dict objectForKey:_CFURLStringTypeKey]; CFURLPathStyle pathStyle = pathStyleNum ? [pathStyleNum intValue] : kCFURLPOSIXPathStyle; BOOL isDir = YES; BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir]; if (exists) { URL = [(NSURL *)CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (CFStringRef)path, pathStyle, /*isDirectory*/ isDir) autorelease]; } } } return URL; } - (NSDictionary *) dockDescription { NSMutableDictionary *dict; NSString *path = [self path]; NSData *aliasData = [self aliasData]; if (path || aliasData) { dict = [NSMutableDictionary dictionaryWithCapacity:3U]; if (path) { NSNumber *type = [[NSNumber alloc] initWithInt:kCFURLPOSIXPathStyle]; [dict setObject:path forKey:_CFURLStringKey]; [dict setObject:type forKey:_CFURLStringTypeKey]; [type release]; } if (aliasData) { [dict setObject:aliasData forKey:_CFURLAliasDataKey]; } } else { dict = nil; } return dict; } @end amsn-0.98.9/utils/macosx/growl1.0/src/ReadMe-Tcl.txt0000644000175000017500000000114410737553652021616 0ustar billiobbilliobAbout Tcl Support ----------------- The Tcl binding for Growl is a simple Objective-C extension which provides the Tcl command ``growl``. It supports notification icons and Unicode strings. Installation ------------ The following commands will install the binding into /Library/Tcl/growl1.0 :: cd Bindings/tcl sudo make install Usage ----- The following Tcl commands will post a basic Growl notification. Try it out! :: package require growl growl register appName "list of notification types" iconFilename growl post type title desc "optional icon" Author ------ Toby Peterson amsn-0.98.9/utils/macosx/growl1.0/src/GrowlPathUtil.h0000644000175000017500000000160510737553652022120 0ustar billiobbilliob// // GrowlPathUtil.h // Growl // // Created by Ingmar Stein on 17.04.05. // Copyright 2005 The Growl Project. All rights reserved. // // This file is under the BSD License, refer to License.txt for details #import @interface GrowlPathUtil : NSObject { } /*! * @method growlPrefPaneBundle * @abstract Returns the bundle containing Growl's PrefPane. * @discussion Searches all installed PrefPanes for the Growl PrefPane. * @result Returns an NSBundle if Growl's PrefPane is installed, nil otherwise */ + (NSBundle *) growlPrefPaneBundle; + (NSBundle *) helperAppBundle; + (NSString *) growlSupportDir; //the current screenshots directory: $HOME/Library/Application\ Support/Growl/Screenshots + (NSString *) screenshotsDirectory; //returns e.g. @"Screenshot 1". you append your own pathname extension; it is guaranteed not to exist. + (NSString *) nextScreenshotName; @end amsn-0.98.9/utils/macosx/growl1.0/src/NSURLAdditions.h0000644000175000017500000000116310737553652022114 0ustar billiobbilliob// // NSURLAdditions.h // Growl // // Created by Karl Adam on Fri May 28 2004. // Copyright 2004-2005 The Growl Project. All rights reserved. // // This file is under the BSD License, refer to License.txt for details #import @interface NSURL (GrowlAdditions) //'alias' as in the Alias Manager. + (NSURL *) fileURLWithAliasData:(NSData *)aliasData; - (NSData *) aliasData; //these are the type of external representations used by Dock.app. + (NSURL *) fileURLWithDockDescription:(NSDictionary *)dict; //-dockDescription returns nil for non-file: URLs. - (NSDictionary *) dockDescription; @end amsn-0.98.9/utils/macosx/growl1.0/src/CFGrowlAdditions.h0000644000175000017500000000754010737553652022521 0ustar billiobbilliob// // CFGrowlAdditions.h // Growl // // Created by Mac-arena the Bored Zo on Wed Jun 18 2004. // Copyright 2005 The Growl Project. // #ifdef __OBJC__ # define DATA_TYPE NSData * # define DICTIONARY_TYPE NSDictionary * # define STRING_TYPE NSString * # define ARRAY_TYPE NSArray * # define URL_TYPE NSURL * # define PLIST_TYPE NSObject * #else # define DATA_TYPE CFDataRef # define DICTIONARY_TYPE CFDictionaryRef # define STRING_TYPE CFStringRef # define ARRAY_TYPE CFArrayRef # define URL_TYPE CFURLRef # define PLIST_TYPE CFPropertyListRef #endif STRING_TYPE copyCurrentProcessName(void); URL_TYPE copyCurrentProcessURL(void); STRING_TYPE copyCurrentProcessPath(void); URL_TYPE copyTemporaryFolderURL(void); STRING_TYPE copyTemporaryFolderPath(void); DICTIONARY_TYPE createDockDescriptionForURL(URL_TYPE url); /* @function copyIconDataForPath * @param path The POSIX path to the file or folder whose icon you want. * @result The icon data, in IconFamily format (same as used in the 'icns' resource and in .icns files). You are responsible for releasing this object. */ DATA_TYPE copyIconDataForPath(STRING_TYPE path); /* @function copyIconDataForURL * @param URL The URL to the file or folder whose icon you want. * @result The icon data, in IconFamily format (same as used in the 'icns' resource and in .icns files). You are responsible for releasing this object. */ DATA_TYPE copyIconDataForURL(URL_TYPE URL); /* @function createURLByMakingDirectoryAtURLWithName * @abstract Create a directory. * @discussion This function has a useful side effect: if you pass * NULL for both parameters, this function will act basically as * CFURL version of getcwd(3). * * Also, for CF clients: the allocator used to create the returned URL will * be the allocator for the parent URL, the allocator for the name string, or * the default allocator, in that order of preference. * @param parent The directory in which to create the new directory. If this is NULL, the current working directory (as returned by getcwd(3)) will be used. * @param name The name of the directory you want to create. If this is NULL, the directory specified by the URL will be created. * @result The URL for the directory if it was successfully created (in which case, you are responsible for releasing this object); else, NULL. */ URL_TYPE createURLByMakingDirectoryAtURLWithName(URL_TYPE parent, STRING_TYPE name); /* @function createURLByCopyingFileFromURLToDirectoryURL * @param file The file to copy. * @param dest The folder to copy it to. * @result The copy. You are responsible for releasing this object. */ URL_TYPE createURLByCopyingFileFromURLToDirectoryURL(URL_TYPE file, URL_TYPE dest); /* @function createPropertyListFromURL * @abstract Reads a property list from the contents of an URL. * @discussion Creates a property list from the data at an URL (for example, a * file URL), and returns it. * @param file The file to read. * @param mutability A mutability-option constant indicating whether the property list (and possibly its contents) should be mutable. * @param outFormat If the property list is read successfully, this will point to the format of the property list. You may pass NULL if you are not interested in this information. If the property list is not read successfully, the value at this pointer will be left unchanged. * @param outErrorString If an error occurs, this will point to a string (which you are responsible for releasing) describing the error. You may pass NULL if you are not interested in this information. If no error occurs, the value at this pointer will be left unchanged. * @result The property list. You are responsible for releasing this object. */ PLIST_TYPE createPropertyListFromURL(URL_TYPE file, u_int32_t mutability, CFPropertyListFormat *outFormat, STRING_TYPE *outErrorString); amsn-0.98.9/utils/macosx/growl1.0/src/GrowlApplicationBridge.m0000644000175000017500000006164310737553652023763 0ustar billiobbilliob// // GrowlApplicationBridge.m // Growl // // Created by Evan Schoenberg on Wed Jun 16 2004. // Copyright 2004-2005 The Growl Project. All rights reserved. // #import "GrowlApplicationBridge.h" #ifdef GROWL_WITH_INSTALLER #import "GrowlInstallationPrompt.h" #import "GrowlVersionUtilities.h" #endif #import "NSURLAdditions.h" #import "CFGrowlAdditions.h" #import "GrowlDefinesInternal.h" #import "GrowlPathUtil.h" #import "GrowlPathway.h" #import #define PREFERENCE_PANES_SUBFOLDER_OF_LIBRARY @"PreferencePanes" #define PREFERENCE_PANE_EXTENSION @"prefPane" @interface GrowlApplicationBridge (PRIVATE) /*! * @method launchGrowlIfInstalled * @abstract Launches GrowlHelperApp. * @discussion Launches the GrowlHelperApp if it's not already running. * GROWL_IS_READY will be posted to the distributed notification center * once it is ready. * * Uses +_launchGrowlIfInstalledWithRegistrationDictionary:. * @result Returns YES if GrowlHelperApp began launching or was already running, NO if Growl isn't installed */ + (BOOL) launchGrowlIfInstalled; /*! * @method _launchGrowlIfInstalledWithRegistrationDictionary: * @abstract Launches GrowlHelperApp and registers. * @discussion Launches the GrowlHelperApp if it's not already running, and passes it a registration dictionary. * If Growl is turned on in the Growl prefpane, GROWL_IS_READY will be posted * to the distributed notification center when Growl is listening for * notifications. * @param regDict The dictionary with which to register. * @result Returns YES if GrowlHelperApp began launching or was already running, NO if Growl isn't installed */ + (BOOL) _launchGrowlIfInstalledWithRegistrationDictionary:(NSDictionary *)regDict; #ifdef GROWL_WITH_INSTALLER + (void) _checkForPackagedUpdateForGrowlPrefPaneBundle:(NSBundle *)growlPrefPaneBundle; #endif /*! @method _applicationNameForGrowlSearchingRegistrationDictionary: * @abstract Obtain the name of the current application. * @param regDict The dictionary to search, or nil not to. * @result The name of the current application. * @discussion Does not call +bestRegistrationDictionary, and is therefore safe to call from it. */ + (NSString *) _applicationNameForGrowlSearchingRegistrationDictionary:(NSDictionary *)regDict; /*! @method _applicationNameForGrowlSearchingRegistrationDictionary: * @abstract Obtain the icon of the current application. * @param regDict The dictionary to search, or nil not to. * @result The icon of the current application, in IconFamily format (same as is used in 'icns' resources and .icns files). * @discussion Does not call +bestRegistrationDictionary, and is therefore safe to call from it. */ + (NSData *) _applicationIconDataForGrowlSearchingRegistrationDictionary:(NSDictionary *)regDict; @end static NSString *appName = nil; static NSData *appIconData = nil; static id delegate = nil; static BOOL growlLaunched = NO; #ifdef GROWL_WITH_INSTALLER static NSMutableArray *queuedGrowlNotifications = nil; static BOOL userChoseNotToInstallGrowl = NO; static BOOL promptedToInstallGrowl = NO; static BOOL promptedToUpgradeGrowl = NO; #endif //used primarily by GIP, but could be useful elsewhere. static BOOL registerWhenGrowlIsReady = NO; #pragma mark - @implementation GrowlApplicationBridge + (void) setGrowlDelegate:(NSObject *)inDelegate { NSDistributedNotificationCenter *NSDNC = [NSDistributedNotificationCenter defaultCenter]; [delegate autorelease]; delegate = [inDelegate retain]; NSDictionary *regDict = [self bestRegistrationDictionary]; //Cache the appName from the delegate or the process name [appName autorelease]; appName = [[self _applicationNameForGrowlSearchingRegistrationDictionary:regDict] retain]; if (!appName) NSLog(@"%@", @"GrowlApplicationBridge: Cannot register because the application name was not supplied and could not be determined"); //Cache the appIconData from the delegate if it responds to the applicationIconDataForGrowl selector, or the application if not [appIconData autorelease]; appIconData = [[self _applicationIconDataForGrowlSearchingRegistrationDictionary:regDict] retain]; //Add the observer for GROWL_IS_READY which will be triggered later if all goes well [NSDNC addObserver:self selector:@selector(_growlIsReady:) name:GROWL_IS_READY object:nil]; //Watch for notification clicks if our delegate responds to the growlNotificationWasClicked: selector //Notifications will come in on a unique notification name based on our app name and GROWL_NOTIFICATION_CLICKED int pid = [[NSProcessInfo processInfo] processIdentifier]; NSString *growlNotificationClickedName = [[NSString alloc] initWithFormat:@"%@-%d-%@", appName, pid, GROWL_NOTIFICATION_CLICKED]; if ([delegate respondsToSelector:@selector(growlNotificationWasClicked:)]) { [NSDNC addObserver:self selector:@selector(_growlNotificationWasClicked:) name:growlNotificationClickedName object:nil]; } else { [NSDNC removeObserver:self name:growlNotificationClickedName object:nil]; } [growlNotificationClickedName release]; NSString *growlNotificationTimedOutName = [[NSString alloc] initWithFormat:@"%@-%d-%@", appName, pid, GROWL_NOTIFICATION_TIMED_OUT]; if ([delegate respondsToSelector:@selector(growlNotificationTimedOut:)]) { [NSDNC addObserver:self selector:@selector(_growlNotificationTimedOut:) name:growlNotificationTimedOutName object:nil]; } else { [NSDNC removeObserver:self name:growlNotificationTimedOutName object:nil]; } [growlNotificationTimedOutName release]; #ifdef GROWL_WITH_INSTALLER //Determine if the user has previously told us not to ever request installation again userChoseNotToInstallGrowl = [[NSUserDefaults standardUserDefaults] boolForKey:@"Growl Installation:Do Not Prompt Again"]; #endif growlLaunched = [self _launchGrowlIfInstalledWithRegistrationDictionary:regDict]; } + (NSObject *) growlDelegate { return delegate; } #pragma mark - + (void) notifyWithTitle:(NSString *)title description:(NSString *)description notificationName:(NSString *)notifName iconData:(NSData *)iconData priority:(int)priority isSticky:(BOOL)isSticky clickContext:(id)clickContext { [GrowlApplicationBridge notifyWithTitle:title description:description notificationName:notifName iconData:iconData priority:priority isSticky:isSticky clickContext:clickContext identifier:nil]; } /*Send a notification to Growl for display. *title, description, and notifName are required. *All other id parameters may be nil to accept defaults. *priority is 0 by default; isSticky is NO by default. */ + (void) notifyWithTitle:(NSString *)title description:(NSString *)description notificationName:(NSString *)notifName iconData:(NSData *)iconData priority:(int)priority isSticky:(BOOL)isSticky clickContext:(id)clickContext identifier:(NSString *)identifier { NSParameterAssert(notifName); //Notification name is required. NSParameterAssert(title || description); //At least one of title or description is required. NSDictionary *regDict = [self bestRegistrationDictionary]; if (!appName) appName = [[self _applicationNameForGrowlSearchingRegistrationDictionary:regDict] retain]; if (!appIconData) appIconData = [[self _applicationIconDataForGrowlSearchingRegistrationDictionary:regDict] retain]; NSNumber *pid = [[NSNumber alloc] initWithInt:[[NSProcessInfo processInfo] processIdentifier]]; // Build our noteDict from all passed parameters NSMutableDictionary *noteDict = [[NSMutableDictionary alloc] initWithObjectsAndKeys: appName, GROWL_APP_NAME, pid, GROWL_APP_PID, notifName, GROWL_NOTIFICATION_NAME, appIconData, GROWL_NOTIFICATION_APP_ICON, nil]; [pid release]; if (title) [noteDict setObject:title forKey:GROWL_NOTIFICATION_TITLE]; if (description) [noteDict setObject:description forKey:GROWL_NOTIFICATION_DESCRIPTION]; if (iconData) [noteDict setObject:iconData forKey:GROWL_NOTIFICATION_ICON]; if (clickContext) [noteDict setObject:clickContext forKey:GROWL_NOTIFICATION_CLICK_CONTEXT]; if (priority) { NSNumber *value = [[NSNumber alloc] initWithInt:priority]; [noteDict setObject:value forKey:GROWL_NOTIFICATION_PRIORITY]; [value release]; } if (isSticky) { NSNumber *value = [[NSNumber alloc] initWithBool:isSticky]; [noteDict setObject:value forKey:GROWL_NOTIFICATION_STICKY]; [value release]; } if (identifier) [noteDict setObject:identifier forKey:GROWL_NOTIFICATION_IDENTIFIER]; [self notifyWithDictionary:noteDict]; [noteDict release]; } + (void) notifyWithDictionary:(NSDictionary *)userInfo { //clean up things that need to be cleaned up. NSMutableDictionary *mUserInfo = [userInfo mutableCopy]; Class NSImageClass = [NSImage class]; //notification icon. NSImage *icon = [mUserInfo objectForKey:GROWL_NOTIFICATION_ICON]; if (icon && [icon isKindOfClass:NSImageClass]) [mUserInfo setObject:[icon TIFFRepresentation] forKey:GROWL_NOTIFICATION_ICON]; //per-notification application icon. icon = [mUserInfo objectForKey:GROWL_NOTIFICATION_APP_ICON]; if (icon && [icon isKindOfClass:NSImageClass]) [mUserInfo setObject:[icon TIFFRepresentation] forKey:GROWL_NOTIFICATION_APP_ICON]; userInfo = [mUserInfo autorelease]; //post it. if (growlLaunched) { NSConnection *connection = [NSConnection connectionWithRegisteredName:@"GrowlApplicationBridgePathway" host:nil]; if (connection) { //Post to Growl via GrowlApplicationBridgePathway NS_DURING NSDistantObject *theProxy = [connection rootProxy]; [theProxy setProtocolForProxy:@protocol(GrowlNotificationProtocol)]; id growlProxy = (id)theProxy; [growlProxy postNotificationWithDictionary:userInfo]; NS_HANDLER NSLog(@"GrowlApplicationBridge: exception while sending notification: %@", localException); NS_ENDHANDLER } else { //Post to Growl via NSDistributedNotificationCenter //NSLog(@"GrowlApplicationBridge: could not find local GrowlApplicationBridgePathway, falling back to NSDistributedNotificationCenter"); [[NSDistributedNotificationCenter defaultCenter] postNotificationName:GROWL_NOTIFICATION object:nil userInfo:userInfo deliverImmediately:NO]; } } else { #ifdef GROWL_WITH_INSTALLER /*if Growl launches, and the user hasn't already said NO to installing * it, store this notification for posting */ if (!userChoseNotToInstallGrowl) { //in case the dictionary is mutable, make a copy. userInfo = [userInfo copy]; if (!queuedGrowlNotifications) { queuedGrowlNotifications = [[NSMutableArray alloc] init]; } [queuedGrowlNotifications addObject:userInfo]; //if we have not already asked the user to install Growl, do it now if (!promptedToInstallGrowl) { [GrowlInstallationPrompt showInstallationPrompt]; promptedToInstallGrowl = YES; } [userInfo release]; } #endif } } #pragma mark - + (BOOL) isGrowlInstalled { return ([GrowlPathUtil growlPrefPaneBundle] != nil); } + (BOOL) isGrowlRunning { BOOL growlIsRunning = NO; ProcessSerialNumber PSN = { kNoProcess, kNoProcess }; while (GetNextProcess(&PSN) == noErr) { NSDictionary *infoDict = (NSDictionary *)ProcessInformationCopyDictionary(&PSN, kProcessDictionaryIncludeAllInformationMask); if ([[infoDict objectForKey:(NSString *)kCFBundleIdentifierKey] isEqualToString:@"com.Growl.GrowlHelperApp"]) { growlIsRunning = YES; [infoDict release]; break; } [infoDict release]; } return growlIsRunning; } #pragma mark - + (BOOL) registerWithDictionary:(NSDictionary *)regDict { if (regDict) regDict = [self registrationDictionaryByFillingInDictionary:regDict]; else regDict = [self bestRegistrationDictionary]; return [self _launchGrowlIfInstalledWithRegistrationDictionary:regDict]; } + (void) reregisterGrowlNotifications { [self registerWithDictionary:nil]; } + (void) setWillRegisterWhenGrowlIsReady:(BOOL)flag { registerWhenGrowlIsReady = flag; } + (BOOL) willRegisterWhenGrowlIsReady { return registerWhenGrowlIsReady; } #pragma mark - + (NSDictionary *) registrationDictionaryFromDelegate { NSDictionary *regDict = nil; if (delegate && [delegate respondsToSelector:@selector(registrationDictionaryForGrowl)]) regDict = [delegate registrationDictionaryForGrowl]; return regDict; } + (NSDictionary *) registrationDictionaryFromBundle:(NSBundle *)bundle { if (!bundle) bundle = [NSBundle mainBundle]; NSDictionary *regDict = nil; NSString *regDictPath = [bundle pathForResource:@"Growl Registration Ticket" ofType:GROWL_REG_DICT_EXTENSION]; if (regDictPath) { regDict = [NSDictionary dictionaryWithContentsOfFile:regDictPath]; if (!regDict) NSLog(@"GrowlApplicationBridge: The bundle at %@ contains a registration dictionary, but it is not a valid property list. Please tell this application's developer.", [bundle bundlePath]); } return regDict; } + (NSDictionary *) bestRegistrationDictionary { NSDictionary *registrationDictionary = [self registrationDictionaryFromDelegate]; if (!registrationDictionary) registrationDictionary = [self registrationDictionaryFromBundle:nil]; if (!registrationDictionary) { NSLog(@"GrowlApplicationBridge: The Growl delegate did not supply a registration dictionary, and the app bundle at %@ does not have one. Please tell this application's developer.", [[NSBundle mainBundle] bundlePath]); } registrationDictionary = [self registrationDictionaryByFillingInDictionary:registrationDictionary]; return registrationDictionary; } #pragma mark - + (NSDictionary *) registrationDictionaryByFillingInDictionary:(NSDictionary *)regDict { return [self registrationDictionaryByFillingInDictionary:regDict restrictToKeys:nil]; } + (NSDictionary *) registrationDictionaryByFillingInDictionary:(NSDictionary *)regDict restrictToKeys:(NSSet *)keys { if (!regDict) return nil; NSMutableDictionary *mRegDict = [regDict mutableCopy]; if ((!keys) || [keys containsObject:GROWL_APP_NAME]) { if (![mRegDict objectForKey:GROWL_APP_NAME]) { if (!appName) appName = [[self _applicationNameForGrowlSearchingRegistrationDictionary:regDict] retain]; [mRegDict setObject:appName forKey:GROWL_APP_NAME]; } } if ((!keys) || [keys containsObject:GROWL_APP_ICON]) { if (![mRegDict objectForKey:GROWL_APP_ICON]) { if (!appIconData) { appIconData = [self _applicationIconDataForGrowlSearchingRegistrationDictionary:regDict]; if(appIconData && [appIconData isKindOfClass:[NSImage class]]) appIconData = [(NSImage *)appIconData TIFFRepresentation]; appIconData = [appIconData retain]; } if (appIconData) { [mRegDict setObject:appIconData forKey:GROWL_APP_ICON]; } } } if ((!keys) || [keys containsObject:GROWL_APP_LOCATION]) { if (![mRegDict objectForKey:GROWL_APP_LOCATION]) { NSURL *myURL = copyCurrentProcessURL(); if (myURL) { NSDictionary *file_data = [myURL dockDescription]; if (file_data) { NSDictionary *location = [[NSDictionary alloc] initWithObjectsAndKeys:file_data, @"file-data", nil]; [mRegDict setObject:location forKey:GROWL_APP_LOCATION]; [location release]; } else { [mRegDict removeObjectForKey:GROWL_APP_LOCATION]; } [myURL release]; } } } if ((!keys) || [keys containsObject:GROWL_NOTIFICATIONS_DEFAULT]) { if (![mRegDict objectForKey:GROWL_NOTIFICATIONS_DEFAULT]) { NSArray *all = [mRegDict objectForKey:GROWL_NOTIFICATIONS_ALL]; if (all) { [mRegDict setObject:all forKey:GROWL_NOTIFICATIONS_DEFAULT]; } } } NSDictionary *result = [NSDictionary dictionaryWithDictionary:mRegDict]; [mRegDict release]; return result; } #pragma mark - #pragma mark Private methods + (NSString *) _applicationNameForGrowlSearchingRegistrationDictionary:(NSDictionary *)regDict { NSString *applicationNameForGrowl = nil; if (delegate && [delegate respondsToSelector:@selector(applicationNameForGrowl)]) applicationNameForGrowl = [delegate applicationNameForGrowl]; if (!applicationNameForGrowl) applicationNameForGrowl = [regDict objectForKey:GROWL_APP_NAME]; if (!applicationNameForGrowl) applicationNameForGrowl = [[NSProcessInfo processInfo] processName]; return applicationNameForGrowl; } + (NSData *) _applicationIconDataForGrowlSearchingRegistrationDictionary:(NSDictionary *)regDict { NSData *iconData = nil; if (delegate && [delegate respondsToSelector:@selector(applicationIconDataForGrowl)]) iconData = [delegate applicationIconDataForGrowl]; if (!iconData) iconData = [regDict objectForKey:GROWL_APP_ICON]; if (!iconData) { NSURL *URL = copyCurrentProcessURL(); iconData = [copyIconDataForURL(URL) autorelease]; [URL release]; } return iconData; } /*Selector called when a growl notification is clicked. This should never be * called manually, and the calling observer should only be registered if the * delegate responds to growlNotificationWasClicked:. */ + (void) _growlNotificationWasClicked:(NSNotification *)notification { [delegate performSelector:@selector(growlNotificationWasClicked:) withObject:[[notification userInfo] objectForKey:GROWL_KEY_CLICKED_CONTEXT]]; } + (void) _growlNotificationTimedOut:(NSNotification *)notification { [delegate performSelector:@selector(growlNotificationTimedOut:) withObject:[[notification userInfo] objectForKey:GROWL_KEY_CLICKED_CONTEXT]]; } #pragma mark - + (void) _growlIsReady:(NSNotification *)notification { #pragma unused(notification) //Growl has now launched; we may get here with (growlLaunched == NO) when the user first installs growlLaunched = YES; //Inform our delegate if it is interested if ([delegate respondsToSelector:@selector(growlIsReady)]) [delegate growlIsReady]; //Post a notification locally [[NSNotificationCenter defaultCenter] postNotificationName:GROWL_IS_READY object:nil]; //Stop observing for GROWL_IS_READY NSDistributedNotificationCenter *distCenter = [NSDistributedNotificationCenter defaultCenter]; [distCenter removeObserver:self name:GROWL_IS_READY object:nil]; //register (fixes #102: this is necessary if we got here by Growl having just been installed) if (registerWhenGrowlIsReady) { [self reregisterGrowlNotifications]; registerWhenGrowlIsReady = NO; } #ifdef GROWL_WITH_INSTALLER //Perform any queued notifications NSEnumerator *enumerator = [queuedGrowlNotifications objectEnumerator]; NSDictionary *noteDict; while ((noteDict = [enumerator nextObject])) { NSConnection *connection = [NSConnection connectionWithRegisteredName:@"GrowlApplicationBridgePathway" host:nil]; if (connection) { //Post to Growl via GrowlApplicationBridgePathway NS_DURING NSDistantObject *theProxy = [connection rootProxy]; [theProxy setProtocolForProxy:@protocol(GrowlNotificationProtocol)]; id growlProxy = (id)theProxy; [growlProxy postNotificationWithDictionary:noteDict]; NS_HANDLER NSLog(@"GrowlApplicationBridge: exception while sending notification: %@", localException); NS_ENDHANDLER } else { //Post to Growl via NSDistributedNotificationCenter //NSLog(@"GrowlApplicationBridge: could not find local GrowlApplicationBridgePathway, falling back to NSDistributedNotificationCenter"); [distCenter postNotificationName:GROWL_NOTIFICATION object:nil userInfo:noteDict deliverImmediately:NO]; } } [queuedGrowlNotifications release]; queuedGrowlNotifications = nil; #endif } #ifdef GROWL_WITH_INSTALLER /*Sent to us by GrowlInstallationPrompt if the user clicks Cancel so we can * avoid prompting again this session (or ever if they checked Don't Ask Again) */ + (void) _userChoseNotToInstallGrowl { //Note the user's action so we stop queueing notifications, etc. userChoseNotToInstallGrowl = YES; //Clear our queued notifications; we won't be needing them [queuedGrowlNotifications release]; queuedGrowlNotifications = nil; } // Check against our current version number and ensure the installed Growl pane is the same or later + (void) _checkForPackagedUpdateForGrowlPrefPaneBundle:(NSBundle *)growlPrefPaneBundle { NSString *ourGrowlPrefPaneInfoPath; NSDictionary *infoDictionary; NSString *packagedVersion, *installedVersion; BOOL upgradeIsAvailable; ourGrowlPrefPaneInfoPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"GrowlPrefPaneInfo" ofType:@"plist"]; NSDictionary *infoDict = [[NSDictionary alloc] initWithContentsOfFile:ourGrowlPrefPaneInfoPath]; packagedVersion = [infoDict objectForKey:(NSString *)kCFBundleVersionKey]; infoDictionary = [growlPrefPaneBundle infoDictionary]; installedVersion = [infoDictionary objectForKey:(NSString *)kCFBundleVersionKey]; //If the installed version is earlier than our packaged version, we can offer an upgrade. upgradeIsAvailable = (compareVersionStringsTranslating1_0To0_5(packagedVersion, installedVersion) == kCFCompareGreaterThan); if (upgradeIsAvailable && !promptedToUpgradeGrowl) { NSString *lastDoNotPromptVersion = [[NSUserDefaults standardUserDefaults] objectForKey:@"Growl Update:Do Not Prompt Again:Last Version"]; if (!lastDoNotPromptVersion || (compareVersionStringsTranslating1_0To0_5(packagedVersion, lastDoNotPromptVersion) == kCFCompareGreaterThan)) { [GrowlInstallationPrompt showUpdatePromptForVersion:packagedVersion]; promptedToUpgradeGrowl = YES; } } [infoDict release]; } #endif #pragma mark - + (BOOL) _launchGrowlIfInstalledWithRegistrationDictionary:(NSDictionary *)regDict { NSBundle *growlPrefPaneBundle; BOOL success = NO; growlPrefPaneBundle = [GrowlPathUtil growlPrefPaneBundle]; if (growlPrefPaneBundle) { NSString *growlHelperAppPath = [growlPrefPaneBundle pathForResource:@"GrowlHelperApp" ofType:@"app"]; #ifdef GROWL_WITH_INSTALLER /* Check against our current version number and ensure the installed Growl pane is the same or later */ [self _checkForPackagedUpdateForGrowlPrefPaneBundle:growlPrefPaneBundle]; #endif //Houston, we are go for launch. if (growlHelperAppPath) { //Let's launch in the background (unfortunately, requires Carbon on Jaguar) LSLaunchFSRefSpec spec; FSRef appRef; OSStatus status = FSPathMakeRef((UInt8 *)[growlHelperAppPath fileSystemRepresentation], &appRef, NULL); if (status == noErr) { FSRef regItemRef; BOOL passRegDict = NO; if (regDict) { OSStatus regStatus; NSString *regDictFileName; NSString *regDictPath; //Obtain a truly unique file name regDictFileName = [[[[self _applicationNameForGrowlSearchingRegistrationDictionary:regDict] stringByAppendingString:@"-"] stringByAppendingString:[[NSProcessInfo processInfo] globallyUniqueString]] stringByAppendingPathExtension:GROWL_REG_DICT_EXTENSION]; if ([regDictFileName length] > NAME_MAX) { regDictFileName = [[regDictFileName substringToIndex:(NAME_MAX - [GROWL_REG_DICT_EXTENSION length])] stringByAppendingPathExtension:GROWL_REG_DICT_EXTENSION]; } //make sure it's within pathname length constraints regDictPath = [NSTemporaryDirectory() stringByAppendingPathComponent:regDictFileName]; if ([regDictPath length] > PATH_MAX) { regDictPath = [[regDictPath substringToIndex:(PATH_MAX - [GROWL_REG_DICT_EXTENSION length])] stringByAppendingPathExtension:GROWL_REG_DICT_EXTENSION]; } //Write the registration dictionary out to the temporary directory NSData *plistData; NSString *error; plistData = [NSPropertyListSerialization dataFromPropertyList:regDict format:NSPropertyListBinaryFormat_v1_0 errorDescription:&error]; if (plistData) { success = [plistData writeToFile:regDictPath atomically:NO]; } else { NSLog(@"GrowlApplicationBridge: Error writing registration dictionary at %@: %@", regDictPath, error); NSLog(@"GrowlApplicationBridge: Registration dictionary follows\n%@", regDict); [error release]; } regStatus = FSPathMakeRef((UInt8 *)[regDictPath fileSystemRepresentation], ®ItemRef, NULL); if (regStatus == noErr) { passRegDict = YES; } } spec.appRef = &appRef; spec.numDocs = (passRegDict != NO); spec.itemRefs = (passRegDict ? ®ItemRef : NULL); spec.passThruParams = NULL; spec.launchFlags = kLSLaunchDontAddToRecents | kLSLaunchDontSwitch | kLSLaunchNoParams | kLSLaunchAsync; spec.asyncRefCon = NULL; status = LSOpenFromRefSpec(&spec, NULL); success = (status == noErr); } } } return success; } /* + (BOOL)launchGrowlIfInstalled * *Returns YES if the Growl helper app began launching or was already running. *Returns NO and performs no other action if the Growl prefPane is not properly * installed. *If Growl is installed but disabled, the application will be registered and * GrowlHelperApp will then quit. This method will still return YES if Growl * is installed but disabled. */ + (BOOL) launchGrowlIfInstalled { return [self _launchGrowlIfInstalledWithRegistrationDictionary:nil]; } @end amsn-0.98.9/utils/macosx/growl1.0/src/growl.m0000644000175000017500000001265611017026572020506 0ustar billiobbilliob/* * growl.m * * Copyright (c) 2004-2005, Toby Peterson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Growl project nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "GrowlDefines.h" #include "GrowlApplicationBridge.h" #include "TclGrowler.h" static TclGrowler *tg = nil; NSArray * Tcl_ListToNSArray(Tcl_Interp * interp, Tcl_Obj * listObj) { NSMutableArray * mut = [[NSMutableArray alloc] init]; Tcl_Obj ** listPtr; int listLen; if (Tcl_ListObjGetElements(interp, listObj, &listLen, &listPtr) != TCL_OK) { return nil; } int i; for (i=0; i #include "CFGrowlAdditions.h" #include static CFStringRef _CFURLAliasDataKey = CFSTR("_CFURLAliasData"); static CFStringRef _CFURLStringKey = CFSTR("_CFURLString"); static CFStringRef _CFURLStringTypeKey = CFSTR("_CFURLStringType"); //see GrowlApplicationBridge-Carbon.c for rationale of using NSLog. extern void NSLog(CFStringRef format, ...); CFStringRef copyCurrentProcessName(void) { ProcessSerialNumber PSN = { 0, kCurrentProcess }; CFStringRef name = NULL; OSStatus err = CopyProcessName(&PSN, &name); if (err != noErr) { NSLog(CFSTR("in copyCurrentProcessName in CFGrowlAdditions: Could not get process name because CopyProcessName returned %li"), (long)err); name = NULL; } return name; } CFURLRef copyCurrentProcessURL(void) { ProcessSerialNumber psn = { 0, kCurrentProcess }; FSRef fsref; CFURLRef URL = NULL; OSStatus err = GetProcessBundleLocation(&psn, &fsref); if (err != noErr) { NSLog(CFSTR("in copyCurrentProcessURL in CFGrowlAdditions: Could not get application location, because GetProcessBundleLocation returned %li\n"), (long)err); } else { URL = CFURLCreateFromFSRef(kCFAllocatorDefault, &fsref); } return URL; } CFStringRef copyCurrentProcessPath(void) { CFURLRef URL = copyCurrentProcessURL(); CFStringRef path = CFURLCopyFileSystemPath(URL, kCFURLPOSIXPathStyle); CFRelease(URL); return path; } CFURLRef copyTemporaryFolderURL(void) { FSRef ref; CFURLRef url = NULL; OSStatus err = FSFindFolder(kOnAppropriateDisk, kTemporaryFolderType, kCreateFolder, &ref); if (err != noErr) NSLog(CFSTR("in copyTemporaryFolderPath in CFGrowlAdditions: Could not locate temporary folder because FSFindFolder returned %li"), (long)err); else url = CFURLCreateFromFSRef(kCFAllocatorDefault, &ref); return url; } CFStringRef copyTemporaryFolderPath(void) { CFStringRef path = NULL; CFURLRef url = copyTemporaryFolderURL(); if (url) { path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); CFRelease(url); } return path; } CFDictionaryRef createDockDescriptionForURL(CFURLRef url) { if (!url) { NSLog(CFSTR("%@"), CFSTR("in copyDockDescriptionForURL in CFGrowlAdditions: Cannot copy Dock description for a NULL URL")); return NULL; } //return NULL for non-file: URLs. CFStringRef scheme = CFURLCopyScheme(url); Boolean isFileURL = (CFStringCompare(scheme, CFSTR("file"), kCFCompareCaseInsensitive) == kCFCompareEqualTo); CFRelease(scheme); if (!isFileURL) return NULL; CFDictionaryRef dict = NULL; CFStringRef path = NULL; CFDataRef aliasData = NULL; FSRef fsref; if (CFURLGetFSRef(url, &fsref)) { AliasHandle alias = NULL; OSStatus err = FSNewAlias(/*fromFile*/ NULL, &fsref, &alias); if (err != noErr) { NSLog(CFSTR("in copyDockDescriptionForURL in CFGrowlAdditions: FSNewAlias for %@ returned %li"), url, (long)err); } else { HLock((Handle)alias); err = FSCopyAliasInfo(alias, /*targetName*/ NULL, /*volumeName*/ NULL, (CFStringRef *)&path, /*whichInfo*/ NULL, /*info*/ NULL); if (err != noErr) { NSLog(CFSTR("in copyDockDescriptionForURL in CFGrowlAdditions: FSCopyAliasInfo for %@ returned %li"), url, (long)err); } aliasData = CFDataCreate(kCFAllocatorDefault, (UInt8 *)*alias, GetHandleSize((Handle)alias)); HUnlock((Handle)alias); DisposeHandle((Handle)alias); } } if (!path) { path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); } if (path || aliasData) { CFMutableDictionaryRef temp = CFDictionaryCreateMutable(kCFAllocatorDefault, /*capacity*/ 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (path) { CFDictionarySetValue(temp, _CFURLStringKey, path); CFRelease(path); int pathStyle = kCFURLPOSIXPathStyle; CFNumberRef pathStyleNum = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &pathStyle); CFDictionarySetValue(temp, _CFURLStringTypeKey, pathStyleNum); CFRelease(pathStyleNum); } if (aliasData) { CFDictionarySetValue(temp, _CFURLAliasDataKey, aliasData); CFRelease(aliasData); } dict = temp; } return dict; } CFDataRef copyIconDataForPath(CFStringRef path) { CFDataRef data = NULL; //false is probably safest, and is harmless when the object really is a directory. CFURLRef URL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path, kCFURLPOSIXPathStyle, /*isDirectory*/ false); if (URL) { data = copyIconDataForURL(URL); CFRelease(URL); } return data; } CFDataRef copyIconDataForURL(CFURLRef URL) { CFDataRef data = NULL; if (URL) { FSRef ref; if (CFURLGetFSRef(URL, &ref)) { IconRef icon = NULL; SInt16 label_noOneCares; OSStatus err = GetIconRefFromFileInfo(&ref, /*inFileNameLength*/ 0U, /*inFileName*/ NULL, kFSCatInfoNone, /*inCatalogInfo*/ NULL, kIconServicesNoBadgeFlag | kIconServicesUpdateIfNeededFlag, &icon, &label_noOneCares); if (err != noErr) { NSLog(CFSTR("in copyIconDataForURL in CFGrowlAdditions: could not get icon for %@: GetIconRefFromFileInfo returned %li\n"), URL, (long)err); } else { IconFamilyHandle fam = NULL; err = IconRefToIconFamily(icon, kSelectorAllAvailableData, &fam); if (err != noErr) { NSLog(CFSTR("in copyIconDataForURL in CFGrowlAdditions: could not get icon for %@: IconRefToIconFamily returned %li\n"), URL, (long)err); } else { HLock((Handle)fam); data = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)*(Handle)fam, GetHandleSize((Handle)fam)); HUnlock((Handle)fam); DisposeHandle((Handle)fam); } ReleaseIconRef(icon); } } } return data; } URL_TYPE createURLByMakingDirectoryAtURLWithName(URL_TYPE parent, STRING_TYPE name) { CFURLRef newDirectory = NULL; CFAllocatorRef allocator = parent ? CFGetAllocator(parent) : name ? CFGetAllocator(name) : kCFAllocatorDefault; if (parent) parent = CFRetain(parent); else { char *cwdBytes = alloca(PATH_MAX); getcwd(cwdBytes, PATH_MAX); parent = CFURLCreateFromFileSystemRepresentation(allocator, (const unsigned char *)cwdBytes, strlen(cwdBytes), /*isDirectory*/ true); if (!name) { newDirectory = parent; goto end; } } if (!parent) NSLog(CFSTR("in createURLByMakingDirectoryAtURLWithName in CFGrowlAdditions: parent directory URL is NULL (please tell the Growl developers)\n"), parent); else { if (name) name = CFRetain(name); else { name = CFURLCopyLastPathComponent(parent); CFURLRef newParent = CFURLCreateCopyDeletingLastPathComponent(allocator, parent); CFRelease(parent); parent = newParent; } if (!name) NSLog(CFSTR("in createURLByMakingDirectoryAtURLWithName in CFGrowlAdditions: name of directory to create is NULL (please tell the Growl developers)\n"), parent); else { FSRef parentRef; if (!CFURLGetFSRef(parent, &parentRef)) NSLog(CFSTR("in createURLByMakingDirectoryAtURLWithName in CFGrowlAdditions: could not create FSRef for parent directory at %@ (please tell the Growl developers)\n"), parent); else { FSRef newDirectoryRef; struct HFSUniStr255 nameUnicode; CFRange range = { 0, (CFStringGetLength(name) > USHRT_MAX ? USHRT_MAX : CFStringGetLength(name)) }; CFStringGetCharacters(name, range, nameUnicode.unicode); nameUnicode.length = range.length; struct FSRefParam refPB = { .ref = &parentRef, .nameLength = nameUnicode.length, .name = nameUnicode.unicode, .whichInfo = kFSCatInfoNone, .catInfo = NULL, .textEncodingHint = kTextEncodingUnknown, .newRef = &newDirectoryRef, }; OSStatus err = PBCreateDirectoryUnicodeSync(&refPB); if (err == dupFNErr) { //dupFNErr == file (or folder) exists already. this is fine. err = PBMakeFSRefUnicodeSync(&refPB); } if (err == noErr) { NSLog(CFSTR("PBCreateDirectoryUnicodeSync or PBMakeFSRefUnicodeSync returned %li; calling CFURLCreateFromFSRef"), (long)err); //XXX newDirectory = CFURLCreateFromFSRef(allocator, &newDirectoryRef); NSLog(CFSTR("CFURLCreateFromFSRef returned %@"), newDirectory); //XXX } else NSLog(CFSTR("in createURLByMakingDirectoryAtURLWithName in CFGrowlAdditions: could not create directory '%@' in parent directory at %@: FSCreateDirectoryUnicode returned %li (please tell the Growl developers)"), name, parent, (long)err); } CFRelease(parent); } //if (name) CFRelease(name); } //if (parent) end: return newDirectory; } #ifndef COPYFORK_BUFSIZE # define COPYFORK_BUFSIZE 5242880U /*5 MiB*/ #endif static OSStatus copyFork(const struct HFSUniStr255 *forkName, const FSRef *srcFile, const FSRef *destDir, const struct HFSUniStr255 *destName, FSRef *outDestFile) { OSStatus err, closeErr; struct FSForkIOParam srcPB = { .ref = srcFile, .forkNameLength = forkName->length, .forkName = forkName->unicode, .permissions = fsRdPerm, }; unsigned char debuggingPathBuf[PATH_MAX] = ""; OSStatus debuggingPathErr; err = PBOpenForkSync(&srcPB); if (err != noErr) { debuggingPathErr = FSRefMakePath(srcFile, debuggingPathBuf, PATH_MAX); if (debuggingPathErr != noErr) snprintf((char *)debuggingPathBuf, PATH_MAX, "(could not get path for source file: FSRefMakePath returned %li)", (long)debuggingPathErr); NSLog(CFSTR("in copyFork in CFGrowlAdditions: PBOpenForkSync (source: %s) returned %li"), debuggingPathBuf, (long)err); } else { FSRef destFile; /*the first thing to do is get the name of the destination file, if one * wasn't provided. *and while we're at it, we get the catalogue info as well. */ struct FSCatalogInfo catInfo; struct FSRefParam refPB = { .ref = srcFile, .whichInfo = kFSCatInfoGettableInfo & kFSCatInfoSettableInfo, .catInfo = &catInfo, .spec = NULL, .parentRef = NULL, .outName = destName ? NULL : (struct HFSUniStr255 *)(destName = alloca(sizeof(struct HFSUniStr255))), }; err = PBGetCatalogInfoSync(&refPB); if (err != noErr) { debuggingPathErr = FSRefMakePath(srcFile, debuggingPathBuf, PATH_MAX); if (debuggingPathErr != noErr) snprintf((char *)debuggingPathBuf, PATH_MAX, "(could not get path for source file: FSRefMakePath returned %li)", (long)debuggingPathErr); NSLog(CFSTR("in copyFork in CFGrowlAdditions: PBGetCatalogInfoSync (source: %s) returned %li"), debuggingPathBuf, (long)err); } else { refPB.ref = destDir; refPB.nameLength = destName->length; refPB.name = destName->unicode; refPB.textEncodingHint = kTextEncodingUnknown; refPB.newRef = &destFile; const char *functionName = "PBMakeFSRefUnicodeSync"; //for error-reporting message err = PBMakeFSRefUnicodeSync(&refPB); if ((err != noErr) && (err != fnfErr)) { handleMakeFSRefError: debuggingPathErr = FSRefMakePath(destDir, debuggingPathBuf, PATH_MAX); if (debuggingPathErr != noErr) snprintf((char *)debuggingPathBuf, PATH_MAX, "(could not get path for destination directory: FSRefMakePath returned %li)", (long)debuggingPathErr); //get filename too CFStringRef debuggingFilename = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, destName->unicode, destName->length, /*contentsDeallocator*/ kCFAllocatorNull); if (!debuggingFilename) debuggingFilename = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, "(could not get filename for destination file: CFStringCreateWithCharactersNoCopy returned NULL)", kCFStringEncodingASCII, /*contentsDeallocator*/ kCFAllocatorNull); NSLog(CFSTR("in copyFork in CFGrowlAdditions: %s (destination: %s/%@) returned %li"), functionName, debuggingPathBuf, debuggingFilename, (long)err); if (debuggingFilename) CFRelease(debuggingFilename); } else { //that file doesn't exist in that folder; create it. err = PBCreateFileUnicodeSync(&refPB); if (err == noErr) { /*make sure the Finder knows about the new file. *FNNotify returns a status code too, but this isn't an * essential step, so we just ignore it. */ FNNotify(destDir, kFNDirectoryModifiedMessage, kNilOptions); } else if (err == dupFNErr) { /*dupFNErr: the file already exists. *we can safely ignore this error. */ err = noErr; } else { functionName = "PBCreateFileUnicodeSync"; goto handleMakeFSRefError; } } } if (err == noErr) { if (outDestFile) memcpy(outDestFile, &destFile, sizeof(destFile)); struct FSForkIOParam destPB = { .ref = &destFile, .forkNameLength = forkName->length, .forkName = forkName->unicode, .permissions = fsWrPerm, }; err = PBOpenForkSync(&destPB); NSLog(CFSTR("in copyFork in CFGrowlAdditions: PBOpenForkSync (dest) returned %li"), (long)err); if (err != noErr) { debuggingPathErr = FSRefMakePath(&destFile, debuggingPathBuf, PATH_MAX); if (debuggingPathErr != noErr) snprintf((char *)debuggingPathBuf, PATH_MAX, "(could not get path for dest file: FSRefMakePath returned %li)", (long)debuggingPathErr); NSLog(CFSTR("in copyFork in CFGrowlAdditions: PBOpenForkSync (destination: %s) returned %li"), debuggingPathBuf, (long)err); } else { void *buf = malloc(COPYFORK_BUFSIZE); if (buf) { srcPB.buffer = destPB.buffer = buf; srcPB.requestCount = COPYFORK_BUFSIZE; while (err == noErr) { err = PBReadForkSync(&srcPB); if (err == eofErr) { err = noErr; if (srcPB.actualCount == 0) break; } if (err != noErr) { debuggingPathErr = FSRefMakePath(&destFile, debuggingPathBuf, PATH_MAX); if (debuggingPathErr != noErr) snprintf((char *)debuggingPathBuf, PATH_MAX, "(could not get path for source file: FSRefMakePath returned %li)", (long)debuggingPathErr); NSLog(CFSTR("in copyFork in CFGrowlAdditions: PBReadForkSync (source: %s) returned %li"), debuggingPathBuf, (long)err); } else { destPB.requestCount = srcPB.actualCount; err = PBWriteForkSync(&destPB); if (err != noErr) { debuggingPathErr = FSRefMakePath(&destFile, debuggingPathBuf, PATH_MAX); if (debuggingPathErr != noErr) snprintf((char *)debuggingPathBuf, PATH_MAX, "(could not get path for dest file: FSRefMakePath returned %li)", (long)debuggingPathErr); NSLog(CFSTR("in copyFork in CFGrowlAdditions: PBWriteForkSync (destination: %s) returned %li"), debuggingPathBuf, (long)err); } } } free(buf); } closeErr = PBCloseForkSync(&destPB); if (closeErr != noErr) { debuggingPathErr = FSRefMakePath(&destFile, debuggingPathBuf, PATH_MAX); if (debuggingPathErr != noErr) snprintf((char *)debuggingPathBuf, PATH_MAX, "(could not get path for dest file: FSRefMakePath returned %li)", (long)debuggingPathErr); NSLog(CFSTR("in copyFork in CFGrowlAdditions: PBCloseForkSync (destination: %s) returned %li"), debuggingPathBuf, (long)err); } if (err == noErr) err = closeErr; } } closeErr = PBCloseForkSync(&srcPB); if (closeErr != noErr) { debuggingPathErr = FSRefMakePath(&destFile, debuggingPathBuf, PATH_MAX); if (debuggingPathErr != noErr) snprintf((char *)debuggingPathBuf, PATH_MAX, "(could not get path for source file: FSRefMakePath returned %li)", (long)debuggingPathErr); NSLog(CFSTR("in copyFork in CFGrowlAdditions: PBCloseForkSync (source: %s) returned %li"), debuggingPathBuf, (long)err); } if (err == noErr) err = closeErr; } return err; } static OSStatus GrowlCopyObjectSync(const FSRef *fileRef, const FSRef *destRef, FSRef *destFileRef) { OSStatus err; struct HFSUniStr255 forkName; struct FSForkIOParam forkPB = { .ref = fileRef, .forkIterator = { .initialize = 0L }, .outForkName = &forkName, }; do { err = PBIterateForksSync(&forkPB); NSLog(CFSTR("PBIterateForksSync returned %li"), (long)err); if (err != noErr) { if (err != errFSNoMoreItems) NSLog(CFSTR("in GrowlCopyObjectSync in CFGrowlAdditions: PBIterateForksSync returned %li"), (long)err); } else { err = copyFork(&forkName, fileRef, destRef, /*destName*/ NULL, /*outDestFile*/ destFileRef); //copyFork prints its own error messages } } while (err == noErr); if (err == errFSNoMoreItems) err = noErr; return err; } CFURLRef createURLByCopyingFileFromURLToDirectoryURL(CFURLRef file, CFURLRef dest) { CFURLRef destFileURL = NULL; FSRef fileRef, destRef, destFileRef; Boolean gotFileRef = CFURLGetFSRef(file, &fileRef); Boolean gotDestRef = CFURLGetFSRef(dest, &destRef); if (!gotFileRef) NSLog(CFSTR("in createURLByCopyingFileFromURLToDirectoryURL in CFGrowlAdditions: CFURLGetFSRef failed with source URL %@"), file); else if (!gotDestRef) NSLog(CFSTR("in createURLByCopyingFileFromURLToDirectoryURL in CFGrowlAdditions: CFURLGetFSRef failed with destination URL %@"), dest); else { OSStatus err; /* * 10.2 has a problem with weak symbols in frameworks so we use * MAC_OS_X_VERSION_MIN_REQUIRED >= 10.3. */ #if defined(NSAppKitVersionNumber10_3) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3 if (FSCopyObjectSync) { err = FSCopyObjectSync(&fileRef, &destRef, /*destName*/ NULL, &destFileRef, kFSFileOperationOverwrite); } else { #endif err = GrowlCopyObjectSync(&fileRef, &destRef, &destFileRef); #if defined(NSAppKitVersionNumber10_3) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3 } #endif if (err == noErr) destFileURL = CFURLCreateFromFSRef(kCFAllocatorDefault, &destFileRef); else NSLog(CFSTR("in createURLByCopyingFileFromURLToDirectoryURL in CFGrowlAdditions: CopyObjectSync returned %li for source URL %@"), (long)err, file); } return destFileURL; } CFPropertyListRef createPropertyListFromURL(CFURLRef file, u_int32_t mutability, CFPropertyListFormat *outFormat, CFStringRef *outErrorString) { CFPropertyListRef plist = NULL; if (!file) NSLog(CFSTR("in createPropertyListFromURL in CFGrowlAdditions: cannot read from a NULL URL")); else { CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, file); if (!stream) NSLog(CFSTR("in createPropertyListFromURL in CFGrowlAdditions: could not create stream for reading from URL %@"), file); else { if (!CFReadStreamOpen(stream)) NSLog(CFSTR("in createPropertyListFromURL in CFGrowlAdditions: could not open stream for reading from URL %@"), file); else { CFPropertyListFormat format; CFStringRef errorString = NULL; plist = CFPropertyListCreateFromStream(kCFAllocatorDefault, stream, /*streamLength*/ 0, mutability, &format, &errorString); if (!plist) NSLog(CFSTR("in createPropertyListFromURL in CFGrowlAdditions: could not read property list from URL %@ (error string: %@)"), file, errorString); if (outFormat) *outFormat = format; if (errorString) { if (outErrorString) *outErrorString = errorString; else CFRelease(errorString); } CFReadStreamClose(stream); } CFRelease(stream); } } return plist; } amsn-0.98.9/utils/macosx/growl1.0/src/GrowlApplicationBridge.h0000644000175000017500000006317410737553652023757 0ustar billiobbilliob// // GrowlApplicationBridge.h // Growl // // Created by Evan Schoenberg on Wed Jun 16 2004. // Copyright 2004-2005 The Growl Project. All rights reserved. // /*! * @header GrowlApplicationBridge.h * @abstract Defines the GrowlApplicationBridge class. * @discussion This header defines the GrowlApplicationBridge class as well as * the GROWL_PREFPANE_BUNDLE_IDENTIFIER constant. */ #ifndef __GrowlApplicationBridge_h__ #define __GrowlApplicationBridge_h__ #import #import "GrowlDefines.h" //Forward declarations @protocol GrowlApplicationBridgeDelegate; /*! * @defined GROWL_PREFPANE_BUNDLE_IDENTIFIER * @discussion The bundle identifier for the Growl prefpane. */ #define GROWL_PREFPANE_BUNDLE_IDENTIFIER @"com.growl.prefpanel" /*! * @defined GROWL_PREFPANE_NAME * @discussion The file name of the Growl prefpane. */ #define GROWL_PREFPANE_NAME @"Growl.prefPane" //Internal notification when the user chooses not to install (to avoid continuing to cache notifications awaiting installation) #define GROWL_USER_CHOSE_NOT_TO_INSTALL_NOTIFICATION @"User chose not to install" //------------------------------------------------------------------------------ #pragma mark - /*! * @class GrowlApplicationBridge * @abstract A class used to interface with Growl. * @discussion This class provides a means to interface with Growl. * * Currently it provides a way to detect if Growl is installed and launch the * GrowlHelperApp if it's not already running. */ @interface GrowlApplicationBridge : NSObject { } /*! * @method isGrowlInstalled * @abstract Detects whether Growl is installed. * @discussion Determines if the Growl prefpane and its helper app are installed. * @result Returns YES if Growl is installed, NO otherwise. */ + (BOOL) isGrowlInstalled; /*! * @method isGrowlRunning * @abstract Detects whether GrowlHelperApp is currently running. * @discussion Cycles through the process list to find whether GrowlHelperApp is running and returns its findings. * @result Returns YES if GrowlHelperApp is running, NO otherwise. */ + (BOOL) isGrowlRunning; #pragma mark - /*! * @method setGrowlDelegate: * @abstract Set the object which will be responsible for providing and receiving Growl information. * @discussion This must be called before using GrowlApplicationBridge. * * The methods in the GrowlApplicationBridgeDelegate protocol are required * and return the basic information needed to register with Growl. * * The methods in the GrowlApplicationBridgeDelegate_InformalProtocol * informal protocol are individually optional. They provide a greater * degree of interaction between the application and growl such as informing * the application when one of its Growl notifications is clicked by the user. * * The methods in the GrowlApplicationBridgeDelegate_Installation_InformalProtocol * informal protocol are individually optional and are only applicable when * using the Growl-WithInstaller.framework which allows for automated Growl * installation. * * When this method is called, data will be collected from inDelegate, Growl * will be launched if it is not already running, and the application will be * registered with Growl. * * If using the Growl-WithInstaller framework, if Growl is already installed * but this copy of the framework has an updated version of Growl, the user * will be prompted to update automatically. * * @param inDelegate The delegate for the GrowlApplicationBridge. It must conform to the GrowlApplicationBridgeDelegate protocol. */ + (void) setGrowlDelegate:(NSObject *)inDelegate; /*! * @method growlDelegate * @abstract Return the object responsible for providing and receiving Growl information. * @discussion See setGrowlDelegate: for details. * @result The Growl delegate. */ + (NSObject *) growlDelegate; #pragma mark - /*! * @method notifyWithTitle:description:notificationName:iconData:priority:isSticky:clickContext: * @abstract Send a Growl notification. * @discussion This is the preferred means for sending a Growl notification. * The notification name and at least one of the title and description are * required (all three are preferred). All other parameters may be * nil (or 0 or NO as appropriate) to accept default values. * * If using the Growl-WithInstaller framework, if Growl is not installed the * user will be prompted to install Growl. If the user cancels, this method * will have no effect until the next application session, at which time when * it is called the user will be prompted again. The user is also given the * option to not be prompted again. If the user does choose to install Growl, * the requested notification will be displayed once Growl is installed and * running. * * @param title The title of the notification displayed to the user. * @param description The full description of the notification displayed to the user. * @param notifName The internal name of the notification. Should be human-readable, as it will be displayed in the Growl preference pane. * @param iconData NSData object to show with the notification as its icon. If nil, the application's icon will be used instead. * @param priority The priority of the notification. The default value is 0; positive values are higher priority and negative values are lower priority. Not all Growl displays support priority. * @param isSticky If YES, the notification will remain on screen until clicked. Not all Growl displays support sticky notifications. * @param clickContext A context passed back to the Growl delegate if it implements -(void)growlNotificationWasClicked: and the notification is clicked. Not all display plugins support clicking. The clickContext must be plist-encodable (completely of NSString, NSArray, NSNumber, NSDictionary, and NSData types). */ + (void) notifyWithTitle:(NSString *)title description:(NSString *)description notificationName:(NSString *)notifName iconData:(NSData *)iconData priority:(signed int)priority isSticky:(BOOL)isSticky clickContext:(id)clickContext; /*! * @method notifyWithTitle:description:notificationName:iconData:priority:isSticky:clickContext:identifier: * @abstract Send a Growl notification. * @discussion This is the preferred means for sending a Growl notification. * The notification name and at least one of the title and description are * required (all three are preferred). All other parameters may be * nil (or 0 or NO as appropriate) to accept default values. * * If using the Growl-WithInstaller framework, if Growl is not installed the * user will be prompted to install Growl. If the user cancels, this method * will have no effect until the next application session, at which time when * it is called the user will be prompted again. The user is also given the * option to not be prompted again. If the user does choose to install Growl, * the requested notification will be displayed once Growl is installed and * running. * * @param title The title of the notification displayed to the user. * @param description The full description of the notification displayed to the user. * @param notifName The internal name of the notification. Should be human-readable, as it will be displayed in the Growl preference pane. * @param iconData NSData object to show with the notification as its icon. If nil, the application's icon will be used instead. * @param priority The priority of the notification. The default value is 0; positive values are higher priority and negative values are lower priority. Not all Growl displays support priority. * @param isSticky If YES, the notification will remain on screen until clicked. Not all Growl displays support sticky notifications. * @param clickContext A context passed back to the Growl delegate if it implements -(void)growlNotificationWasClicked: and the notification is clicked. Not all display plugins support clicking. The clickContext must be plist-encodable (completely of NSString, NSArray, NSNumber, NSDictionary, and NSData types). * @param identifier An identifier for this notification. Notifications with equal identifiers are coalesced. */ + (void) notifyWithTitle:(NSString *)title description:(NSString *)description notificationName:(NSString *)notifName iconData:(NSData *)iconData priority:(signed int)priority isSticky:(BOOL)isSticky clickContext:(id)clickContext identifier:(NSString *)identifier; /*! @method notifyWithDictionary: * @abstract Notifies using a userInfo dictionary suitable for passing to * NSDistributedNotificationCenter. * @param userInfo The dictionary to notify with. * @discussion Before Growl 0.6, your application would have posted * notifications using NSDistributedNotificationCenter by * creating a userInfo dictionary with the notification data. This had the * advantage of allowing you to add other data to the dictionary for programs * besides Growl that might be listening. * * This method allows you to use such dictionaries without being restricted * to using NSDistributedNotificationCenter. The keys for this dictionary * can be found in GrowlDefines.h. */ + (void) notifyWithDictionary:(NSDictionary *)userInfo; #pragma mark - /*! @method registerWithDictionary: * @abstract Register your application with Growl without setting a delegate. * @discussion When you call this method with a dictionary, * GrowlApplicationBridge registers your application using that dictionary. * If you pass nil, GrowlApplicationBridge will ask the delegate * (if there is one) for a dictionary, and if that doesn't work, it will look * in your application's bundle for an auto-discoverable plist. * (XXX refer to more information on that) * * If you pass a dictionary to this method, it must include the * GROWL_APP_NAME key, unless a delegate is set. * * This method is mainly an alternative to the delegate system introduced * with Growl 0.6. Without a delegate, you cannot receive callbacks such as * -growlIsReady (since they are sent to the delegate). You can, * however, set a delegate after registering without one. * * This method was introduced in Growl.framework 0.7. */ + (BOOL) registerWithDictionary:(NSDictionary *)regDict; /*! @method reregisterGrowlNotifications * @abstract Reregister the notifications for this application. * @discussion This method does not normally need to be called. If your * application changes what notifications it is registering with Growl, call * this method to have the Growl delegate's * -registrationDictionaryForGrowl method called again and the * Growl registration information updated. * * This method is now implemented using -registerWithDictionary:. */ + (void) reregisterGrowlNotifications; #pragma mark - /*! @method setWillRegisterWhenGrowlIsReady: * @abstract Tells GrowlApplicationBridge to register with Growl when Growl * launches (or not). * @discussion When Growl has started listening for notifications, it posts a * GROWL_IS_READY notification on the Distributed Notification * Center. GrowlApplicationBridge listens for this notification, using it to * perform various tasks (such as calling your delegate's * -growlIsReady method, if it has one). If this method is * called with YES, one of those tasks will be to reregister * with Growl (in the manner of -reregisterGrowlNotifications). * * This attribute is automatically set back to NO (the default) * after every GROWL_IS_READY notification. * @param flag YES if you want GrowlApplicationBridge to register with * Growl when next it is ready; NO if not. */ + (void) setWillRegisterWhenGrowlIsReady:(BOOL)flag; /*! @method willRegisterWhenGrowlIsReady * @abstract Reports whether GrowlApplicationBridge will register with Growl * when Growl next launches. * @result YES if GrowlApplicationBridge will register with Growl * when next it posts GROWL_IS_READY; NO if not. */ + (BOOL) willRegisterWhenGrowlIsReady; #pragma mark - /*! @method registrationDictionaryFromDelegate * @abstract Asks the delegate for a registration dictionary. * @discussion If no delegate is set, or if the delegate's * -registrationDictionaryForGrowl method returns * nil, this method returns nil. * * This method does not attempt to clean up the dictionary in any way - for * example, if it is missing the GROWL_APP_NAME key, the result * will be missing it too. Use +[GrowlApplicationBridge * registrationDictionaryByFillingInDictionary:] or * +[GrowlApplicationBridge * registrationDictionaryByFillingInDictionary:restrictToKeys:] to try * to fill in missing keys. * * This method was introduced in Growl.framework 0.7. * @result A registration dictionary. */ + (NSDictionary *) registrationDictionaryFromDelegate; /*! @method registrationDictionaryFromBundle: * @abstract Looks in a bundle for a registration dictionary. * @discussion This method looks in a bundle for an auto-discoverable * registration dictionary file using -[NSBundle * pathForResource:ofType:]. If it finds one, it loads the file using * +[NSDictionary dictionaryWithContentsOfFile:] and returns the * result. * * If you pass nil as the bundle, the main bundle is examined. * * This method does not attempt to clean up the dictionary in any way - for * example, if it is missing the GROWL_APP_NAME key, the result * will be missing it too. Use +[GrowlApplicationBridge * registrationDictionaryByFillingInDictionary:] or * +[GrowlApplicationBridge * registrationDictionaryByFillingInDictionary:restrictToKeys:] to try * to fill in missing keys. * * This method was introduced in Growl.framework 0.7. * @result A registration dictionary. */ + (NSDictionary *) registrationDictionaryFromBundle:(NSBundle *)bundle; /*! @method bestRegistrationDictionary * @abstract Obtains a registration dictionary, filled out to the best of * GrowlApplicationBridge's knowledge. * @discussion This method creates a registration dictionary as best * GrowlApplicationBridge knows how. * * First, GrowlApplicationBridge contacts the Growl delegate (if there is * one) and gets the registration dictionary from that. If no such dictionary * was obtained, GrowlApplicationBridge looks in your application's main * bundle for an auto-discoverable registration dictionary file. If that * doesn't exist either, this method returns nil. * * Second, GrowlApplicationBridge calls * +registrationDictionaryByFillingInDictionary: with whatever * dictionary was obtained. The result of that method is the result of this * method. * * GrowlApplicationBridge uses this method when you call * +setGrowlDelegate:, or when you call * +registerWithDictionary: with nil. * * This method was introduced in Growl.framework 0.7. * @result A registration dictionary. */ + (NSDictionary *) bestRegistrationDictionary; #pragma mark - /*! @method registrationDictionaryByFillingInDictionary: * @abstract Tries to fill in missing keys in a registration dictionary. * @discussion This method examines the passed-in dictionary for missing keys, * and tries to work out correct values for them. As of 0.7, it uses: * * Key Value * --- ----- * GROWL_APP_NAME CFBundleExecutableName * GROWL_APP_ICON The icon of the application. * GROWL_APP_LOCATION The location of the application. * GROWL_NOTIFICATIONS_DEFAULT GROWL_NOTIFICATIONS_ALL * * Keys are only filled in if missing; if a key is present in the dictionary, * its value will not be changed. * * This method was introduced in Growl.framework 0.7. * @param regDict The dictionary to fill in. * @result The dictionary with the keys filled in. This is an autoreleased * copy of regDict. */ + (NSDictionary *) registrationDictionaryByFillingInDictionary:(NSDictionary *)regDict; /*! @method registrationDictionaryByFillingInDictionary:restrictToKeys: * @abstract Tries to fill in missing keys in a registration dictionary. * @discussion This method examines the passed-in dictionary for missing keys, * and tries to work out correct values for them. As of 0.7, it uses: * * Key Value * --- ----- * GROWL_APP_NAME CFBundleExecutableName * GROWL_APP_ICON The icon of the application. * GROWL_APP_LOCATION The location of the application. * GROWL_NOTIFICATIONS_DEFAULT GROWL_NOTIFICATIONS_ALL * * Only those keys that are listed in keys will be filled in. * Other missing keys are ignored. Also, keys are only filled in if missing; * if a key is present in the dictionary, its value will not be changed. * * This method was introduced in Growl.framework 0.7. * @param regDict The dictionary to fill in. * @param keys The keys to fill in. If nil, any missing keys are filled in. * @result The dictionary with the keys filled in. This is an autoreleased * copy of regDict. */ + (NSDictionary *) registrationDictionaryByFillingInDictionary:(NSDictionary *)regDict restrictToKeys:(NSSet *)keys; @end //------------------------------------------------------------------------------ #pragma mark - /*! * @protocol GrowlApplicationBridgeDelegate * @abstract Required protocol for the Growl delegate. * @discussion The methods in this protocol are required and are called * automatically as needed by GrowlApplicationBridge. See * +[GrowlApplicationBridge setGrowlDelegate:]. * See also GrowlApplicationBridgeDelegate_InformalProtocol. */ @protocol GrowlApplicationBridgeDelegate // -registrationDictionaryForGrowl has moved to the informal protocol as of 0.7. @end //------------------------------------------------------------------------------ #pragma mark - /*! * @category NSObject(GrowlApplicationBridgeDelegate_InformalProtocol) * @abstract Methods which may be optionally implemented by the GrowlDelegate. * @discussion The methods in this informal protocol will only be called if implemented by the delegate. */ @interface NSObject (GrowlApplicationBridgeDelegate_InformalProtocol) /*! * @method registrationDictionaryForGrowl * @abstract Return the dictionary used to register this application with Growl. * @discussion The returned dictionary gives Growl the complete list of * notifications this application will ever send, and it also specifies which * notifications should be enabled by default. Each is specified by an array * of NSString objects. * * For most applications, these two arrays can be the same (if all sent * notifications should be displayed by default). * * The NSString objects of these arrays will correspond to the * notificationName: parameter passed in * +[GrowlApplicationBridge * notifyWithTitle:description:notificationName:iconData:priority:isSticky:clickContext:] calls. * * The dictionary should have 2 key object pairs: * key: GROWL_NOTIFICATIONS_ALL object: NSArray of NSString objects * key: GROWL_NOTIFICATIONS_DEFAULT object: NSArray of NSString objects * * You do not need to implement this method if you have an auto-discoverable * plist file in your app bundle. (XXX refer to more information on that) * * @result The NSDictionary to use for registration. */ - (NSDictionary *) registrationDictionaryForGrowl; /*! * @method applicationNameForGrowl * @abstract Return the name of this application which will be used for Growl bookkeeping. * @discussion This name is used both internally and in the Growl preferences. * * This should remain stable between different versions and incarnations of * your application. * For example, "SurfWriter" is a good app name, whereas "SurfWriter 2.0" and * "SurfWriter Lite" are not. * * You do not need to implement this method if you are providing the * application name elsewhere, meaning in an auto-discoverable plist file in * your app bundle (XXX refer to more information on that) or in the result * of -registrationDictionaryForGrowl. * * @result The name of the application using Growl. */ - (NSString *) applicationNameForGrowl; /*! * @method applicationIconDataForGrowl * @abstract Return the NSData to treat as the application icon. * @discussion The delegate may optionally return an NSData * object to use as the application icon; if this is not implemented, the * application's own icon is used. This is not generally needed. * @result The NSData to treat as the application icon. */ - (NSData *) applicationIconDataForGrowl; /*! * @method growlIsReady * @abstract Informs the delegate that Growl has launched. * @discussion Informs the delegate that Growl (specifically, the * GrowlHelperApp) was launched successfully or was already running. The * application can take actions with the knowledge that Growl is installed and * functional. */ - (void) growlIsReady; /*! * @method growlNotificationWasClicked: * @abstract Informs the delegate that a Growl notification was clicked. * @discussion Informs the delegate that a Growl notification was clicked. It * is only sent for notifications sent with a non-nil * clickContext, so if you want to receive a message when a notification is * clicked, clickContext must not be nil when calling * +[GrowlApplicationBridge notifyWithTitle: description:notificationName:iconData:priority:isSticky:clickContext:]. * @param clickContext The clickContext passed when displaying the notification originally via +[GrowlApplicationBridge notifyWithTitle:description:notificationName:iconData:priority:isSticky:clickContext:]. */ - (void) growlNotificationWasClicked:(id)clickContext; /*! * @method growlNotificationTimedOut: * @abstract Informs the delegate that a Growl notification timed out. * @discussion Informs the delegate that a Growl notification timed out. It * is only sent for notifications sent with a non-nil * clickContext, so if you want to receive a message when a notification is * clicked, clickContext must not be nil when calling * +[GrowlApplicationBridge notifyWithTitle: description:notificationName:iconData:priority:isSticky:clickContext:]. * @param clickContext The clickContext passed when displaying the notification originally via +[GrowlApplicationBridge notifyWithTitle:description:notificationName:iconData:priority:isSticky:clickContext:]. */ - (void) growlNotificationTimedOut:(id)clickContext; @end #pragma mark - /*! * @category NSObject(GrowlApplicationBridgeDelegate_Installation_InformalProtocol) * @abstract Methods which may be optionally implemented by the Growl delegate when used with Growl-WithInstaller.framework. * @discussion The methods in this informal protocol will only be called if * implemented by the delegate. They allow greater control of the information * presented to the user when installing or upgrading Growl from within your * application when using Growl-WithInstaller.framework. */ @interface NSObject (GrowlApplicationBridgeDelegate_Installation_InformalProtocol) /*! * @method growlInstallationWindowTitle * @abstract Return the title of the installation window. * @discussion If not implemented, Growl will use a default, localized title. * @result An NSString object to use as the title. */ - (NSString *)growlInstallationWindowTitle; /*! * @method growlUpdateWindowTitle * @abstract Return the title of the upgrade window. * @discussion If not implemented, Growl will use a default, localized title. * @result An NSString object to use as the title. */ - (NSString *)growlUpdateWindowTitle; /*! * @method growlInstallationInformation * @abstract Return the information to display when installing. * @discussion This information may be as long or short as desired (the window * will be sized to fit it). It will be displayed to the user as an * explanation of what Growl is and what it can do in your application. It * should probably note that no download is required to install. * * If this is not implemented, Growl will use a default, localized explanation. * @result An NSAttributedString object to display. */ - (NSAttributedString *)growlInstallationInformation; /*! * @method growlUpdateInformation * @abstract Return the information to display when upgrading. * @discussion This information may be as long or short as desired (the window * will be sized to fit it). It will be displayed to the user as an * explanation that an updated version of Growl is included in your * application and no download is required. * * If this is not implemented, Growl will use a default, localized explanation. * @result An NSAttributedString object to display. */ - (NSAttributedString *)growlUpdateInformation; @end //private @interface GrowlApplicationBridge (GrowlInstallationPrompt_private) + (void) _userChoseNotToInstallGrowl; @end #endif /* __GrowlApplicationBridge_h__ */ amsn-0.98.9/utils/macosx/growl1.0/src/TclGrowler.m0000644000175000017500000000517210737553652021447 0ustar billiobbilliob/* * TclGrowler.m * * Copyright (c) 2005, Toby Peterson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Growl project nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "GrowlApplicationBridge.h" #include "TclGrowler.h" @implementation TclGrowler - (id)initWithName:(NSString *)aName notifications:(NSArray *)notes icon:(NSImage *)aIcon { if ((self = [super init])) { appName = [[NSString alloc] initWithString:aName]; allNotifications = [[NSArray alloc] initWithArray:notes]; appIcon = [[NSData alloc] initWithData:[aIcon TIFFRepresentation]]; [GrowlApplicationBridge setGrowlDelegate:self]; } return self; } - (void)dealloc { [appName release]; [allNotifications release]; [appIcon release]; [super dealloc]; } #pragma mark GrowlApplicationBridgeDelegate - (NSDictionary *)registrationDictionaryForGrowl { return [NSDictionary dictionaryWithObjectsAndKeys: allNotifications, GROWL_NOTIFICATIONS_ALL, allNotifications, GROWL_NOTIFICATIONS_DEFAULT, nil]; } - (NSString *)applicationNameForGrowl { return appName; } - (NSData *)applicationIconDataForGrowl { return appIcon; } - (void)growlIsReady { } - (void)growlNotificationWasClicked:(id)clickContext { } @end amsn-0.98.9/utils/macosx/growl1.0/test.tcl0000644000175000017500000000061111017026572020056 0ustar billiobbilliob lappend auto_path [pwd] package require growl set notifications [list "Test With Spaces" "NoSpace"] growl register "Tcl Test App" ${notifications} "" foreach notification ${notifications} { growl post ${notification} "Test Notification" "Testing notification \"${notification}\"..." } #puts "This notification shouldn't show..." #growl post "__Unknown Notification__" "Title" "Message" amsn-0.98.9/utils/macosx/growl1.0/Rules.mk0000644000175000017500000000037310747207165020033 0ustar billiobbilliobOBJS-growl = $(macosx_dir)/growl1.0/src/libgrowl.dylib TARGETS-growl = $(macosx_dir)/growl1.0/libgrowl.dylib all:: $(TARGETS-growl) $(TARGETS-growl): $(OBJS-growl) cp $< $@ clean:: clean-growl clean-growl:: rm -f $(OBJS-growl) $(TARGETS-growl) amsn-0.98.9/utils/macosx/tclCarbon/0000755000175000017500000000000011757711723016745 5ustar billiobbilliobamsn-0.98.9/utils/macosx/tclCarbon/pkgIndex.tcl0000644000175000017500000000013010757260626021214 0ustar billiobbilliobpackage ifneeded tclCarbon 0.1 "[list load [file join $dir tclCarbon.dylib] tclCarbon]" amsn-0.98.9/utils/macosx/tclCarbon/src/0000755000175000017500000000000011757711630017531 5ustar billiobbilliobamsn-0.98.9/utils/macosx/tclCarbon/src/tclCarbonHICommand.h0000644000175000017500000000143711232112204023312 0ustar billiobbilliob#ifndef __TCLCARBONHICOMMAND_H_INCLUDE #define __TCLCARBONHICOMMAND_H_INCLUDE #ifdef __APPLE__ #define Cursor QD_Cursor #define WindowPtr QD_WindowPtr #define Picture QD_Picture #define BOOL OSX_BOOL #define EventType HIT_EventType #endif #include #ifdef __APPLE__ #undef Cursor #undef WindowPtr #undef Picture #undef BOOL #undef EventType #endif #include "tk.h" #include "tcl.h" #include "tclCarbon.h" typedef struct TkWindowPrivate { Tk_Window *winPtr; CGrafPtr grafPtr; } TkWindowPrivate; int processHICommand(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int enableMenuCommand(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static char * TclCarbonHICommandErr(OSErr err); #endif amsn-0.98.9/utils/macosx/tclCarbon/src/tclCarbon.h0000644000175000017500000000036310757260626021616 0ustar billiobbilliob#ifndef __TCLCARBON_H_INCLUDE #define __TCLCARBON_H_INCLUDE #include "tk.h" #include "tcl.h" #include "tclCarbonNotification.h" #include "tclCarbonHICommand.h" int Tclcarbon_Init(Tcl_Interp *); int Tclcarbon_SafeInit(Tcl_Interp *); #endif amsn-0.98.9/utils/macosx/tclCarbon/src/tclCarbonHICommand.c0000644000175000017500000001400610757260626023330 0ustar billiobbilliob/** * * C code based on Critl original with below copyright. * # ####################################################################### # # tclCarbonHICommand.tcl # # Critcl wrapper for Mac OS X HICommand Carbon Event Manager services. # # Process this file with 'critcl -pkg' to build a loadable package (or # simply source this file if [package require critcl] and a compiler # are available at deployment). # # # Author: Daniel A. Steffen # E-mail: # mail: Mathematics Departement # Macquarie University NSW 2109 Australia # www: # # RCS: @(#) $Id: 13463,v 1.5 2005/02/01 07:01:36 jcw Exp $ # # BSD License: c.f. # # Copyright (c) 2005, Daniel A. Steffen # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # * Redistributions of source code must retain the above # copyright notice, this list of conditions and the # following disclaimer. # # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials # provided with the distribution. # # * Neither the name of Macquarie University nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MACQUARIE # UNIVERSITY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. # # ####################################################################### # \ */ #include "tclCarbonHICommand.h" /* #--------------------------------------------------------------------------------------------------- # # carbon::processHICommand commandID toplevel # # this command takes a Carbon HICommand ID (4 char string, c.f. CarbonEvents.h), and either the # name of a toplevel window (for window specific HICommands) or an empty string (for menu specific # HICommands) and calls ProcessHICommand() with the resulting HICommandExtended structure. # */ int processHICommand(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { if(objc != 3) { Tcl_AppendResult (interp, "Must be carbon::processHICommand commandID toplevel", NULL); return TCL_ERROR; } char *commandID = Tcl_GetStringFromObj(objv[1], NULL); char *toplevel = Tcl_GetStringFromObj(objv[2], NULL); OSErr err; HICommandExtended command; EventRef event; bzero(&command, sizeof(HICommandExtended)); if (strlen(commandID) != sizeof(UInt32)) { Tcl_AppendResult(interp, "Argument commandID needs to be exactly 4 chars long", NULL); return TCL_ERROR; } memcpy(&(command.commandID), commandID, sizeof(UInt32)); #ifdef __LITTLE_ENDIAN__ command.commandID = CFSwapInt32HostToBig(command.commandID); #endif if (strlen(toplevel)) { Tk_Window tkwin = Tk_NameToWindow(interp,toplevel,Tk_MainWindow(interp)); if(!tkwin) return TCL_ERROR; if(!Tk_IsTopLevel(tkwin)) { Tcl_AppendResult(interp, "Window \"", toplevel, "\" is not a toplevel window", NULL); return TCL_ERROR; } command.source.window = GetWindowFromPort( ((TkWindowPrivate*)Tk_WindowId(tkwin))->grafPtr); command.attributes = kHICommandFromWindow; } else { err = GetIndMenuItemWithCommandID(NULL, command.commandID, 1, &command.source.menu.menuRef, &command.source.menu.menuItemIndex); if (err != noErr) { Tcl_AppendResult(interp, "Could not find menu item corresponding to commandID: ", TclCarbonHICommandErr(err), NULL); } else { command.attributes = kHICommandFromMenu; } } err = ProcessHICommand((HICommand*)&command); if (err != noErr) { Tcl_AppendResult(interp, "Could not process command: ", TclCarbonHICommandErr(err), NULL); return TCL_ERROR; } return TCL_OK; } /* #--------------------------------------------------------------------------------------------------- # # carbon::enableMenuCommand commandID disable # # this command takes a Carbon HICommand ID (4 char string, c.f. CarbonEvents.h) of a menu specific # HICommand, and a flag specifing whether to enable (0) or disable (1) the associated menu item. # #--------------------------------------------------------------------------------------------------- */ int enableMenuCommand(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { if(objc != 3) { Tcl_AppendResult (interp, "Must be carbon::enableMenuCommand commandID disable", NULL); return TCL_ERROR; } char *commandID = Tcl_GetStringFromObj(objv[1], NULL); int disable; MenuCommand command; if (strlen(commandID) != sizeof(UInt32)) { Tcl_AppendResult(interp, "Argument commandID needs to be exactly 4 chars long", NULL); return TCL_ERROR; } memcpy(&command, CFSwapInt32HostToBig(commandID), sizeof(UInt32)); #ifdef __LITTLE_ENDIAN__ command = CFSwapInt32HostToBig(command); #endif if (disable) { DisableMenuCommand(NULL, command); } else { EnableMenuCommand(NULL, command); } return TCL_OK; } /* * Helper routine for errors. */ static char * TclCarbonHICommandErr(OSErr err) { static char desc[255]; sprintf(desc, "OS Error: %d.\n", err); return desc; } amsn-0.98.9/utils/macosx/tclCarbon/src/tclCarbon.c0000644000175000017500000000622511234130207021572 0ustar billiobbilliob/** * * C code based on Critl original with below copyright. * #!/bin/sh # ####################################################################### # # tclCarbonNotification.tcl # # Critcl wrapper for Mac OS X Notification Manager services. # # Process this file with 'critcl -pkg' to build a loadable package (or # simply source this file if [package require critcl] and a compiler # are available at deployment). # # # Author: Daniel A. Steffen # E-mail: # mail: Mathematics Departement # Macquarie University NSW 2109 Australia # www: # # RCS: @(#) $Id: 13462,v 1.5 2005/02/01 07:01:31 jcw Exp $ # # BSD License: c.f. # # Copyright (c) 2005, Daniel A. Steffen # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # * Redistributions of source code must retain the above # copyright notice, this list of conditions and the # following disclaimer. # # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials # provided with the distribution. # # * Neither the name of Macquarie University nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MACQUARIE # UNIVERSITY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. # # ####################################################################### # \ */ #include "tclCarbon.h" int Tclcarbon_Init(Tcl_Interp *interp) { if (Tcl_InitStubs(interp, "8.4", 0) == NULL) { return TCL_ERROR; } if (Tk_InitStubs(interp, "8.4", 0) == NULL) { return TCL_ERROR; } // From tclCarbonNotification.h Tcl_CreateObjCommand(interp, "carbon::notification", notification, NULL, NULL); Tcl_CreateObjCommand(interp, "carbon::endNotification", endNotification, NULL, NULL); // From tclCarbonHICommand.h Tcl_CreateObjCommand(interp, "carbon::processHICommand", processHICommand, NULL, NULL); Tcl_CreateObjCommand(interp, "carbon::enableMenuCommand", enableMenuCommand, NULL, NULL); return Tcl_PkgProvide(interp, "tclCarbon", "0.1"); } int Tclcarbon_SafeInit(Tcl_Interp *interp) { return Tclcarbon_Init(interp); } amsn-0.98.9/utils/macosx/tclCarbon/src/tclCarbonNotification.h0000644000175000017500000000137511232112204024142 0ustar billiobbilliob#ifndef __TCLCARBONNOTIFICATION_H_INCLUDE #define __TCLCARBONNOTIFICATION_H_INCLUDE #ifdef __APPLE__ #define Cursor QD_Cursor #define WindowPtr QD_WindowPtr #define Picture QD_Picture #define BOOL OSX_BOOL #define EventType HIT_EventType #endif #include #ifdef __APPLE__ #undef Cursor #undef WindowPtr #undef Picture #undef BOOL #undef EventType #endif #include "tk.h" #include "tcl.h" #include "tclCarbon.h" static int notificationAdded = 0; static NMRec request; int endNotification(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int notification(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static char * TclCarbonNotificationErr(OSErr err); #endif amsn-0.98.9/utils/macosx/tclCarbon/src/Rules.mk0000644000175000017500000000075011000076376021146 0ustar billiobbilliobTARGETS-tclCarbon = $(macosx_dir)/tclCarbon/src/tclCarbon.dylib OBJS-tclCarbon = $(macosx_dir)/tclCarbon/src/tclCarbonHICommand.o $(macosx_dir)/tclCarbon/src/tclCarbonNotification.o $(macosx_dir)/tclCarbon/src/tclCarbon.o LDFLAGS += -framework CoreFoundation -framework Carbon -framework QuickTime all:: $(TARGETS-tclCarbon) $(TARGETS-tclCarbon): $(OBJS-tclCarbon) @$(echo_link_so) @$(link_so) clean:: clean-tclCarbon clean-tclCarbon:: rm -f $(OBJS-tclCarbon) $(TARGET-tclCarbon) amsn-0.98.9/utils/macosx/tclCarbon/src/tclCarbonNotification.c0000644000175000017500000001111610757260626024156 0ustar billiobbilliob/** * * C code based on Critl original with below copyright. * #!/bin/sh # ####################################################################### # # tclCarbonNotification.tcl # # Critcl wrapper for Mac OS X Notification Manager services. # # Process this file with 'critcl -pkg' to build a loadable package (or # simply source this file if [package require critcl] and a compiler # are available at deployment). # # # Author: Daniel A. Steffen # E-mail: # mail: Mathematics Departement # Macquarie University NSW 2109 Australia # www: # # RCS: @(#) $Id: 13462,v 1.5 2005/02/01 07:01:31 jcw Exp $ # # BSD License: c.f. # # Copyright (c) 2005, Daniel A. Steffen # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # * Redistributions of source code must retain the above # copyright notice, this list of conditions and the # following disclaimer. # # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials # provided with the distribution. # # * Neither the name of Macquarie University nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MACQUARIE # UNIVERSITY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. # # ####################################################################### # \ */ #include "tclCarbonNotification.h" /* * Start a notification! */ int notification(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { if(objc != 3) { Tcl_AppendResult (interp, "Must be carbon::notification message bounce", NULL); return TCL_ERROR; } char *msg = Tcl_GetStringFromObj(objv[1], NULL); int bounce; if (Tcl_GetIntFromObj(interp, objv[2], &bounce) == TCL_ERROR) { return TCL_ERROR; } OSErr err; Str255 message; if(notificationAdded) { err = NMRemove(&request); if (err != noErr) { Tcl_AppendResult(interp, "Could not remove notification: ", TclCarbonNotificationErr(err), NULL); return TCL_ERROR; } notificationAdded = 0; } if(strlen(msg)) { CopyCStringToPascal(msg,message); request.nmStr = (StringPtr)&message; } else { request.nmStr = NULL; } request.nmMark = bounce; request.qType = nmType; request.nmSound = NULL; request.nmResp = NULL; err = NMInstall(&request); if (err != noErr) { Tcl_AppendResult(interp, "Could not install notification: ", TclCarbonNotificationErr(err), NULL); return TCL_ERROR; } notificationAdded = 1; return TCL_OK; } /* * End the notification! */ int endNotification(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { if(objc != 1) { Tcl_AppendResult (interp, "No options to carbon::endNotification permitted", NULL); return TCL_ERROR; } OSErr err; if(notificationAdded) { err = NMRemove(&request); if (err != noErr) { Tcl_AppendResult(interp, "Could not remove notification: ", TclCarbonNotificationErr(err), NULL); return TCL_ERROR; } notificationAdded = 0; } return TCL_OK; } /* * Helper routine for errors. */ static char * TclCarbonNotificationErr(OSErr err) { static char desc[255]; sprintf(desc, "OS Error: %d.\n", err); return desc; } amsn-0.98.9/utils/macosx/tclCarbon/Rules.mk0000644000175000017500000000044310757260626020371 0ustar billiobbilliobOBJS-tclCarbon = $(macosx_dir)/tclCarbon/src/tclCarbon.dylib TARGETS-tclCarbon = $(macosx_dir)/tclCarbon/tclCarbon.dylib all:: $(TARGETS-tclCarbon) $(TARGETS-tclCarbon): $(OBJS-tclCarbon) cp $< $@ clean:: clean-tclCarbon clean-tclCarbon:: rm -f $(OBJS-tclCarbon) $(TARGETS-tclCarbon) amsn-0.98.9/utils/macosx/make_dmg/0000755000175000017500000000000011757711630016577 5ustar billiobbilliobamsn-0.98.9/utils/macosx/make_dmg/background.jpg0000755000175000017500000004153311052003201021401 0ustar billiobbilliobJFIFHHExifMM*C  !"$"$Cl"E!12AQq"a#BR3Sb$4Tr%Cc5s,!1"Q2Aaq#bR ?bRjߍ^OVFm>OjL},f~3&?ϺxVg4Sbȱ`M"Ł6,ز,Xb KxSdzZ^Mč{6k\6%D]^f/On>Dx4ȵW#r?rx`KG<2~hRLRiZsD=18c9&ll1:YÿvX6T9,NSJlYbȱ`M"Ł6,س(#kRԈ%l6Vv\lY,!6,ز,Xbȱ`M"Ł6,ز6,ز,Xbȱ`M"Ł6,ز,Xbȱ`M"Ł6,ز,Xbȱ`M"Ł6,ز,Xbȱ`M"ŁtUORi0eO:Sby <\Ƌ~*ydr"D[泽3zQl%|(%LY$g6o=g\QoO9}=xywaَzpp2pgTDƝCW[Lro6|2u.6RŘ:bȲcY$w [@2(IpsIr_ki>Ӎ=GP.O}jbz3&5_mGG+ywp1b/YCosÜ13;G9;9h8s8l8s8l⮣onFC&#,Nž#1Jmwty'T\uHf[z/{Hr".i\Su,VȱdX"bȳOSn,t5fӨjzAb oLO=[zO_zJJӡOuVw;vgcY,6,`X i~V'+'3U,kUUi֑; r=!ҳs"Ċif,#XV5T]KY$i#(خ{kZKUU]h]aR9ːem6ڬG#n lY?/Z1u-#)2GDw5nD@k8rSŗQjMMb1ʱ_ݵ)=;5RI^&*3r1_/ iEKDWeEfc͗6?5*~̱HOq͒5g6q20%VE2tC{l_ ˚=\0ɧZ/[[c>Skgoֳ&{>?r/lLJo6FRo-;cOK5.خ{_X.^֡ge{18I×yVrیqcȝNٽ浞'Oɾf;Qq}Yo_ЬZRzutMO՗3%_e~^F+%^^:kz{r=Q֋Phf\ M,33J4f RynrȦgѽrwlKz:쇝X^kwHym>52(~Ix,.XXz >k4,65\=br#QuU^\. V{rR&dz]U]p_ɍgEVq}dKVMY &>lY>F$&8Ѫ9_Tu?Ѝ"9܌ns<ˌ*91xQIj'?^G/!竛}emyRزcGc*:Ձ:I4}5u]fhqtakQתq;{"pW712u_*,4L̟F1η*%n[̴oZ)9%zsק-U/uͺncjlrcWj#xiSoe-:4yCgG26rWQWj_?^|OH2p~iكYXMZ_ekg"(~$DDsdUk_MDZc{,rQQ/})?G5dDIK‘1UQ7T/pۭQ֓]Ƒ1I Z17EETN9o\mJM1= ~\Q2E|;UDΗgVPȮKvB.W*5y9c򱏷DTI398Zݤ1#q)8x|s)<^iIJzEs·n6GF~^irbd*U+*ּNYPKj4T翴б?˖}O"Xc[fbȨ-,jzÍ.Gi)RQq5WEIv=11:D"D;nE~j^)dXw$muPoi3F d>%ڎۅF:Ҧ &f&Ɠ3{Too^y?LtMOҍO7&ǏIR-=eSS^'76]GSݮiڳr%z^n$LLUb_[r|yixKٝI#حUr9R;SȎޟv˾%j*oVϟTf7$ȋĻz=f'˨꘳GfD%g mæzE.ܵެsOT1gŤk8ki$Ǎyj{K^HJJ)t[Ⱦ#2ªJGl*z,G5\bE*ȕj"lA{ZJ{Z:\w2`NnGUcW=\r)MCn MbIIc[v;hljܼ*Dz=^s y^Ftk,MVSUSCy5m9yTIdkz;<SdIjRX9LDpUsxv"Q[_TEO/jYx Hر[^ߧCş.!rٺ*"Z׉ɇ3^tJ%m{MVru6M um:,xd̉!?U^էDߪruj*&苲@@@elYJҢa\l!_/wG8k4>m9g=n%?mڽZu2b=op,#e9z(n63]Sd^<T{#őV~jy}0z|9xؙ9 s*~*z=?HDtlSm@#-N2q/gymNަ}^568:9ظ߽e7_.*&2q~4]";ۛ٤)MɬM<ԥmt-o=~!/O#Pzt,b=˹>V:|.ã+X7CuЯrXޟV'-S5U~%68NF4ڎM1yؿ9O/_i>'݉1Y#TVMGBDWb/^68Ttt)[Z9bxعnkdV95zy푉#_rƇ.> [ruC'ɕؾoX-m>.#ԉr$[f~_wwLMK2cC&L$;,Djz5T=SScc }|WL2,(jD_H۩pڹæ'?F̎\lwUΗ1#;dTjRRɻt=i6^M{$U6t74f#GGfRM[:5XIF.4zZLG"*nbFe{.WÑS>gF%/mM1"пf:Gq>'2Y^^7y5=*|OF1dla.$OiYU6D%1;i@oMn|dy0OE?&F,Nj56b' .4^,nDws8-V;fMvG.)tNV9\rQUU>J#cf>\ʉw/EU=3I%T6Esն'zۍ4ܼ?E"2[T896x<rO+pɝZd>W'-G6ܖEmFfNƑϗ!s֫ꈴOB9>7%^l9bnW*+Oг h8,#JISӊES4RVAdQB̅ɕLcؽ%2ѽWsr=HUɂl]#'ZDuUx]7 %v&t0VZԶ*$RACml\U^'"+V@p4#34TtwkܼI֣*t"%1ct1^sdstvU6_gYx8RcKƜXYtEuR9izpO$+\9ʈj':z@fId8+ږw64XcO|-;2`~3%9#e}Z%M^р9<.d]>B+lLb#QUzw|}WȂi>;޳9oVMVOPeÑ@vF>75|sȪdYY|ܾa bޓLZ>9Sӯ|DD 5ƑǗhwr[sƢ֙dG|]IG=dzX14;xk)6u^(Rf^3uvők1)w)j"tWhA$X4@4+ZR/)NvLʜ~}SGdtsOֽ)MIcV{ҶZ'hHhk%c-lEʆ<4{m5j v/eߗgȍı{M^Ӌ"/3e@"x!3"*% D,QEUC%T*-hRLǸFZd!U nE VWUU&D iJ!PEU#l*7Pм%ԑ9J.#cQO憚.N? i1#'["~'Zxr0 &EhQj"M@VBM (Qj"EPEPEPDР".$i$ n_[ѣ8D̾ƚF!c C%(DB AAZ]0H2ıP'  /DУ' (Ѝ-dFDPP# gT1 )hgh'D:-$OS2cm~=*EލhQj]ƭ -B -B -B -BDР+BP+BhQj& /B 4^7,oG'p8V4Kz>B%Yo9kpbd%t}+adC7Cꌉؖa6 '-S:"t2Nh 4Z+BP+BP+D4( Т( Т( Т( Т( Т( ODNt|r~v*'gN>M'>E፮r&9gyfܶ=Wd; kXֵ64= 9*5?ȭ㯹x󑧰ZjJBc'eAugb㍫1 1 "%%iUi7#Kmp8Kpb%d%4QBQBeBRazCǔZbN{%Oo QU4uR5 qzD)pÆOW懌TOU"W࿡JUZ蛻}DpU]/1dM)lyfO^s&J˺.ztrw* XHQfI c8ujƓv$N/YYRQ֋*G7N^?aߋS5>\֏ 5CP6/nQxTEPB( ( ( EP(BDz(Qz(Qz(Qz(Qz(Qz(Qz:d@ch ( ( ( ( ( ( aB>Og"^adIJNCI#͎U<^Ml8 =U膚"5/Zx"Ň"7ȣt"kHm2ʈt,i >4 R{ջ944Ob0OofXOT ='< ;{)q翵,QT\$&u(ܵ1k}bJ PT4'TMTEJ^%1:qdeEZ^úVIc՟Ե5pUNSg)jNҒFײb3Ւ1RX̥-KdxŒ6ѱ3U'"I=LXYxo{کhvR+nɓ%z64lmOEQZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZbs͚XDνӹuG*7eSC锝WX`8S~&XR&,ik]B,qH ,xqj) m;P4N(C!U@5s#㏉:4^ӪhO OM*cꛡHOyFʖf/=xP,fͫ˥3蹜}^U7ܿDjJSlV(ԽU 44LX#?'Nȝ-^3cFJJQFJ:d@cFJ:d@cFJ:d@cE:d@cFJ:d@cFJ:ZZZPQj-@cFJ:ZZd@cFJRSuIL_KD񍵎xlc'7R38#3ܩ3,  A h$B(gz~ʔTڔH=7dg< R4Rږ&$QUTwE7Vzt1HC3 'QU9II@ D[ NFG%K GF*9: ZBE "&E JHDZisWRFA4D9U|In&6DinȞ5LyN mSJu(/UBPĭ -B -B -B -B -B -B -B -B -B -@ Т( Т -B -B -B -B -B -B -BQ!9\iZFI^=-_gާt11l50Ï -+RV',0vq&\mYKK^k;n*ZmoU[;Nƕ|̳φnJD_SceGwxy>(;жG+<7Jt[7**-+iSV,Y %;džMu.2d./r[2 _:憊sӿnwp@xٯK͎Ot[6'%_ry+%cz}N<^8dEET^Mg Mm9:J#~9?1#S%`+0$u5>*y;~;袏U~ILDbUCZNyO5VdXM'I^ɗK^ G5>kF.cQ>%Qj yH(Qjh$"Z(QjhQjhMZZ @AZ(QjhQj EPEPD@AHQ -?jL_ӡl:t'>%gn8q$8̋2r1d;UIlWN$Ɠ{n궽TYřW籢w4x,uNqņ7:|(5Y*|:=EVx8ȶ YI'RG*"ZB}&Z3#lh}D蟩;69F1MnSIX{Ҝfm+ʇ$xռ+[_φ[nZ䉵u&d*e4ٛPW|*Wwk,[Q r+8bOCМICdz9Q~҃r'XQ3n6";%$2gG5DDN$o*)KZsz5v9[R1Oy;z5RjQ毻t2&~2w'NX厯_ Ç 5諹iPDۉHigK"+c#VG}m,ˉ=F|)YoETJ9yWuy(߲ؓ䟩ʕ%tWk5ϖ]DInaM"^bzW:J6EDruj|zZkh֍ƞF^4?k}?SfFJrR*+9+vUU께GZsdDrҎ؁|ҶC`c77~|WM=LLF,% x!;)^0˓QbZ\ċ˛uLcTD*#QRzĴYŲC"yl-RTB==yOYO=e> ҄&6:-Z{{򋒞%"Cפ0F_%'fS"atėO` F(ߟfGmE얧 Nk˕>_;o߃h iÌamsn-0.98.9/utils/macosx/make_dmg/view_options.applescript0000644000175000017500000000166311202522642023566 0ustar billiobbilliobtell application "Finder" tell disk "aMSN 0.98ß" -- Set the window up how we want open tell container window set current view to icon view set toolbar visible to false set statusbar visible to false set the bounds to {105, 187, 714, 612} end tell set opts to the icon view options of container window tell opts set icon size to 80 set arrangement to not arranged set label position to bottom end tell set background picture of opts to file ".hidden:background.jpg" set position of file "aMSN.app" to {360, 125} set position of file "Applications" to {530, 125} set position of file "Help & Support.webloc" to {390, 270} set position of file "Plugins & Skins Installer.app" to {500, 270} update without registering applications tell container window set the bounds to {105, 187, 714, 612} end tell update without registering applications delay 5 end tell end tellamsn-0.98.9/utils/macosx/make_dmg/openUp.c0000755000175000017500000000457711202522642020215 0ustar billiobbilliob/* * Copyright (c) 2001 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. * * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * Shantonu Sen * openUp.c - program to set the "first-open-window" field of a volume * * Get the directory ID for the first argument, and set it as word 2 * of the Finder Info fields for the volume it lives on * * cc -o openUp openUp.c * Usage: openUp /Volumes/Foo/OpenMe/ * * RCS: @(#) $Id: openUp.c,v 1.1 2003/08/06 02:15:48 das Exp $ * */ #include #include #include #include #include struct directoryinfo { unsigned long length; u_int32_t dirid; }; struct volumeinfo { unsigned long length; u_int32_t finderinfo[8]; }; int main(int argc, char *argv[]) { char *path = NULL; struct attrlist alist; struct directoryinfo dirinfo; struct volumeinfo volinfo; struct statfs sfs; path = argv[1]; bzero(&alist, sizeof(alist)); alist.bitmapcount = 5; alist.commonattr = ATTR_CMN_OBJID; getattrlist(path, &alist, &dirinfo, sizeof(dirinfo), 0); printf("directory id: %lu\n", dirinfo.dirid); statfs(path, &sfs); printf("mountpoint: %s\n", sfs.f_mntonname); alist.commonattr = ATTR_CMN_FNDRINFO; alist.volattr = ATTR_VOL_INFO; getattrlist(sfs.f_mntonname, &alist, &volinfo, sizeof(volinfo), 0); volinfo.finderinfo[2] = dirinfo.dirid; setattrlist(sfs.f_mntonname, &alist, volinfo.finderinfo, sizeof(volinfo.finderinfo), 0); return 0; } amsn-0.98.9/utils/macosx/make_dmg/openUp0000755000175000017500000010217411202522642017764 0ustar billiobbilliob7 P4|   8__PAGEZERO__TEXT __text__TEXT" __symbol_stub__TEXT,__picsymbol_stub__TEXT,$__symbol_stub1__TEXT,0__cstring__TEXT,$__picsymbolstub1__TEXT. __DATA0 __data__DATA0 __nl_symbol_ptr__DATA0 __la_symbol_ptr__DATA0$L $__dyld__DATA0p p__bss__DATA0x__common__DATA048__LINKEDIT@0 /usr/lib/dyld 4DvSX/usr/lib/libSystem.B.dylib053l P 2*2|("|: x8!T!48!z8;cW{:|H |<@!= |#x|yx|+x!b0 0<@0$/}"Kx@8= 9),H<|i|lxN!HX//A 8BH 9"}"Kx|t/@<@fx"0H8/@<@;FB0B/A|I|LxN!<@B0B/A|I|LxN!H<@B0/A|I|LxN!<`8<8c,HI<| | xN!<`8@8c,H)<`888c-H<`8H8c- H <`8L8c-8H<`8P8c-XHA@/A,8/A H/AL/AP/A|I|Lx?;;-|N!|~xHԀ8x| | xN!H//A 8BH 8b|bx|t/@=`9 9k-t |t/A | 9k|t@`9)K؀Hx| | xN!/A<Lx8| | xN!/AP| | xN!,@;@A,<`8D8c-HaD/AH<@8xexB0Fx#xHH=a,}N =a)}N =a,}N =a&\}N =a,}N =0p}=9N =`k0t}iN |!|> x~x|8`8(HQ|`x8^8x^8|^88(8`-H|`x^88`-8H!|N |B}=|9}N |B}=|9D}N |B}=|9}N |!|> x~x|888`-H|`x@8@ xBHq<_B88/A^8T>+A<_8b`H<_8bHH!|N |B}=|9}N |B}=|9}N |B}=|9}N |!P|> xB~Ȑ88^8B88^<8888 888<8 @8<8^T~8|x|Ex88HX<_8b|xH8~8|xH8^8K<_8b|xH8@@<D8^8K8^<9>\|x|Dx}%Kx8$8H!Xh8^9"K9~<8^\8}#Kx}d[x|x8 8H 8|x!|N |B|H|=9</@!|> x|_xlptx|>^~h<_8bHM|lx<_8B<~h^>|xtpl!|}N ||dxB8_!p8a98Hy8a8|}xH<_}]|~x9"܀B܈ i|].<_x j;xH,@|}xxH9HU8!|N =`0$}N =`0(}N =`0,}N __dyld_make_delayed_module_initializer_calls__dyld_image_count__dyld_get_image_name__dyld_get_image_header__dyld_NSLookupSymbolInImage__dyld_NSAddressOfSymbollibobjc__objcInit__dyld_mod_term_funcsdirectory id: %lu mountpoint: %s printf$LDBL128libSystem.|B}h=k|(}N |B}h=k| }N |B}h=k|}N |B}h=k|}N |B}h=k|}N |B}h=k|}N |B}h=k|}N |B}h=k|d}N |B}h=k|H}N |B}h=k|,}N |B}h=k|}N |B}h=k|}N |B}h=k|}N |B}h=k|}N |B}h=k|}N |B}h=k|}N (&D&D&D&D&D&D&D&D&D&D&D&D&D&D&D&D&D&D&D0 &\3"D&D&l='Tc 0xO+4u+0 0c(0 0 0 09 0L 0f 0 0 0 0 0 0 0;0`)f 0]"w-4@G<BM`mN[`)+9;@\5>V9  -!*)$%'&.(+/123 40,#"-!*)$%'&.(+/123 4_NXArgc_NXArgv___progname__dyld_func_lookup__start_environdyld_stub_binding_helperstart___darwin_gcc3_preregister_frame_info___keymgr_dwarf2_register_sections__cthread_init_routine__mh_execute_header_atexit_catch_exception_raise_catch_exception_raise_state_catch_exception_raise_state_identity_clock_alarm_reply_do_mach_notify_dead_name_do_mach_notify_no_senders_do_mach_notify_port_deleted_do_mach_notify_send_once_do_seqnos_mach_notify_dead_name_do_seqnos_mach_notify_no_senders_do_seqnos_mach_notify_port_deleted_do_seqnos_mach_notify_send_once_errno_exit_mach_init_routine_main_receive_samples___keymgr_global__dyld_register_func_for_add_image__dyld_register_func_for_remove_image__init_keymgr__keymgr_get_and_lock_processwide_ptr__keymgr_set_and_unlock_processwide_ptr_abort_calloc_free_getattrlist_printf$LDBLStub_setattrlist_statfs___stub_getrealaddr_NSAddressOfSymbol_NSIsSymbolNameDefinedWithHint_NSLookupAndBindSymbolWithHint_strcpy_strlen_pointer_to__darwin_gcc3_preregister_frame_info_darwin_unwind_dyld_add_image_hook_darwin_unwind_dyld_remove_image_hook_funcptr P 8__PAGEZERO__TEXT__text__TEXT4U4 __cstring__TEXTp__textcoal_nt__TEXT __DATA __data__DATA __dyld__DATA __common__DATA 4__IMPORT0 __pointers__IMPORT0 __jump_table__IMPORT 0# 8__LINKEDIT@0| /usr/lib/dyld 4)vDX/usr/lib/libSystem.B.dylib0"1 P 1 1 P4j]\$ML$ˉ\$UWVS,} ]E =  u # # # # set -e; if [ -z "$1" -o -z "$2" -o -z "$3" ]; then echo "usage: $0 output_file src_folder volume_name ?applescript? ?eula_resource_file?" exit 1 fi DMG_DIRNAME="`dirname "$1"`" DMG_DIR="`cd "$DMG_DIRNAME" > /dev/null; pwd`" DMG_NAME="`basename "$1"`" DMG_TEMP_NAME="${DMG_DIR}/rw.${DMG_NAME}" SRC_FOLDER="`cd "$2" > /dev/null; pwd`" VOLUME_NAME="$3" # optional arguments APPLESCRIPT="$4" EULA_RSRC="$5" # Create the image echo "creating disk image" rm -f "$DMG_TEMP_NAME" hdiutil create -srcfolder "$SRC_FOLDER" -volname "$VOLUME_NAME" -fs HFS+ -fsargs "-c c=64,a=16,e=16" -format UDRW "$DMG_TEMP_NAME" # mount it echo "mounting disk image" MOUNT_DIR="/Volumes/$VOLUME_NAME" DEV_NAME="`hdiutil attach -readwrite -noverify -noautoopen $DMG_TEMP_NAME | egrep '^/dev/' | sed 1q | awk '{print $1}'`" # run applescript if [ ! -z "${APPLESCRIPT}" -a "${APPLESCRIPT}" != "-null-" ]; then osascript $APPLESCRIPT fi # make sure it's not world writeable echo "fixing permissions" chmod -Rf go-w "${MOUNT_DIR}" || true # make the top window open itself on mount: if [ -x ./openUp ]; then echo "making top window open on mount (openUp)" ./openUp "${MOUNT_DIR}" else echo "making top window open on mount (bless)" bless --openfolder "${MOUNT_DIR}" fi # unmount echo "unmounting disk image" hdiutil detach "$DEV_NAME" # compress image echo "compressing disk image" hdiutil convert "$DMG_TEMP_NAME" -format UDZO -imagekey zlib-level=9 -o "${DMG_DIR}/${DMG_NAME}" rm -f "$DMG_TEMP_NAME" # adding EULA resources if [ ! -z "${EULA_RSRC}" -a "${EULA_RSRC}" != "-null-" ]; then echo "adding EULA resources" hdiutil unflatten "${DMG_DIR}/${DMG_NAME}" /Developer/Tools/ResMerger -a ${EULA_RSRC} -o "${DMG_DIR}/${DMG_NAME}" hdiutil flatten "${DMG_DIR}/${DMG_NAME}" fi echo "disk image done" exit 0 amsn-0.98.9/utils/macosx/windowlist/0000755000175000017500000000000011757711630017236 5ustar billiobbilliobamsn-0.98.9/utils/macosx/windowlist/pkgIndex.tcl0000644000175000017500000000104011202742655021502 0ustar billiobbilliob# Tcl package index file, version 1.1 # This file is generated by the "pkg_mkIndex" command # and sourced either when an application starts up or # by a "package unknown" script. It invokes the # "package ifneeded" command to set up package-related # information so that packages will be loaded automatically # in response to "package require" commands. When this # script is sourced, the variable $dir must contain the # full path name of this file's directory. package ifneeded windowlist 1.1 [list source [file join $dir windowlist.tcl]] amsn-0.98.9/utils/macosx/windowlist/windowlist.tcl0000644000175000017500000000640511306001502022126 0ustar billiobbilliob #windowlist.tcl: provides routines for managing windows from menu, i.e. minimize, raise, bring all to front; standard menu item on Mac OS X. #(c) 2009 WordTech Communications LLC. License: standard Tcl license, http://www.tcl.tk/software/tcltk/license.html #includes code from http://wiki.tcl.tk/1461 ##"cycle through windows" code courtesy of Tom Hennigan, tomhennigan@gmail.com, (c) 2009 package provide windowlist 1.1 namespace eval windowlist { #make the window menu proc windowMenu {mainmenu} { menu $mainmenu.window $mainmenu.window add command -label [trans minimizeplain] -command [namespace current]::minimizeFrontWindow -accelerator "Command-M" $mainmenu.window add separator $mainmenu.window add command -label [trans bringtofront] -command [namespace current]::raiseAllWindows $mainmenu.window add separator $mainmenu.window add command -label [trans cyclewindows] \ -command {raise [lindex [wm stackorder .] 0]} \ -accelerator "Command-`" bind all {raise [lindex [wm stackorder .] 0]} bind all [namespace current]::minimizeFrontWindow bind all [namespace current]::minimizeFrontWindow $mainmenu.window add separator $mainmenu.window add separator $mainmenu add cascade -label [string totitle [trans window]] -menu $mainmenu.window #bind the window menu to update whenever a new window is added, on menu selection bind all <> +[list [namespace current]::updateWindowMenu $mainmenu.window] } #update the window menu with windows proc updateWindowMenu {windowmenu} { # If the window gets destroyed, the windowmenu no longer exists. if { [winfo exists $windowmenu] == 0 } { return } set windowlist [wm stackorder .] if {$windowlist == {}} { return } else { $windowmenu delete 6 end foreach item $windowlist { $windowmenu add command -label "[wm title $item]" -command [list raise $item] } } } #make all windows visible proc raiseAllWindows {} { #blacklist certain windows set blacklist [list .#BWidget .plugins_log .fake .status .degt .nscmd .balloon] #use [winfo children .] here to get windows that are minimized foreach item [winfo children .] { # Check if the window has been blacklisted. if { [lsearch $blacklist $item] != -1 } { continue } #get all toplevel windows, exclude menubar windows if { [string equal [winfo toplevel $item] $item] && [catch {$item cget -tearoff}]} { wm deiconify $item } } #be sure to deiconify ., since the above command only gets the child toplevels wm deiconify . } #minimize the selected window proc minimizeFrontWindow {} { #get list of mapped windows set windowlist [wm stackorder .] #do nothing if all windows are minimized if {$windowlist == {}} { return } else { #minimize topmost window set topwindow [lindex $windowlist end] wm iconify $topwindow } } #demo to show how things work proc demo {} { menu .mb . configure -menu .mb menu .mb.file .mb.file add command -label [trans quit] -command exit .mb add cascade -label [trans file] -menu .mb.file [namespace current]::windowMenu .mb toplevel .a toplevel .b } namespace export * } amsn-0.98.9/utils/macosx/macDock/0000755000175000017500000000000011757711723016377 5ustar billiobbilliobamsn-0.98.9/utils/macosx/macDock/pkgindex.tcl0000644000175000017500000000011010751663702020700 0ustar billiobbilliobpackage ifneeded macDock 0.1 [list load [file join $dir macDock.dylib]] amsn-0.98.9/utils/macosx/macDock/src/0000755000175000017500000000000011757711630017163 5ustar billiobbilliobamsn-0.98.9/utils/macosx/macDock/src/dockIcon.c0000644000175000017500000000511710751663702021063 0ustar billiobbilliob/* This file is part of "aMSN". "aMSN" is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. "aMSN" is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with "aMSN"; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "dockIcon.h" // Tcl command to set the dock icon. int setIcon(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { if(objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathToPNG"); return TCL_ERROR; } UInt8 * path = Tcl_GetStringFromObj(objv[1], NULL); CGImageRef img = getImageRefFromPath(path); if(img == NULL) { Tcl_AppendResult (interp, "couldn't create CGImageRef from path.", (char *) NULL); return TCL_ERROR; } SetApplicationDockTileImage(img); CGImageRelease(img); return TCL_OK; } // Tcl command to set the dock icon. int overlayIcon(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { if(objc != 2) { Tcl_WrongNumArgs(interp, objc, objv, "pathToPNG"); return TCL_ERROR; } UInt8 * path = Tcl_GetStringFromObj(objv[1], NULL); CGImageRef img = getImageRefFromPath(path); if(img == NULL) { Tcl_AppendResult (interp, "couldn't create CGImageRef from path.", (char *) NULL); return TCL_ERROR; } OverlayApplicationDockTileImage(img); CGImageRelease(img); return TCL_OK; } int restoreIcon(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { if(objc > 1) { Tcl_WrongNumArgs(interp, objc, objv, NULL); return TCL_ERROR; } RestoreApplicationDockTileImage(); } // Helper function to create a CGImageRef from a path. CGImageRef getImageRefFromPath(UInt8 * path) { CFURLRef url = NULL; CGDataProviderRef dp = NULL; CGImageRef img = NULL; url = CFURLCreateFromFileSystemRepresentation(\ (CFAllocatorRef)NULL, path, strlen(path), (Boolean)0); if(url == NULL) { return NULL; } dp = CGDataProviderCreateWithURL(url); if(dp == NULL) { CFRelease(url); return NULL; } img = CGImageCreateWithPNGDataProvider(dp, NULL, \ (bool)1, (CGColorRenderingIntent)kCGRenderingIntentDefault); CFRelease(url); CFRelease(dp); if(img == NULL) { return NULL; } return img; } amsn-0.98.9/utils/macosx/macDock/src/macDock.h0000644000175000017500000000155010751664247020702 0ustar billiobbilliob/* This file is part of "aMSN". "aMSN" is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. "aMSN" is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with "aMSN"; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __MACDOCK_H_INCLUDE #define __MACDOCK_H_INCLUDE #include #include "dockIcon.h" int Macdock_Init(Tcl_Interp *); int Macdock_SafeInit(Tcl_Interp *); #endif amsn-0.98.9/utils/macosx/macDock/src/macDock.c0000644000175000017500000000251711231562047020666 0ustar billiobbilliob/* This file is part of "aMSN". "aMSN" is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. "aMSN" is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with "aMSN"; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "macDock.h" int Macdock_Init(Tcl_Interp *interp) { if (Tcl_InitStubs(interp, "8.4", 0) == NULL) { return TCL_ERROR; } Tcl_CreateObjCommand(interp, \ "::macDock::setIcon", setIcon, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, \ "::macDock::overlayIcon", overlayIcon, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateObjCommand(interp, \ "::macDock::restoreIcon", restoreIcon, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); if (Tcl_PkgProvide(interp, "macDock", "0.1") != TCL_OK) { return TCL_ERROR; } return TCL_OK; } int Macdock_SafeInit(Tcl_Interp *interp) { return Macdock_Init(interp); } amsn-0.98.9/utils/macosx/macDock/src/Rules.mk0000644000175000017500000000054010751703333020577 0ustar billiobbilliobTARGETS-macDock = $(macosx_dir)/macDock/src/macDock.dylib OBJS-macDock = $(macosx_dir)/macDock/src/dockIcon.o $(macosx_dir)/macDock/src/macDock.o LDFLAGS += -framework Carbon all:: $(TARGETS-macDock) $(TARGETS-macDock): $(OBJS-macDock) @$(echo_link_so) @$(link_so) clean:: clean-macDock clean-macDock:: rm -f $(OBJS-macDock) $(TARGET-macDock) amsn-0.98.9/utils/macosx/macDock/src/dockIcon.h0000644000175000017500000000215010751664247021067 0ustar billiobbilliob/* This file is part of "aMSN". "aMSN" is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. "aMSN" is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with "aMSN"; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DOCKICON_H_INCLUDE #define __DOCKICON_H_INCLUDE #include #include CGImageRef getImageRefFromPath(UInt8 *); int setIcon(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int overlayIcon(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int restoreIcon(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); #endif amsn-0.98.9/utils/macosx/macDock/Rules.mk0000644000175000017500000000041110751663702020012 0ustar billiobbilliobOBJS-macDock = $(macosx_dir)/macDock/src/macDock.dylib TARGETS-macDock = $(macosx_dir)/macDock/macDock.dylib all:: $(TARGETS-macDock) $(TARGETS-macDock): $(OBJS-macDock) cp $< $@ clean:: clean-macDock clean-macDock:: rm -f $(OBJS-macDock) $(TARGETS-macDock) amsn-0.98.9/utils/macosx/sndplay-src/0000755000175000017500000000000011757711630017272 5ustar billiobbilliobamsn-0.98.9/utils/macosx/sndplay-src/sndplay.m0000644000175000017500000000150010747070156021115 0ustar billiobbilliob#import #import int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; NSSound *sound; if( argc != 2 ) { fprintf(stderr,"Usage: sndplay sound.[snd][aiff][wav]\n "); return -1; } if( strcmp(argv[1],"-?") == 0) { fprintf(stderr,"Usage: sndplay sound.[snd][aiff][wav]\n "); return -1; } if( strcmp(argv[1],"--help") == 0) { fprintf(stderr,"Usage: sndplay sound.[snd][aiff][wav]\n "); return -1; } NS_DURING sound = [[NSSound alloc] initWithContentsOfFile:[NSString stringWithCString:argv[1]] byReference:(bool)false]; [sound play]; while ( [sound isPlaying] ); NS_HANDLER NS_ENDHANDLER [pool release]; return 0; } amsn-0.98.9/utils/macosx/sndplay-src/Rules.mk0000644000175000017500000000061710747103150020707 0ustar billiobbilliobOBJS-sndplay := $(macosx_dir)/sndplay-src/sndplay.o TARGETS-sndplay := $(macosx_dir)/sndplay-src/sndplay FINAL-sndplay := $(macosx_dir)/sndplay LDFLAGS += -framework AppKit $(TARGETS-sndplay): $(OBJS-sndplay) @$(echo_link_app) @$(link_app) $(FINAL-sndplay): $(TARGETS-sndplay) cp $< $@ all:: $(FINAL-sndplay) clean:: clean-sndplay clean-sndplay: rm -f $(TARGETS-sndplay) $(OBJS-sndplay) amsn-0.98.9/utils/macosx/gst_files.txt0000644000175000017500000000251411233427713017550 0ustar billiobbillioblibbz2.1.0.dylib libfsfunnel.so libfsrtcpfilter.so libfsrtpconference.so libfsvideoanyrate.so libglib-2.0.0.dylib libgmodule-2.0.0.dylib libgobject-2.0.0.dylib libgstalaw.so libgstaudio-0.10.0.dylib libgstaudioconvert.so libgstaudiorate.so libgstaudioresample.so libgstaudiotestsrc.so libgstautodetect.so libgstbase-0.10.0.dylib libgstcontroller-0.10.0.dylib libgstcoreelements.so libgstcoreindexers.so libgstdecodebin.so libgstdecodebin2.so libgstdtmf.so libgsteffectv.so libgstfarsight-0.10.0.dylib libgstffmpeg.so libgstffmpegcolorspace.so libgstinterfaces-0.10.0.dylib libgstlevel.so libgstliveadder.so libgstmulaw.so libgstnetbuffer-0.10.0.dylib libgstnice.so libgstoss4audio.so libgstosxaudio.so libgstosxvideosink.so libgstosxvideosrc.so libgstqtdemux.so libgstqtmux.so libgstqueue2.so libgstreamer-0.10.0.dylib libgstrtp-0.10.0.dylib libgstrtp.so libgstrtpmanager.so libgstrtpmux.so libgstselector.so libgstsiren.so libgstspeed.so libgstspeex.so libgsttag-0.10.0.dylib libgsttypefindfunctions.so libgstudp.so libgstvalve.so libgstvideobalance.so libgstvideoflip.so libgstvideoscale.so libgstvideotestsrc.so libgstvolume.so libgthread-2.0.0.dylib libiconv.2.dylib libintl.8.dylib libnice-transmitter.so libnice.0.dylib liboil-0.3.0.dylib librawudp-transmitter.so libspeex.1.dylib libxml2.2.dylib libgstpbutils-0.10.0.dylib libgstvideo-0.10.0.dylib amsn-0.98.9/utils/macosx/statusicon/0000755000175000017500000000000011757711723017232 5ustar billiobbilliobamsn-0.98.9/utils/macosx/statusicon/statusicon-quartz.m0000644000175000017500000001026711400041303023105 0ustar billiobbilliob/* statusicon-quartz.c: * * Copyright (C) 2006 Imendio AB * Copyright (C) 2010 Youness Alaoui * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * GCC on Mac OS X handles inlined objective C in C-files. * * Authors: * Mikael Hallendal * Youness Alaoui */ #include "statusicon-quartz.h" @implementation QuartzStatusIcon : NSObject - (id) initWithCallback:(void *)cb andUserData:(void *)data; { [super init]; ns_bar = [NSStatusBar systemStatusBar]; [ns_bar retain]; callback = cb; user_data = data; return self; } - (void) ensureItem { if (ns_item != nil) return; ns_item = [ns_bar statusItemWithLength:NSVariableStatusItemLength]; [ns_item setAction:@selector(actionCb:)]; [ns_item setDoubleAction:@selector(doubleActionCb:)]; [ns_item setTarget:self]; [ns_item retain]; } - (void) dealloc { [ns_bar removeStatusItem:ns_item]; [image release]; [alternate_image release]; [tooltip release]; [title release]; [ns_item release]; [ns_bar release]; [super dealloc]; } - (void) actionCb:(NSObject *)button { void (*cb)(QuartzStatusIcon *, void *, int) = callback; cb(self, user_data, 0); } - (void) doubleActionCb:(NSObject *)button { void (*cb)(QuartzStatusIcon *, void *, int) = callback; cb(self, user_data, 1); } - (void) setImagePath:(const char *)imagePath { /* Support NULL */ [self ensureItem]; if (image != nil) { [image release]; image = nil; } if (imagePath) { image = [[NSImage alloc] initWithContentsOfFile:[NSString stringWithUTF8String:imagePath]]; if (image) { [image setSize:NSMakeSize([self getWidth], [self getHeight])]; [image retain]; } } [ns_item setImage:image]; } - (void) setAlternateImagePath:(const char *)alternate_imagePath { /* Support NULL */ [self ensureItem]; if (alternate_image != nil) { [alternate_image release]; alternate_image = nil; } if (alternate_imagePath) { alternate_image = [[NSImage alloc] initWithContentsOfFile:[NSString stringWithUTF8String:alternate_imagePath]]; if (alternate_image) { [alternate_image setSize:NSMakeSize([self getWidth], [self getHeight])]; [alternate_image retain]; } } [ns_item setAlternateImage:alternate_image]; } - (void) setVisible:(int)visible { if (visible) { [self ensureItem]; if (image != nil) [ns_item setImage:image]; if (alternate_image != nil) [ns_item setAlternateImage:alternate_image]; if (tooltip != nil) [ns_item setToolTip:tooltip]; if (title != nil) [ns_item setTitle:title]; [ns_item setHighlightMode:highlighted]; } else { [ns_bar removeStatusItem:ns_item]; [ns_item release]; ns_item = nil; } } - (void) setToolTip:(const char *)tooltip_text { [self ensureItem]; if (tooltip != nil) [tooltip release]; tooltip = nil; /* if tooltip_text is nil, raises an exception */ if (tooltip_text) tooltip = [[NSString stringWithUTF8String:tooltip_text] retain]; [ns_item setToolTip:tooltip]; } - (void) setTitle:(const char *)title_text { [self ensureItem]; if (title != nil) [title release]; title = nil; /* if title_text is nil, raises an exception */ if (title_text) title = [[NSString stringWithUTF8String:title_text] retain]; [ns_item setTitle:title]; } - (void) setHighlightMode:(int)highlightMode { highlighted = highlightMode; [ns_item setHighlightMode:highlighted]; } - (float) getWidth { return [ns_bar thickness]; } - (float) getHeight { return [ns_bar thickness]; } @end amsn-0.98.9/utils/macosx/statusicon/pkgindex.tcl0000644000175000017500000000011611262703462021535 0ustar billiobbilliobpackage ifneeded statusicon 0.1 [list load [file join $dir statusicon.dylib]] amsn-0.98.9/utils/macosx/statusicon/statusicon.m0000644000175000017500000002403111400041303021553 0ustar billiobbilliob/* statusicon.c: * * Copyright (C) 2010 Youness Alaoui * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "statusicon.h" #define QUARTZ_POOL_ALLOC NSAutoreleasePool *pool = \ [[NSAutoreleasePool alloc] init] #define QUARTZ_POOL_RELEASE [pool release] static int icon_counter = 0; static Tcl_HashTable *icons = NULL; static Tcl_HashTable *callbacks = NULL; typedef struct { Tcl_Interp *interp; Tcl_Obj *cb; } callback_s; int Statusicon_Create(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { char name[15]; Tcl_HashEntry *hPtr = NULL; int newHash; callback_s *callback = NULL; int ret = TCL_OK; QuartzStatusIcon *status_item = NULL; if(objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "callback"); return TCL_ERROR; } QUARTZ_POOL_ALLOC; callback = (callback_s *) ckalloc(sizeof(callback_s)); callback->interp = interp; callback->cb = objv[1]; Tcl_IncrRefCount(callback->cb); status_item = [[QuartzStatusIcon alloc] initWithCallback:Statusicon_Callback andUserData:callback]; if (status_item == NULL) { Tcl_DecrRefCount(callback->cb); ckfree(callback); ret = TCL_ERROR; } else { sprintf(name, "statusicon%d", ++icon_counter); hPtr = Tcl_CreateHashEntry(icons, name, &newHash); Tcl_SetHashValue(hPtr, (ClientData) status_item); hPtr = Tcl_CreateHashEntry(callbacks, name, &newHash); Tcl_SetHashValue(hPtr, (ClientData) callback); Tcl_ResetResult(interp); Tcl_AppendResult(interp, name, NULL); } QUARTZ_POOL_RELEASE; return ret; } void Statusicon_Callback(QuartzStatusIcon *status_item, void *user_data, int doubleAction) { callback_s * callback = (callback_s *) user_data; Tcl_Obj *action = Tcl_NewStringObj(doubleAction ? "DOUBLE_ACTION" : "ACTION", -1); Tcl_Obj *eval = Tcl_NewStringObj("eval", -1); Tcl_Obj *command[] = {eval, callback->cb, action}; Tcl_Obj *cb = callback->cb; Tcl_IncrRefCount (eval); Tcl_IncrRefCount (action); Tcl_IncrRefCount (cb); if (Tcl_EvalObjv(callback->interp, 3, command, TCL_EVAL_GLOBAL) == TCL_ERROR) { Tcl_BackgroundError(callback->interp); } Tcl_DecrRefCount (eval); Tcl_DecrRefCount (action); Tcl_DecrRefCount (cb); } int Statusicon_SetImage(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { QuartzStatusIcon *status_item; Tcl_HashEntry *hPtr = NULL; char * name = NULL; char * path = NULL; // We verify the arguments if( objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "icon pathToImage"); return TCL_ERROR; } name = Tcl_GetStringFromObj(objv[1], NULL); path = Tcl_GetStringFromObj(objv[2], NULL); hPtr = Tcl_FindHashEntry(icons, name); if (hPtr != NULL) { status_item = (QuartzStatusIcon *) Tcl_GetHashValue(hPtr); } if (!status_item) { Tcl_AppendResult (interp, "Invalid StatusIcon : " , name, (char *) NULL); return TCL_ERROR; } QUARTZ_POOL_ALLOC; [status_item setImagePath:path]; QUARTZ_POOL_RELEASE; return TCL_OK; } int Statusicon_SetAlternateImage(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { QuartzStatusIcon *status_item; Tcl_HashEntry *hPtr = NULL; char * name = NULL; char * path = NULL; // We verify the arguments if( objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "icon pathToImage"); return TCL_ERROR; } name = Tcl_GetStringFromObj(objv[1], NULL); path = Tcl_GetStringFromObj(objv[2], NULL); hPtr = Tcl_FindHashEntry(icons, name); if (hPtr != NULL) { status_item = (QuartzStatusIcon *) Tcl_GetHashValue(hPtr); } if (!status_item) { Tcl_AppendResult (interp, "Invalid StatusIcon : " , name, (char *) NULL); return TCL_ERROR; } QUARTZ_POOL_ALLOC; [status_item setAlternateImagePath:path]; QUARTZ_POOL_RELEASE; return TCL_OK; } int Statusicon_SetTooltip(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { QuartzStatusIcon *status_item; Tcl_HashEntry *hPtr = NULL; char * name = NULL; char * tooltip = NULL; // We verify the arguments if( objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "icon tooltip"); return TCL_ERROR; } name = Tcl_GetStringFromObj(objv[1], NULL); tooltip = Tcl_GetStringFromObj(objv[2], NULL); hPtr = Tcl_FindHashEntry(icons, name); if (hPtr != NULL) { status_item = (QuartzStatusIcon *) Tcl_GetHashValue(hPtr); } if (!status_item) { Tcl_AppendResult (interp, "Invalid StatusIcon : " , name, (char *) NULL); return TCL_ERROR; } QUARTZ_POOL_ALLOC; [status_item setToolTip:tooltip]; QUARTZ_POOL_RELEASE; return TCL_OK; } int Statusicon_SetTitle(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { QuartzStatusIcon *status_item; Tcl_HashEntry *hPtr = NULL; char * name = NULL; char * title = NULL; // We verify the arguments if( objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "icon title"); return TCL_ERROR; } name = Tcl_GetStringFromObj(objv[1], NULL); title = Tcl_GetStringFromObj(objv[2], NULL); hPtr = Tcl_FindHashEntry(icons, name); if (hPtr != NULL) { status_item = (QuartzStatusIcon *) Tcl_GetHashValue(hPtr); } if (!status_item) { Tcl_AppendResult (interp, "Invalid StatusIcon : " , name, (char *) NULL); return TCL_ERROR; } QUARTZ_POOL_ALLOC; [status_item setTitle:title]; QUARTZ_POOL_RELEASE; return TCL_OK; } int Statusicon_SetHighlightMode(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { QuartzStatusIcon *status_item; Tcl_HashEntry *hPtr = NULL; char * name = NULL; int highlighted = 0; // We verify the arguments if( objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "icon highlightMode"); return TCL_ERROR; } name = Tcl_GetStringFromObj(objv[1], NULL); if (Tcl_GetBooleanFromObj(interp, objv[2], &highlighted) != TCL_OK) return TCL_ERROR; hPtr = Tcl_FindHashEntry(icons, name); if (hPtr != NULL) { status_item = (QuartzStatusIcon *) Tcl_GetHashValue(hPtr); } if (!status_item) { Tcl_AppendResult (interp, "Invalid StatusIcon : " , name, (char *) NULL); return TCL_ERROR; } QUARTZ_POOL_ALLOC; [status_item setHighlightMode:highlighted]; QUARTZ_POOL_RELEASE; return TCL_OK; } int Statusicon_SetVisible(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { QuartzStatusIcon *status_item; Tcl_HashEntry *hPtr = NULL; char * name = NULL; int visible = 0; // We verify the arguments if( objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "icon visible"); return TCL_ERROR; } name = Tcl_GetStringFromObj(objv[1], NULL); if (Tcl_GetBooleanFromObj(interp, objv[2], &visible) != TCL_OK) return TCL_ERROR; hPtr = Tcl_FindHashEntry(icons, name); if (hPtr != NULL) { status_item = (QuartzStatusIcon *) Tcl_GetHashValue(hPtr); } if (!status_item) { Tcl_AppendResult (interp, "Invalid StatusIcon : " , name, (char *) NULL); return TCL_ERROR; } QUARTZ_POOL_ALLOC; [status_item setVisible:visible]; QUARTZ_POOL_RELEASE; return TCL_OK; } int Statusicon_Destroy(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { QuartzStatusIcon *status_item; callback_s * callback = NULL; Tcl_HashEntry *hPtr = NULL; char * name = NULL; // We verify the arguments if( objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "icon"); return TCL_ERROR; } name = Tcl_GetStringFromObj(objv[1], NULL); hPtr = Tcl_FindHashEntry(icons, name); if (hPtr != NULL) { status_item = (QuartzStatusIcon *) Tcl_GetHashValue(hPtr); } if (!status_item) { Tcl_AppendResult (interp, "Invalid StatusIcon : " , name, (char *) NULL); return TCL_ERROR; } QUARTZ_POOL_ALLOC; [status_item release]; QUARTZ_POOL_RELEASE; Tcl_DeleteHashEntry(hPtr); hPtr = Tcl_FindHashEntry(callbacks, name); if (hPtr != NULL) { callback = (callback_s *) Tcl_GetHashValue(hPtr); } if (callback) { Tcl_DecrRefCount(callback->cb); ckfree(callback); Tcl_DeleteHashEntry(hPtr); } return TCL_OK; } int Statusicon_Init(Tcl_Interp *interp) { if (Tcl_InitStubs(interp, "8.4", 0) == NULL) { return TCL_ERROR; } NSApplicationLoad(); icons = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable)); Tcl_InitHashTable(icons, TCL_STRING_KEYS); callbacks = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable)); Tcl_InitHashTable(callbacks, TCL_STRING_KEYS); Tcl_CreateObjCommand(interp, "::statusicon::create", Statusicon_Create, NULL, NULL); Tcl_CreateObjCommand(interp, "::statusicon::setImage", Statusicon_SetImage, NULL, NULL); Tcl_CreateObjCommand(interp, "::statusicon::setAlternateImage", Statusicon_SetAlternateImage, NULL, NULL); Tcl_CreateObjCommand(interp, "::statusicon::setTooltip", Statusicon_SetTooltip, NULL, NULL); Tcl_CreateObjCommand(interp, "::statusicon::setTitle", Statusicon_SetTitle, NULL, NULL); Tcl_CreateObjCommand(interp, "::statusicon::setHighlightMode", Statusicon_SetHighlightMode, NULL, NULL); Tcl_CreateObjCommand(interp, "::statusicon::setVisible", Statusicon_SetVisible, NULL, NULL); Tcl_CreateObjCommand(interp, "::statusicon::destroy", Statusicon_Destroy, NULL, NULL); return Tcl_PkgProvide(interp, "statusicon", "0.1"); } int Statusicon_SafeInit(Tcl_Interp *interp) { return Statusicon_Init(interp); } amsn-0.98.9/utils/macosx/statusicon/statusicon-quartz.h0000644000175000017500000000336411400041303023100 0ustar billiobbilliob/* statusicon-quartz.h: * * Copyright (C) 2006 Imendio AB * Copyright (C) 2010 Youness Alaoui * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * GCC on Mac OS X handles inlined objective C in C-files. * * Authors: * Mikael Hallendal * Youness Alaoui */ #import @interface QuartzStatusIcon : NSObject { void *callback; void *user_data; NSStatusBar *ns_bar; NSStatusItem *ns_item; NSImage *image; NSImage *alternate_image; NSString *tooltip; NSString *title; int highlighted; } - (id) initWithCallback:(void *)callback; - (void) ensureItem; - (void) actionCb:(NSObject *)button; - (void) doubleActionCb:(NSObject *)button; - (void) setImagePath:(const char *)imagePath; - (void) setAlternateImagePath:(const char *)alternate_imagePath; - (void) setVisible:(int)visible; - (void) setToolTip:(const char *)tooltip_text; - (void) setTitle:(const char *)title_text; - (void) setHighlightMode:(const char *)highlightMode; - (float) getWidth; - (float) getHeight; @end amsn-0.98.9/utils/macosx/statusicon/statusicon.h0000644000175000017500000000442711400041303021555 0ustar billiobbilliob/* statusicon.h: * * Copyright (C) 2010 Youness Alaoui * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef _STATUS_ICON #define _STATUS_ICON #include #import #import #ifdef __cplusplus extern "C" #endif #include "statusicon-quartz.h" // External functions EXTERN int Statusicon_Init _ANSI_ARGS_((Tcl_Interp *interp)); EXTERN int Statusicon_SafeInit _ANSI_ARGS_((Tcl_Interp *interp)); EXTERN int Statusicon_Create _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Statusicon_SetImage _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Statusicon_SetAlternateImage _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Statusicon_SetVisible _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Statusicon_SetTooltip _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Statusicon_SetTitle _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Statusicon_SetHighlightMode _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Statusicon_Destroy _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); void Statusicon_Callback(QuartzStatusIcon *status_item, void *user_data, int doubleAction); #endif /* _STATUS_ICON */ amsn-0.98.9/utils/macosx/statusicon/Rules.mk0000644000175000017500000000060611262717072020651 0ustar billiobbilliobTARGETS-statusicon = $(macosx_dir)/statusicon/statusicon.dylib OBJS-statusicon = $(macosx_dir)/statusicon/statusicon.o $(macosx_dir)/statusicon/statusicon-quartz.o LDFLAGS += -framework Cocoa all:: $(TARGETS-statusicon) $(TARGETS-statusicon): $(OBJS-statusicon) @$(echo_link_so) @$(link_so) clean:: clean-statusicon clean-statusicon:: rm -f $(OBJS-statusicon) $(TARGET-statusicon) amsn-0.98.9/utils/macosx/aMSN.xcodeproj/0000755000175000017500000000000011757711627017633 5ustar billiobbilliobamsn-0.98.9/utils/macosx/aMSN.xcodeproj/project.pbxproj0000644000175000017500000005675211107134515022706 0ustar billiobbilliob// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 42; objects = { /* Begin PBXAggregateTarget section */ E215602B0B680F7800A2B04A /* amsn-clean */ = { isa = PBXAggregateTarget; buildConfigurationList = E21560310B680F8F00A2B04A /* Build configuration list for PBXAggregateTarget "amsn-clean" */; buildPhases = ( E215602C0B680F7C00A2B04A /* ShellScript */, ); dependencies = ( ); name = "amsn-clean"; productName = "amsn-clean"; }; E27012DF0B67802B00EE2699 /* amsn */ = { isa = PBXAggregateTarget; buildConfigurationList = E27012E70B67806800EE2699 /* Build configuration list for PBXAggregateTarget "amsn" */; buildPhases = ( E27012E20B67803D00EE2699 /* Build */, ); dependencies = ( ); name = amsn; productName = amsn; }; /* End PBXAggregateTarget section */ /* Begin PBXGroup section */ E2700DC70B67644600EE2699 = { isa = PBXGroup; children = ( E2700DD30B67645800EE2699 /* amsn */, E27012D60B6766CB00EE2699 /* Products */, ); sourceTree = ""; }; E2700DD30B67645800EE2699 /* amsn */ = { isa = PBXGroup; children = ( E2700DE50B67645800EE2699 /* autopackage */, E2700DEF0B67645900EE2699 /* build */, E2700E0C0B67645900EE2699 /* debian */, E2700E180B67645900EE2699 /* docs */, E2700E620B67645A00EE2699 /* icons */, E2700E790B67645A00EE2699 /* lang */, E2700EB80B67645B00EE2699 /* plugins */, E2700F040B67645B00EE2699 /* skins */, E270103C0B67645D00EE2699 /* utils */, ); name = amsn; sourceTree = ""; }; E2700DE50B67645800EE2699 /* autopackage */ = { isa = PBXGroup; children = ( E2700DE60B67645800EE2699 /* @tcl.sourceforge.net */, ); path = autopackage; sourceTree = ""; }; E2700DE60B67645800EE2699 /* @tcl.sourceforge.net */ = { isa = PBXGroup; children = ( E2700DE70B67645800EE2699 /* tcl */, E2700DE90B67645800EE2699 /* tk */, ); path = "@tcl.sourceforge.net"; sourceTree = ""; }; E2700DE70B67645800EE2699 /* tcl */ = { isa = PBXGroup; children = ( ); path = tcl; sourceTree = ""; }; E2700DE90B67645800EE2699 /* tk */ = { isa = PBXGroup; children = ( ); path = tk; sourceTree = ""; }; E2700DEF0B67645900EE2699 /* build */ = { isa = PBXGroup; children = ( E2700DF00B67645900EE2699 /* aMSN.build */, ); path = build; sourceTree = ""; }; E2700DF00B67645900EE2699 /* aMSN.build */ = { isa = PBXGroup; children = ( E2700DF10B67645900EE2699 /* aMSN.pbxindex */, ); path = aMSN.build; sourceTree = ""; }; E2700DF10B67645900EE2699 /* aMSN.pbxindex */ = { isa = PBXGroup; children = ( E2700DFA0B67645900EE2699 /* strings.pbxstrings */, ); path = aMSN.pbxindex; sourceTree = ""; }; E2700DFA0B67645900EE2699 /* strings.pbxstrings */ = { isa = PBXGroup; children = ( ); path = strings.pbxstrings; sourceTree = ""; }; E2700E0C0B67645900EE2699 /* debian */ = { isa = PBXGroup; children = ( ); path = debian; sourceTree = ""; }; E2700E180B67645900EE2699 /* docs */ = { isa = PBXGroup; children = ( ); path = docs; sourceTree = ""; }; E2700E620B67645A00EE2699 /* icons */ = { isa = PBXGroup; children = ( E2700E630B67645A00EE2699 /* 128x128 */, E2700E660B67645A00EE2699 /* 32x32 */, E2700E6C0B67645A00EE2699 /* 48x48 */, E2700E710B67645A00EE2699 /* 64x64 */, E2700E750B67645A00EE2699 /* 96x96 */, ); path = icons; sourceTree = ""; }; E2700E630B67645A00EE2699 /* 128x128 */ = { isa = PBXGroup; children = ( ); path = 128x128; sourceTree = ""; }; E2700E660B67645A00EE2699 /* 32x32 */ = { isa = PBXGroup; children = ( ); path = 32x32; sourceTree = ""; }; E2700E6C0B67645A00EE2699 /* 48x48 */ = { isa = PBXGroup; children = ( ); path = 48x48; sourceTree = ""; }; E2700E710B67645A00EE2699 /* 64x64 */ = { isa = PBXGroup; children = ( ); path = 64x64; sourceTree = ""; }; E2700E750B67645A00EE2699 /* 96x96 */ = { isa = PBXGroup; children = ( ); path = 96x96; sourceTree = ""; }; E2700E790B67645A00EE2699 /* lang */ = { isa = PBXGroup; children = ( ); path = lang; sourceTree = ""; }; E2700EB80B67645B00EE2699 /* plugins */ = { isa = PBXGroup; children = ( E2700EB90B67645B00EE2699 /* inkdraw */, E2700ECB0B67645B00EE2699 /* Nudge */, E2700EDE0B67645B00EE2699 /* PowerTool */, E2700EE10B67645B00EE2699 /* remind */, E2700EF00B67645B00EE2699 /* WebcamShooter */, ); path = plugins; sourceTree = ""; }; E2700EB90B67645B00EE2699 /* inkdraw */ = { isa = PBXGroup; children = ( E2700EBB0B67645B00EE2699 /* pencils */, E2700EBE0B67645B00EE2699 /* pixmaps */, ); path = inkdraw; sourceTree = ""; }; E2700EBB0B67645B00EE2699 /* pencils */ = { isa = PBXGroup; children = ( ); path = pencils; sourceTree = ""; }; E2700EBE0B67645B00EE2699 /* pixmaps */ = { isa = PBXGroup; children = ( ); path = pixmaps; sourceTree = ""; }; E2700ECB0B67645B00EE2699 /* Nudge */ = { isa = PBXGroup; children = ( E2700ECC0B67645B00EE2699 /* lang */, ); path = Nudge; sourceTree = ""; }; E2700ECC0B67645B00EE2699 /* lang */ = { isa = PBXGroup; children = ( ); path = lang; sourceTree = ""; }; E2700EDE0B67645B00EE2699 /* PowerTool */ = { isa = PBXGroup; children = ( ); path = PowerTool; sourceTree = ""; }; E2700EE10B67645B00EE2699 /* remind */ = { isa = PBXGroup; children = ( E2700EE20B67645B00EE2699 /* lang */, ); path = remind; sourceTree = ""; }; E2700EE20B67645B00EE2699 /* lang */ = { isa = PBXGroup; children = ( ); path = lang; sourceTree = ""; }; E2700EF00B67645B00EE2699 /* WebcamShooter */ = { isa = PBXGroup; children = ( E2700EF20B67645B00EE2699 /* lang */, ); path = WebcamShooter; sourceTree = ""; }; E2700EF20B67645B00EE2699 /* lang */ = { isa = PBXGroup; children = ( ); path = lang; sourceTree = ""; }; E2700F040B67645B00EE2699 /* skins */ = { isa = PBXGroup; children = ( E2700F050B67645B00EE2699 /* default */, ); path = skins; sourceTree = ""; }; E2700F050B67645B00EE2699 /* default */ = { isa = PBXGroup; children = ( E2700F070B67645B00EE2699 /* displaypic */, E2700F210B67645C00EE2699 /* pixmaps */, E2700FCF0B67645C00EE2699 /* smileys */, E27010210B67645D00EE2699 /* sounds */, E27010280B67645D00EE2699 /* winicons */, ); path = default; sourceTree = ""; }; E2700F070B67645B00EE2699 /* displaypic */ = { isa = PBXGroup; children = ( ); path = displaypic; sourceTree = ""; }; E2700F210B67645C00EE2699 /* pixmaps */ = { isa = PBXGroup; children = ( ); path = pixmaps; sourceTree = ""; }; E2700FCF0B67645C00EE2699 /* smileys */ = { isa = PBXGroup; children = ( ); path = smileys; sourceTree = ""; }; E27010210B67645D00EE2699 /* sounds */ = { isa = PBXGroup; children = ( ); path = sounds; sourceTree = ""; }; E27010280B67645D00EE2699 /* winicons */ = { isa = PBXGroup; children = ( ); path = winicons; sourceTree = ""; }; E270103C0B67645D00EE2699 /* utils */ = { isa = PBXGroup; children = ( E270103F0B67645D00EE2699 /* base64 */, E27010440B67645D00EE2699 /* bwidget1.8.0 */, E27010920B67645E00EE2699 /* combobox */, E27010950B67645E00EE2699 /* contentmanager */, E27010980B67645E00EE2699 /* dpbrowser */, E270109B0B67645E00EE2699 /* drawboard */, E270109F0B67645E00EE2699 /* framec */, E27010A20B67645E00EE2699 /* http */, E27010A50B67645E00EE2699 /* linux */, E27010E40B67645F00EE2699 /* log */, E27010EC0B67645F00EE2699 /* macosx */, E27011270B67645F00EE2699 /* pixmapbutton */, E27011400B67646000EE2699 /* pixmapmenu */, E27011470B67646000EE2699 /* pixmapoption */, E27011510B67646000EE2699 /* pixmapprogbar */, E27011560B67646000EE2699 /* pixmapscroll */, E270118E0B67646000EE2699 /* scalable-bg */, E27011920B67646000EE2699 /* sexytile */, E27011970B67646000EE2699 /* sha1 */, E270119A0B67646000EE2699 /* snit */, E27011A00B67646100EE2699 /* tcl_siren */, E27011BE0B67646100EE2699 /* tcldom */, E27011C30B67646100EE2699 /* tclsoap1.6.7 */, E27011D70B67646100EE2699 /* Tclxml */, E27011E30B67646100EE2699 /* TkCximage */, E27012340B67646200EE2699 /* toolbar */, E27012370B67646200EE2699 /* uri */, E270123B0B67646200EE2699 /* webcamsn */, E27012700B67646300EE2699 /* windows */, ); path = utils; sourceTree = ""; }; E270103F0B67645D00EE2699 /* base64 */ = { isa = PBXGroup; children = ( ); path = base64; sourceTree = ""; }; E27010440B67645D00EE2699 /* bwidget1.8.0 */ = { isa = PBXGroup; children = ( E27010510B67645D00EE2699 /* images */, E27010750B67645E00EE2699 /* lang */, ); path = bwidget1.8.0; sourceTree = ""; }; E27010510B67645D00EE2699 /* images */ = { isa = PBXGroup; children = ( ); path = images; sourceTree = ""; }; E27010750B67645E00EE2699 /* lang */ = { isa = PBXGroup; children = ( ); path = lang; sourceTree = ""; }; E27010920B67645E00EE2699 /* combobox */ = { isa = PBXGroup; children = ( ); path = combobox; sourceTree = ""; }; E27010950B67645E00EE2699 /* contentmanager */ = { isa = PBXGroup; children = ( ); path = contentmanager; sourceTree = ""; }; E27010980B67645E00EE2699 /* dpbrowser */ = { isa = PBXGroup; children = ( ); path = dpbrowser; sourceTree = ""; }; E270109B0B67645E00EE2699 /* drawboard */ = { isa = PBXGroup; children = ( ); path = drawboard; sourceTree = ""; }; E270109F0B67645E00EE2699 /* framec */ = { isa = PBXGroup; children = ( ); path = framec; sourceTree = ""; }; E27010A20B67645E00EE2699 /* http */ = { isa = PBXGroup; children = ( ); path = http; sourceTree = ""; }; E27010A50B67645E00EE2699 /* linux */ = { isa = PBXGroup; children = ( E27010A60B67645E00EE2699 /* capture */, E27010DA0B67645F00EE2699 /* linflash */, E27010DF0B67645F00EE2699 /* traydock */, ); path = linux; sourceTree = ""; }; E27010A60B67645E00EE2699 /* capture */ = { isa = PBXGroup; children = ( E27010AB0B67645E00EE2699 /* libng */, E27010D00B67645F00EE2699 /* structs */, ); path = capture; sourceTree = ""; }; E27010AB0B67645E00EE2699 /* libng */ = { isa = PBXGroup; children = ( E27010BF0B67645E00EE2699 /* plugins */, ); path = libng; sourceTree = ""; }; E27010BF0B67645E00EE2699 /* plugins */ = { isa = PBXGroup; children = ( ); path = plugins; sourceTree = ""; }; E27010D00B67645F00EE2699 /* structs */ = { isa = PBXGroup; children = ( ); path = structs; sourceTree = ""; }; E27010DA0B67645F00EE2699 /* linflash */ = { isa = PBXGroup; children = ( ); path = linflash; sourceTree = ""; }; E27010DF0B67645F00EE2699 /* traydock */ = { isa = PBXGroup; children = ( ); path = traydock; sourceTree = ""; }; E27010E40B67645F00EE2699 /* log */ = { isa = PBXGroup; children = ( E27010E90B67645F00EE2699 /* msgs */, ); path = log; sourceTree = ""; }; E27010E90B67645F00EE2699 /* msgs */ = { isa = PBXGroup; children = ( ); path = msgs; sourceTree = ""; }; E27010EC0B67645F00EE2699 /* macosx */ = { isa = PBXGroup; children = ( E27010ED0B67645F00EE2699 /* applescript */, E27010EF0B67645F00EE2699 /* Ffidl0.6 */, E27010F40B67645F00EE2699 /* growl1.0 */, E27010F90B67645F00EE2699 /* snack2.2 */, E27010FF0B67645F00EE2699 /* tclAE2.0 */, E270110F0B67645F00EE2699 /* tclCarbonHICommand */, E27011150B67645F00EE2699 /* tclCarbonNotification */, E270111B0B67645F00EE2699 /* TkCximage */, E270111E0B67645F00EE2699 /* tkUnsupported */, E27011200B67645F00EE2699 /* tls1.50 */, E27011240B67645F00EE2699 /* webcamsn */, ); path = macosx; sourceTree = ""; }; E27010ED0B67645F00EE2699 /* applescript */ = { isa = PBXGroup; children = ( ); path = applescript; sourceTree = ""; }; E27010EF0B67645F00EE2699 /* Ffidl0.6 */ = { isa = PBXGroup; children = ( ); path = Ffidl0.6; sourceTree = ""; }; E27010F40B67645F00EE2699 /* growl1.0 */ = { isa = PBXGroup; children = ( ); path = growl1.0; sourceTree = ""; }; E27010F90B67645F00EE2699 /* snack2.2 */ = { isa = PBXGroup; children = ( ); path = snack2.2; sourceTree = ""; }; E27010FF0B67645F00EE2699 /* tclAE2.0 */ = { isa = PBXGroup; children = ( E27011000B67645F00EE2699 /* Contents */, ); path = tclAE2.0; sourceTree = ""; }; E27011000B67645F00EE2699 /* Contents */ = { isa = PBXGroup; children = ( E27011020B67645F00EE2699 /* MacOS */, E27011040B67645F00EE2699 /* MacOSClassic */, E27011060B67645F00EE2699 /* Resources */, ); path = Contents; sourceTree = ""; }; E27011020B67645F00EE2699 /* MacOS */ = { isa = PBXGroup; children = ( ); path = MacOS; sourceTree = ""; }; E27011040B67645F00EE2699 /* MacOSClassic */ = { isa = PBXGroup; children = ( ); path = MacOSClassic; sourceTree = ""; }; E27011060B67645F00EE2699 /* Resources */ = { isa = PBXGroup; children = ( ); path = Resources; sourceTree = ""; }; E270110F0B67645F00EE2699 /* tclCarbonHICommand */ = { isa = PBXGroup; children = ( E27011110B67645F00EE2699 /* src */, ); path = tclCarbonHICommand; sourceTree = ""; }; E27011110B67645F00EE2699 /* src */ = { isa = PBXGroup; children = ( ); path = src; sourceTree = ""; }; E27011150B67645F00EE2699 /* tclCarbonNotification */ = { isa = PBXGroup; children = ( E27011170B67645F00EE2699 /* src */, ); path = tclCarbonNotification; sourceTree = ""; }; E27011170B67645F00EE2699 /* src */ = { isa = PBXGroup; children = ( ); path = src; sourceTree = ""; }; E270111B0B67645F00EE2699 /* TkCximage */ = { isa = PBXGroup; children = ( ); path = TkCximage; sourceTree = ""; }; E270111E0B67645F00EE2699 /* tkUnsupported */ = { isa = PBXGroup; children = ( ); path = tkUnsupported; sourceTree = ""; }; E27011200B67645F00EE2699 /* tls1.50 */ = { isa = PBXGroup; children = ( ); path = tls1.50; sourceTree = ""; }; E27011240B67645F00EE2699 /* webcamsn */ = { isa = PBXGroup; children = ( ); path = webcamsn; sourceTree = ""; }; E27011270B67645F00EE2699 /* pixmapbutton */ = { isa = PBXGroup; children = ( ); path = pixmapbutton; sourceTree = ""; }; E27011400B67646000EE2699 /* pixmapmenu */ = { isa = PBXGroup; children = ( ); path = pixmapmenu; sourceTree = ""; }; E27011470B67646000EE2699 /* pixmapoption */ = { isa = PBXGroup; children = ( ); path = pixmapoption; sourceTree = ""; }; E27011510B67646000EE2699 /* pixmapprogbar */ = { isa = PBXGroup; children = ( ); path = pixmapprogbar; sourceTree = ""; }; E27011560B67646000EE2699 /* pixmapscroll */ = { isa = PBXGroup; children = ( E27011570B67646000EE2699 /* horizontal */, E27011740B67646000EE2699 /* vertical */, ); path = pixmapscroll; sourceTree = ""; }; E27011570B67646000EE2699 /* horizontal */ = { isa = PBXGroup; children = ( ); path = horizontal; sourceTree = ""; }; E27011740B67646000EE2699 /* vertical */ = { isa = PBXGroup; children = ( ); path = vertical; sourceTree = ""; }; E270118E0B67646000EE2699 /* scalable-bg */ = { isa = PBXGroup; children = ( ); path = "scalable-bg"; sourceTree = ""; }; E27011920B67646000EE2699 /* sexytile */ = { isa = PBXGroup; children = ( ); path = sexytile; sourceTree = ""; }; E27011970B67646000EE2699 /* sha1 */ = { isa = PBXGroup; children = ( ); path = sha1; sourceTree = ""; }; E270119A0B67646000EE2699 /* snit */ = { isa = PBXGroup; children = ( ); path = snit; sourceTree = ""; }; E27011A00B67646100EE2699 /* tcl_siren */ = { isa = PBXGroup; children = ( E27011A30B67646100EE2699 /* src */, ); path = tcl_siren; sourceTree = ""; }; E27011A30B67646100EE2699 /* src */ = { isa = PBXGroup; children = ( ); path = src; sourceTree = ""; }; E27011BE0B67646100EE2699 /* tcldom */ = { isa = PBXGroup; children = ( ); path = tcldom; sourceTree = ""; }; E27011C30B67646100EE2699 /* tclsoap1.6.7 */ = { isa = PBXGroup; children = ( E27011C80B67646100EE2699 /* interop */, ); path = tclsoap1.6.7; sourceTree = ""; }; E27011C80B67646100EE2699 /* interop */ = { isa = PBXGroup; children = ( ); path = interop; sourceTree = ""; }; E27011D70B67646100EE2699 /* Tclxml */ = { isa = PBXGroup; children = ( ); path = Tclxml; sourceTree = ""; }; E27011E30B67646100EE2699 /* TkCximage */ = { isa = PBXGroup; children = ( E27011E40B67646100EE2699 /* demos */, E27011EE0B67646100EE2699 /* src */, ); path = TkCximage; sourceTree = ""; }; E27011E40B67646100EE2699 /* demos */ = { isa = PBXGroup; children = ( ); path = demos; sourceTree = ""; }; E27011EE0B67646100EE2699 /* src */ = { isa = PBXGroup; children = ( E27011EF0B67646100EE2699 /* CxImage */, ); path = src; sourceTree = ""; }; E27011EF0B67646100EE2699 /* CxImage */ = { isa = PBXGroup; children = ( ); path = CxImage; sourceTree = ""; }; E27012340B67646200EE2699 /* toolbar */ = { isa = PBXGroup; children = ( ); path = toolbar; sourceTree = ""; }; E27012370B67646200EE2699 /* uri */ = { isa = PBXGroup; children = ( ); path = uri; sourceTree = ""; }; E270123B0B67646200EE2699 /* webcamsn */ = { isa = PBXGroup; children = ( E270123F0B67646200EE2699 /* doc */, E27012480B67646200EE2699 /* src */, ); path = webcamsn; sourceTree = ""; }; E270123F0B67646200EE2699 /* doc */ = { isa = PBXGroup; children = ( ); path = doc; sourceTree = ""; }; E27012480B67646200EE2699 /* src */ = { isa = PBXGroup; children = ( ); path = src; sourceTree = ""; }; E27012700B67646300EE2699 /* windows */ = { isa = PBXGroup; children = ( E27012710B67646300EE2699 /* launcher */, E27012790B67646300EE2699 /* NSIS */, E27012800B67646300EE2699 /* snack2.2 */, E27012860B67646300EE2699 /* winflash */, E270128E0B67646300EE2699 /* winico0.6 */, E27012920B67646300EE2699 /* winutils */, ); path = windows; sourceTree = ""; }; E27012710B67646300EE2699 /* launcher */ = { isa = PBXGroup; children = ( ); path = launcher; sourceTree = ""; }; E27012790B67646300EE2699 /* NSIS */ = { isa = PBXGroup; children = ( ); path = NSIS; sourceTree = ""; }; E27012800B67646300EE2699 /* snack2.2 */ = { isa = PBXGroup; children = ( ); path = snack2.2; sourceTree = ""; }; E27012860B67646300EE2699 /* winflash */ = { isa = PBXGroup; children = ( ); path = winflash; sourceTree = ""; }; E270128E0B67646300EE2699 /* winico0.6 */ = { isa = PBXGroup; children = ( ); path = winico0.6; sourceTree = ""; }; E27012920B67646300EE2699 /* winutils */ = { isa = PBXGroup; children = ( ); path = winutils; sourceTree = ""; }; E27012D60B6766CB00EE2699 /* Products */ = { isa = PBXGroup; children = ( ); name = Products; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXProject section */ E2700DC90B67644600EE2699 /* Project object */ = { isa = PBXProject; buildConfigurationList = E2700DCA0B67644600EE2699 /* Build configuration list for PBXProject "aMSN" */; hasScannedForEncodings = 0; mainGroup = E2700DC70B67644600EE2699; productRefGroup = E27012D60B6766CB00EE2699 /* Products */; projectDirPath = ""; targets = ( E27012DF0B67802B00EE2699 /* amsn */, E215602B0B680F7800A2B04A /* amsn-clean */, ); }; /* End PBXProject section */ /* Begin PBXShellScriptBuildPhase section */ E215602C0B680F7C00A2B04A /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "make clean\n\nrm config.status config.log Makefile utils/tcl_siren/tcl_siren.so\nrm utils/TkCximage/TkCximage.so utils/webcamsn/webcamsn.so utils/linux/capture/config.h"; }; E27012E20B67803D00EE2699 /* Build */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = Build; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "cd $PROJECT_DIR\n\n# Clear up from previous builds.\nrm -rf build/\n\nif [ -f Makefile ]; then\n\techo \"Already configured.\"\nelse\n\t./configure\nfi\n\nmake\n\nutils/macosx/finishbuild.sh"; }; /* End PBXShellScriptBuildPhase section */ /* Begin XCBuildConfiguration section */ E21560320B680F8F00A2B04A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = YES; GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; PRODUCT_NAME = "amsn-clean"; ZERO_LINK = NO; }; name = Release; }; E2700DCC0B67644600EE2699 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = YES; }; name = Release; }; E27012E80B67806800EE2699 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = YES; GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; PRODUCT_NAME = amsn; ZERO_LINK = NO; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ E21560310B680F8F00A2B04A /* Build configuration list for PBXAggregateTarget "amsn-clean" */ = { isa = XCConfigurationList; buildConfigurations = ( E21560320B680F8F00A2B04A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; E2700DCA0B67644600EE2699 /* Build configuration list for PBXProject "aMSN" */ = { isa = XCConfigurationList; buildConfigurations = ( E2700DCC0B67644600EE2699 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; E27012E70B67806800EE2699 /* Build configuration list for PBXAggregateTarget "amsn" */ = { isa = XCConfigurationList; buildConfigurations = ( E27012E80B67806800EE2699 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = E2700DC90B67644600EE2699 /* Project object */; } amsn-0.98.9/utils/macosx/tkUnsupported/0000755000175000017500000000000011757711613017723 5ustar billiobbilliobamsn-0.98.9/utils/macosx/tkUnsupported/pkgIndex.tcl0000644000175000017500000000031710626570250022173 0ustar billiobbilliob#package ifneeded tkUnsupported 1.0 "source [file join $dir dockicon_api.tcl]; source [file join $dir macWindowStyle.tcl]" package ifneeded tkUnsupported 1.0 [list source [file join $dir macWindowStyle.tcl]]amsn-0.98.9/utils/macosx/tkUnsupported/macWindowStyle.tcl0000644000175000017500000000250411524172556023400 0ustar billiobbilliob# macWindowStyle.tcl # An API for accesing the unsupported window styles in Tk Aqua. # Thursday, 5th October 2006 # By Tom Hennigan (tomhennigan[at]gmail[dot]com) # CF. http://wiki.tcl.tk/14518, http://wiki.tcl.tk/13428 ::tk::unsupported::MacWindowStyle style . document [list closeBox verticalZoom collapseBox resizable] rename toplevel Tk_toplevel proc toplevel { pathname args } { set window [eval Tk_toplevel [list $pathname] $args] catch {::macWindowStyle::setBrushed $window} return $window } namespace eval macWindowStyle { # Cached variable storing the system version IE. 10.3.9, 10.4.10 or 10.5.1 proc setBrushed {w} { if { [systemSupportsBrushed] && [::skin::getKey usebrushedmetal 0] && [::config::getKey allowbrushedmetal 1] } { catch [list ::tk::unsupported::MacWindowStyle style $w document [list closeBox horizontalZoom verticalZoom collapseBox resizable metal]] } } proc systemSupportsBrushed { } { set r 1 set macos_version [exec sw_vers -productVersion] if { [package vcompare 10.5.0 $macos_version] == -1 } { status_log "::macWindowStyle::setBrushed - style disabled (os version: $macos_version)" white set r 0 } # Cache the result of this call. rename ::macWindowStyle::systemSupportsBrushed {} proc ::macWindowStyle::systemSupportsBrushed {} [list return $r] return $r } } amsn-0.98.9/utils/macosx/startbuild.sh0000644000175000017500000000065211255125103017532 0ustar billiobbilliobecho "Make sure you run this with '. ./utils/macosx/startbuild.sh' (start with a dot then space then path) so that the exported variables affect your current shell" export CC="gcc-4.0" export CXX="g++-4.0" export CFLAGS='-arch ppc -arch i386 -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.3' export CXXFLAGS=$CFLAGS export LDFLAGS="$CFLAGS -headerpad_max_install_names" export MACOSX_DEPLOYMENT_TARGET=10.3 amsn-0.98.9/utils/macosx/applescript/0000755000175000017500000000000011757711613017362 5ustar billiobbilliobamsn-0.98.9/utils/macosx/applescript/ae.tcl0000755000175000017500000000327510567435163020466 0ustar billiobbilliob ::Version::setSubversionId {$Id: ae.tcl 8064 2007-02-23 00:50:59Z lephilousophe $} #Here we add the code to make aMSN accept AppleEvent from "Do Script" command in AppleScript #Thanks to Jon Guyer package require tclAE tclAE::installEventHandler misc dosc handleDoScript tclAE::aete::register constructAETE proc handleDoScript {theAppleEvent theReplyAE} { set scriptDesc [tclAE::getKeyDesc $theAppleEvent ----] set type [tclAE::getDescType $scriptDesc] switch -- $type { "TEXT" - "utxt" - "STXT" { eval [tclAE::getData $scriptDesc utxt] } "alis" { source [tclAE::getData $scriptDesc TEXT] } default { set errn -1770 set errs "AEDoScriptHandler: invalid script type '${type}', \ must be 'alis', 'TEXT', 'utxt', or 'STXT'" status::msg $errs tclAE::putKeyData $theReplyAE errs TEXT $errs tclAE::putKeyData $theReplyAE errn long $errn return $errn } } } proc constructAETE {} { set events {} set enumerations {} set enumerators {} lappend enumerators [list "Tcl instructions" utxt "Tcl script code to execute"] lappend enumerators [list "alias" alis "alias of a .tcl script file to source"] lappend enumerations [list ScAl $enumerators] lappend events [list "my do script" \ "Execute a Tcl (Tool Command Language) script" misc dosc \ {null "" 000} {ScAl "the Tcl script to execute" 0011}] lappend suites [list "Miscellaneous Standards Suite" \ "Useful events that aren't in any other suite." \ misc 1 1 $events {} {} $enumerations] return [list 1 0 0 0 $suites] } amsn-0.98.9/utils/macosx/cp_gstreamer.sh0000755000175000017500000000150411233427713020040 0ustar billiobbilliob rm ~/amsn/utils/macosx/gstreamer/*.so rm ~/amsn/utils/macosx/gstreamer/*.dylib for software in $(echo gettext libiconv glib2 libxml2 liboil gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-ffmpeg farsight2 libnice bzip2 speex); do cp /opt/local/var/macports/software/$software/*+universal/opt/local/lib/*.dylib ~/amsn/utils/macosx/gstreamer/ cp /opt/local/var/macports/software/$software/*+universal/opt/local/lib/gstreamer-0.10/*.so ~/amsn/utils/macosx/gstreamer/ cp /opt/local/var/macports/software/$software/*+universal/opt/local/lib/farsight2-0.0/*.so ~/amsn/utils/macosx/gstreamer/ done for file in ~/amsn/utils/macosx/gstreamer/*.so ~/amsn/utils/macosx/gstreamer/*.dylib; do base=`basename $file` if [ x`grep "$base" ~/amsn/utils/macosx/gst_files.txt ` == "x" ] ; then rm $file fi done amsn-0.98.9/utils/macosx/snack2.2/0000755000175000017500000000000011757711723016357 5ustar billiobbilliobamsn-0.98.9/utils/macosx/snack2.2/pkgIndex.tcl0000644000175000017500000000071311231716620020621 0ustar billiobbilliob# # Immediate loading of Snack because of item types etc. # # http://www.wjduquette.com/tcl/namespaces.html # package ifneeded snack 2.2 "[list load [file join $dir libsnack.dylib]];[list source [file join $dir snack.tcl]]" package ifneeded sound 2.2 [list load [file join $dir libsound.dylib]] package ifneeded snacksphere 1.2 [list load [file join $dir libsnacksphere.dylib]] package ifneeded snackogg 1.3 [list load [file join $dir libsnackogg.dylib]] amsn-0.98.9/utils/macosx/snack2.2/patches/0000755000175000017500000000000011757711613020004 5ustar billiobbilliobamsn-0.98.9/utils/macosx/snack2.2/patches/jkAudIO_osx.c.patch0000644000175000017500000001321611075465612023426 0ustar billiobbilliob--- jkAudIO_osx.c.orig 2005-12-14 03:29:38.000000000 -0800 +++ jkAudIO_osx.c 2006-11-06 20:43:08.000000000 -0800 @@ -30,6 +30,15 @@ extern void Snack_WriteLog(char *s); extern void Snack_WriteLogInt(char *s, int n); +/* Define for debugging */ +#undef SNACK_DEBUG_MACOSX + +#ifdef SNACK_DEBUG_MACOSX +#define XXDEBUG(X) X +#else +#define XXDEBUG(X) ; +#endif + #ifndef min #define min(a,b) ((a)<(b)?(a):(b)) #define max(a,b) ((a)>(b)?(a):(b)) @@ -42,7 +51,8 @@ #define BUFLEN (44100*2) static short otmp[BUFLEN]; static float itmp[BUFLEN]; -static int usageCount = 0; +static int AIusageCount = 0; +static int AOusageCount = 0; static float rate; static ADesc *AO = NULL; static ADesc *AI = NULL; @@ -60,18 +70,18 @@ float *in = inInputData->mBuffers[0].mData; /* printf("w %d r %d %d %d\n", A->wpos, A->rpos, numFrames*2, A->nChannels);*/ - if (AO != NULL && AO->mode == PLAY) { + if (AO != NULL && AO->mode == PLAY && out != NULL) { for (i = 0; i < numFrames*A->nChannels; ++i) { *out++ = (float) (otmp[(A->rpos*A->nChannels + i) % BUFLEN] / 32768.0); - if (A->nChannels == 1) { - *out++ = (float) (otmp[(A->rpos*A->nChannels + i) % BUFLEN] / 32768.0); - } + if (A->nChannels == 1) { + *out++ = (float) (otmp[(A->rpos*A->nChannels + i) % BUFLEN] / 32768.0); + } } A->rpos = (A->rpos + numFrames) % (BUFLEN/A->nChannels); } - /* printf("appIOProc wpos %d %d %d\n", - A->wpos,numFrames,inInputData->mNumberBuffers);*/ - if (AI != NULL && AI->mode == RECORD) { + + /* printf("appIOProc wpos %d %d %d\n", A->wpos,numFrames,inInputData->mNumberBuffers); */ + if (AI != NULL && AI->mode == RECORD && in != NULL) { if (A->wpos + numFrames < BUFLEN/2) { memcpy(&itmp[A->wpos*2], in, numFrames*2*sizeof(float)); A->wpos += numFrames; @@ -95,6 +105,7 @@ UInt32 count = sizeof(AudioDeviceID); UInt32 bufferSize; AudioStreamBasicDescription format; + int *usageCountPtr; if (mode == PLAY) { AO = A; @@ -102,29 +113,46 @@ A->wpos = 0; A->rpos = 0; A->tot = 0; + err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, + &count, (void *) &A->device); + + count = sizeof(bufferSize); + err = AudioDeviceGetProperty(A->device, 0, false, + kAudioDevicePropertyBufferSize, + &count, &bufferSize); + + count = sizeof(format); + err = AudioDeviceGetProperty(A->device, 0, false, + kAudioDevicePropertyStreamFormat, + &count, &format); + usageCountPtr = &AOusageCount; + XXDEBUG(printf("START: A->device=%d, AO, in:usageCount=%d\n", A->device, AOusageCount);) } else { AI = A; A->rpos = 0; A->wpos = 0; A->tot = 0; - } - if (usageCount == 1) { - usageCount = 2; - return TCL_OK; - } - - err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, + err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &count, (void *) &A->device); - count = sizeof(bufferSize); - err = AudioDeviceGetProperty(A->device, 0, false, + count = sizeof(bufferSize); + err = AudioDeviceGetProperty(A->device, 0, true, kAudioDevicePropertyBufferSize, &count, &bufferSize); - count = sizeof(format); - err = AudioDeviceGetProperty(A->device, 0, false, + count = sizeof(format); + err = AudioDeviceGetProperty(A->device, 0, true, kAudioDevicePropertyStreamFormat, &count, &format); + usageCountPtr = &AIusageCount; + XXDEBUG(printf("START: A->device=%d, AI, in:usageCount=%d\n", A->device, AIusageCount);) + } + + if (*usageCountPtr > 0) { + XXDEBUG(printf("Multiple open recorded, usageCount=%d\n", *usageCountPtr);) + (*usageCountPtr)++; + return TCL_OK; + } if ((err = AudioDeviceAddIOProc(A->device, appIOProc, (void *)A)) != -kAudioHardwareNoError) { @@ -144,7 +172,7 @@ A->mode = mode; A->encoding = encoding; rate = (float) freq; - usageCount = 1; + *usageCountPtr = 1; switch (encoding) { case LIN24: @@ -162,29 +190,50 @@ SnackAudioClose(ADesc *A) { OSStatus err = kAudioHardwareNoError; + int *usageCountPtr; if (A->mode == PLAY) { - AO = NULL; + XXDEBUG(printf("STOP: A->device=%d, AO, in:usageCount=%d\n", A->device, AOusageCount);) + if (AOusageCount <= 0 && AO == NULL) { + XXDEBUG(printf("Repeat PLAY stop!\n");) + return TCL_ERROR; + } + if (AOusageCount == 1) { + AO = NULL; + } + usageCountPtr = &AOusageCount; } else { - AI = NULL; + XXDEBUG(printf("STOP: A->device=%d, AI, in:usageCount=%d\n", A->device, AIusageCount);) + if (AIusageCount <= 0 && AI == NULL) { + XXDEBUG(printf("Repeat RECORD stop!\n");) + return TCL_ERROR; + } + if (AIusageCount == 1) { + AI = NULL; + } + usageCountPtr = &AIusageCount; + } + (*usageCountPtr)--; + if (*usageCountPtr < 0) { + XXDEBUG(printf("SnackAudioClose usageCount < 0?!\n");) + return TCL_ERROR; } - if (usageCount == 2) { - usageCount = 1; + if (*usageCountPtr != 0) { + XXDEBUG(printf("SnackAudioClose usageCount > 0\n");) return(0); } - usageCount = 0; - /* printf("SnackAudioClose\n");*/ + XXDEBUG(printf("SnackAudioClose usageCount == 0\n");) if ((err = AudioDeviceStop(A->device, appIOProc)) != -kAudioHardwareNoError) { - /* printf("AudioDeviceStop failed\n");*/ + XXDEBUG(printf("AudioDeviceStop failed\n");) return TCL_ERROR; } if ((err = AudioDeviceRemoveIOProc(A->device, appIOProc)) != -kAudioHardwareNoError) { - /* printf("AudioDeviceRemoveIOProc failed\n");*/ + XXDEBUG(printf("AudioDeviceRemoveIOProc failed\n");) return TCL_ERROR; } amsn-0.98.9/utils/macosx/snack2.2/patches/ReadMe.txt0000644000175000017500000000104611075465612021701 0ustar billiobbilliobThese patches were created by David Luyer (the Makefile.in patch was created from looking at the code in his build-amsn-snack.sh script), in order to make snack work correctly on Intel mac machines. The patches are against the 2.2.10 version of snack, and reconfigure the Makefile to build universally, while also editing jkAudIO_osx to work correctly. The patches should be applied inside the unix directory of the snack2.2.10 folder. They should be applied before snack is configured, there is no particular order in which they should be applied.amsn-0.98.9/utils/macosx/snack2.2/patches/Makefile.in.patch0000644000175000017500000000304111075465612023143 0ustar billiobbilliob--- Makefile.in.orig 2005-12-14 11:29:39.000000000 +0000 +++ Makefile.in 2008-10-15 22:55:34.000000000 +0100 @@ -31,13 +31,19 @@ INCLUDES = ${XINCLUDES} @TCL_INCLUDE_SPEC@ -I${TCL_INCPATH} -I${TK_INCPATH} @AINC@ @NISTINC@ -CFLAGS = -O @CFLAGS@ @AFLAG@ ${INCLUDES} @TCLAPI@ -I${GENERIC_DIR} @DEFS@ +UNIVERSAL = -arch ppc -arch i386 -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.3 -LIBSO = -lc @ALIB@ @TCL_LIB_SPEC@ +CFLAGSBASE = -O @CFLAGS@ @AFLAG@ ${INCLUDES} @TCLAPI@ -I${GENERIC_DIR} @DEFS@ -LIBSN = -lc @TK_LIBS@ @ALIB@ @TCL_LIB_SPEC@ @TK_LIB_SPEC@ +CFLAGS = ${CFLAGSBASE} ${UNIVERSAL} -SHLIB_LD = @SHLIB_LD@ +LIBSO = -lc @ALIB@ -framework Tcl + +LIBSN = -lc @TK_LIBS@ @ALIB@ -framework Tcl -framework Tk + +LDFLAGS = ${UNIVERSAL} + +SHLIB_LD = @SHLIB_LD@ ${LDFLAGS} SHLIB_SUFFIX = @SHLIB_SUFFIX@ all: libsound${SHLIB_SUFFIX} libsnack${SHLIB_SUFFIX} @DOSTUBLIB@ @LIBNIST@ @LIBOGG@ editversion @@ -284,7 +290,7 @@ chmod 755 mixplay.tcl ;\ cd ../../unix ;\ fi -LIBNIST = @NISTLIBS@ -lc @TCL_LIB_SPEC@ -L. @SNACK_STUB_LIB_FLAG@ +LIBNIST = @NISTLIBS@ -lc -framework Tcl -L. @SNACK_STUB_LIB_FLAG@ OBJNIST = SphereFile.o SphereFile.o: $(GENERIC_DIR)/SphereFile.c @@ -293,7 +299,7 @@ libsnacksphere${SHLIB_SUFFIX}: ${OBJNIST} ${SHLIB_LD} ${OBJNIST} ${LIBNIST} -o libsnacksphere${SHLIB_SUFFIX} -LIBOGG = @OGGLIBS@ -lc @TCL_LIB_SPEC@ -L. @SNACK_STUB_LIB_FLAG@ +LIBOGG = @OGGLIBS@ -lc -framework Tcl -L. @SNACK_STUB_LIB_FLAG@ OBJOGG = SnackOgg.o SnackOgg.o: $(GENERIC_DIR)/SnackOgg.c amsn-0.98.9/utils/macosx/snack2.2/snack.tcl0000644000175000017500000011527111234153526020160 0ustar billiobbilliob# # Copyright (C) 1997-99 Kare Sjolander # # This file is part of the Snack sound extension for Tcl/Tk. # The latest version can be found at http://www.speech.kth.se/snack/ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # package provide snack 2.2 # Set playback latency according to the environment variable PLAYLATENCY if {$::tcl_platform(platform) == "unix"} { if {[info exists env(PLAYLATENCY)] && $env(PLAYLATENCY) > 0} { snack::audio playLatency $env(PLAYLATENCY) } } namespace eval snack { namespace export gainBox get* add* menu* frequencyAxis timeAxis \ createIcons mixerDialog sound audio mixer debug # # Gain control dialog # proc gainBox flags { variable gainbox catch {destroy .snackGainBox} toplevel .snackGainBox wm title .snackGainBox {Gain Control Panel} if {[string match *p* $flags]} { set gainbox(play) [snack::audio play_gain] pack [scale .snackGainBox.s -label {Play volume} -orient horiz \ -variable snack::gainbox(play) \ -command {snack::audio play_gain} \ -length 200] } if {[snack::mixer inputs] != ""} { if {[string match *r* $flags]} { set gainbox(rec) [snack::audio record_gain] pack [scale .snackGainBox.s2 -label {Record gain} \ -orient horiz \ -variable snack::gainbox(rec) \ -command {snack::audio record_gain} \ -length 200] } } pack [button .snackGainBox.exitB -text Close -command {destroy .snackGainBox}] } # # Snack mixer dialog # proc flipScaleValue {scaleVar var args} { set $var [expr 100-[set $scaleVar]] } proc mixerDialog {} { set wi .snackMixerDialog catch {destroy $wi} toplevel $wi wm title $wi "Mixer" # pack [frame $wi.f0] # label $wi.f0.l -text "Mixer device:" # set outDevList [snack::mixer devices] # eval tk_optionMenu $wi.f0.om mixerDev $outDevList # pack $wi.f0.l $wi.f0.om -side left pack [frame $wi.f] -expand yes -fill both foreach line [snack::mixer lines] { pack [frame $wi.f.g$line -bd 1 -relief solid] -side left \ -expand yes -fill both pack [label $wi.f.g$line.l -text $line] if {[snack::mixer channels $line] == "Mono"} { snack::mixer volume $line snack::v(r$line) } else { snack::mixer volume $line snack::v(l$line) snack::v(r$line) if {[info exists tile::version]} { pack [ttk::scale $wi.f.g$line.e -from 0 -to 100 -show no -orient vertical \ -var snack::v(lI$line) -command [namespace code [list flipScaleValue ::snack::v(lI$line) ::snack::v(l$line)]]] -side left -expand yes -fill y set snack::v(lI$line) [expr 100-[lindex [snack::mixer volume $line] end]] $wi.f.g$line.e set $snack::v(lI$line) } else { pack [scale $wi.f.g$line.e -from 100 -to 0 -show no -orient vertical \ -var snack::v(l$line)] -side left -expand yes -fill both } } if {[info exists tile::version]} { pack [ttk::scale $wi.f.g$line.s -from 0 -to 100 -show no -orient vertical \ -var snack::v(rI$line) -command [namespace code [list flipScaleValue ::snack::v(rI$line) ::snack::v(r$line)]]] -expand yes -fill y set snack::v(rI$line) [expr 100-[lindex [snack::mixer volume $line] end]] $wi.f.g$line.s set $snack::v(rI$line) } else { pack [scale $wi.f.g$line.s -from 100 -to 0 -show no -orient vertical \ -var snack::v(r$line)] -expand yes -fill both } } pack [frame $wi.f.f2] -side left if {[snack::mixer inputs] != ""} { pack [label $wi.f.f2.li -text "Input jacks:"] foreach jack [snack::mixer inputs] { snack::mixer input $jack [namespace current]::v(in$jack) pack [checkbutton $wi.f.f2.b$jack -text $jack \ -variable [namespace current]::v(in$jack)] \ -anchor w } } if {[snack::mixer outputs] != ""} { pack [label $wi.f.f2.lo -text "Output jacks:"] foreach jack [snack::mixer outputs] { snack::mixer output $jack [namespace current]::v(out$jack) pack [checkbutton $wi.f.f2.b$jack -text $jack \ -variable [namespace current]::v(out$jack)] \ -anchor w } } pack [button $wi.b1 -text Close -command "destroy $wi"] } # # Snack filename dialog # proc getOpenFile {args} { upvar #0 __snack_args data set specs { {-title "" "" "Open file"} {-initialdir "" "" "."} {-initialfile "" "" ""} {-multiple "" "" 0} {-format "" "" "none"} } tclParseConfigSpec __snack_args $specs "" $args if {$data(-format) == "none"} { if {$data(-initialfile) != ""} { set data(-format) [ext2fmt [file extension $data(-initialfile)]] } else { set data(-format) WAV } } if {$data(-format) == ""} { set data(-format) RAW } set data(-format) [string toupper $data(-format)] if {$data(-initialdir) == ""} { set data(-initialdir) "." } if {[string match Darwin $::tcl_platform(os)]} { return [tk_getOpenFile -title $data(-title) \ -multiple $data(-multiple) \ -filetypes [loadTypes $data(-format)] \ -defaultextension [fmt2ext $data(-format)] \ -initialdir $data(-initialdir)] } # Later Tcl's allow multiple files returned as a list if {$::tcl_version <= 8.3} { set res [tk_getOpenFile -title $data(-title) \ -filetypes [loadTypes $data(-format)] \ -defaultextension [fmt2ext $data(-format)] \ -initialdir $data(-initialdir) \ -initialfile $data(-initialfile)] } else { set res [tk_getOpenFile -title $data(-title) \ -multiple $data(-multiple) \ -filetypes [loadTypes $data(-format)] \ -defaultextension [fmt2ext $data(-format)] \ -initialdir $data(-initialdir) \ -initialfile $data(-initialfile)] } return $res } set loadTypes "" proc addLoadTypes {typelist fmtlist} { variable loadTypes variable filebox set loadTypes $typelist set i 9 ; # Needs updating when adding new formats foreach fmt $fmtlist { set filebox(l$fmt) $i incr i } } proc loadTypes fmt { variable loadTypes variable filebox if {$::tcl_platform(platform) == "windows"} { set l [concat {{{MS Wav Files} {.wav}} {{Smp Files} {.smp}} {{Snd Files} {.snd}} {{AU Files} {.au}} {{AIFF Files} {.aif}} {{AIFF Files} {.aiff}} {{Waves Files} {.sd}} {{MP3 Files} {.mp3}} {{CSL Files} {.nsp}}} $loadTypes {{{All Files} * }}] } else { set l [concat {{{MS Wav Files} {.wav .WAV}} {{Smp Files} {.smp .SMP}} {{Snd Files} {.snd .SND}} {{AU Files} {.au .AU}} {{AIFF Files} {.aif .AIF}} {{AIFF Files} {.aiff .AIFF}} {{Waves Files} {.sd .SD}} {{MP3 Files} {.mp3 .MP3}} {{CSL Files} {.nsp .NSP}}} $loadTypes {{{All Files} * }}] } return [swapListElem $l $filebox(l$fmt)] } variable filebox set filebox(RAW) .raw set filebox(SMP) .smp set filebox(AU) .au set filebox(WAV) .wav set filebox(SD) .sd set filebox(SND) .snd set filebox(AIFF) .aif set filebox(MP3) .mp3 set filebox(CSL) .nsp set filebox(lWAV) 0 set filebox(lSMP) 1 set filebox(lSND) 2 set filebox(lAU) 3 set filebox(lAIFF) 4 # skip 2 because of aif and aiff set filebox(lSD) 6 set filebox(lMP3) 7 set filebox(lCSL) 8 set filebox(lRAW) end # Do not forget to update indexes set filebox(sWAV) 0 set filebox(sSMP) 1 set filebox(sSND) 2 set filebox(sAU) 3 set filebox(sAIFF) 4 # skip 2 because of aif and aiff set filebox(sCSL) 6 set filebox(sRAW) end proc fmt2ext fmt { variable filebox return $filebox($fmt) } proc addExtTypes extlist { variable filebox foreach pair $extlist { set filebox([lindex $pair 0]) [lindex $pair 1] } } proc getSaveFile args { upvar #0 __snack_args data set specs { {-title "" "" "Save file"} {-initialdir "" "" "."} {-initialfile "" "" ""} {-format "" "" "none"} } tclParseConfigSpec __snack_args $specs "" $args if {$data(-format) == "none"} { if {$data(-initialfile) != ""} { set data(-format) [ext2fmt [file extension $data(-initialfile)]] } else { set data(-format) WAV } } if {$data(-format) == ""} { set data(-format) RAW } set data(-format) [string toupper $data(-format)] if {$data(-initialdir) == ""} { set data(-initialdir) "." } if {[string match macintosh $::tcl_platform(platform)]} { set tmp [tk_getSaveFile -title $data(-title) \ -initialdir $data(-initialdir) -initialfile $data(-initialfile)] if {[string compare [file ext $tmp] ""] == 0} { append tmp [fmt2ext $data(-format)] } return $tmp } else { return [tk_getSaveFile -title $data(-title) \ -filetypes [saveTypes $data(-format)] \ -defaultextension [fmt2ext $data(-format)] \ -initialdir $data(-initialdir) -initialfile $data(-initialfile)] } } set saveTypes "" proc addSaveTypes {typelist fmtlist} { variable saveTypes variable filebox set saveTypes $typelist set j 7 ; # Needs updating when adding new formats foreach fmt $fmtlist { set filebox(s$fmt) $j incr j } } proc saveTypes fmt { variable saveTypes variable filebox if {[info exists filebox(s$fmt)] == 0} { set fmt RAW } if {$::tcl_platform(platform) == "windows"} { set l [concat {{{MS Wav Files} {.wav}} {{Smp Files} {.smp}} {{Snd Files} {.snd}} {{AU Files} {.au}} {{AIFF Files} {.aif}} {{AIFF Files} {.aiff}} {{CSL Files} {.nsp}}} $saveTypes {{{All Files} * }}] } else { set l [concat {{{MS Wav Files} {.wav .WAV}} {{Smp Files} {.smp .SMP}} {{Snd Files} {.snd .SND}} {{AU Files} {.au .AU}} {{AIFF Files} {.aif .AIF}} {{AIFF Files} {.aiff .AIFF}} {{CSL Files} {.nsp .NSP}}} $saveTypes {{{All Files} * }}] } return [swapListElem $l $filebox(s$fmt)] } proc swapListElem {l n} { set tmp [lindex $l $n] set l [lreplace $l $n $n] return [linsert $l 0 $tmp] } set filebox(.wav) WAV set filebox(.smp) SMP set filebox(.au) AU set filebox(.raw) RAW set filebox(.snd) SND set filebox(.sd) SD set filebox(.aif) AIFF set filebox(.aiff) AIFF set filebox(.mp3) MP3 set filebox(.nsp) CSL set filebox() WAV proc ext2fmt ext { variable filebox return $filebox($ext) } # # Menus # proc menuInit { {m .menubar} } { variable menu menu $m [winfo parent $m] configure -menu $m set menu(menubar) $m set menu(uid) 0 } proc menuPane {label {u 0} {postcommand ""}} { variable menu if [info exists menu(menu,$label)] { error "Menu $label already defined" } if {$label == "Help"} { set name $menu(menubar).help } else { set name $menu(menubar).mb$menu(uid) } set m [menu $name -tearoff 1 -postcommand $postcommand] $menu(menubar) add cascade -label $label -menu $name -underline $u incr menu(uid) set menu(menu,$label) $m return $m } proc menuDelete {menuName label} { variable menu set m [menuGet $menuName] if [catch {$m index $label} index] { error "$label not in menu $menuName" } [menuGet $menuName] delete $index } proc menuDeleteByIndex {menuName index} { [menuGet $menuName] delete $index } proc menuGet menuName { variable menu if [catch {set menu(menu,$menuName)} m] { return -code error "No such menu: $menuName" } return $m } proc menuCommand {menuName label command} { [menuGet $menuName] add command -label $label -command $command } proc menuCheck {menuName label var {command {}} } { variable menu [menuGet $menuName] add check -label $label -command $command \ -variable $var } proc menuRadio {menuName label var {val {}} {command {}} } { variable menu if {[string length $val] == 0} { set val $label } [menuGet $menuName] add radio -label $label -command $command \ -value $val -variable $var } proc menuSeparator menuName { variable menu [menuGet $menuName] add separator } proc menuCascade {menuName label} { variable menu set m [menuGet $menuName] if [info exists menu(menu,$label)] { error "Menu $label already defined" } set sub $m.sub$menu(uid) incr menu(uid) menu $sub -tearoff 0 $m add cascade -label $label -menu $sub set menu(menu,$label) $sub return $sub } proc menuBind {what char menuName label} { variable menu set m [menuGet $menuName] if [catch {$m index $label} index] { error "$label not in menu $menuName" } set command [$m entrycget $index -command] if {$::tcl_platform(platform) == "unix"} { bind $what $command $m entryconfigure $index -accelerator Alt-$char } else { bind $what $command set char [string toupper $char] $m entryconfigure $index -accelerator Ctrl-$char } } proc menuEntryOff {menuName label} { variable menu set m [menuGet $menuName] if [catch {$m index $label} index] { error "$label not in menu $menuName" } $m entryconfigure $index -state disabled } proc menuEntryOn {menuName label} { variable menu set m [menuGet $menuName] if [catch {$m index $label} index] { error "$label not in menu $menuName" } $m entryconfigure $index -state normal } # # Vertical frequency axis # proc frequencyAxis {canvas x y width height args} { array set a [list \ -tags snack_y_axis \ -font {Helvetica 8} \ -topfr 8000 \ -fill black \ -draw0 0 ] if {[string match unix $::tcl_platform(platform)] } { set a(-font) {Helvetica 10} } array set a $args if {$height <= 0} return set ticklist [list 10 20 50 100 200 500 1000 2000 5000 \ 10000 20000 50000 100000 200000 500000 1000000] set npt 10 set dy [expr {double($height * $npt) / $a(-topfr)}] while {$dy < [font metrics $a(-font) -linespace]} { foreach elem $ticklist { if {$elem <= $npt} { continue } set npt $elem break } set dy [expr {double($height * $npt) / $a(-topfr)}] } if {$npt < 1000} { set hztext Hz } else { set hztext kHz } if $a(-draw0) { set i0 0 set j0 0 } else { set i0 $dy set j0 1 } for {set i $i0; set j $j0} {$i < $height} {set i [expr {$i+$dy}]; incr j} { set yc [expr {$height + $y - $i}] if {$npt < 1000} { set t [expr {$j * $npt}] } else { set t [expr {$j * $npt / 1000}] } if {$yc > [expr {8 + $y}]} { if {[expr {$yc - [font metrics $a(-font) -ascent]}] > \ [expr {$y + [font metrics $a(-font) -linespace]}] || [font measure $a(-font) $hztext] < \ [expr {$width - 8 - [font measure $a(-font) $t]}]} { $canvas create text [expr {$x +$width - 8}] [expr {$yc-2}]\ -text $t -fill $a(-fill)\ -font $a(-font) -anchor e -tags $a(-tags) } $canvas create line [expr {$x + $width - 5}] $yc \ [expr {$x + $width}]\ $yc -tags $a(-tags) -fill $a(-fill) } } $canvas create text [expr {$x + 2}] [expr {$y + 1}] -text $hztext \ -font $a(-font) -anchor nw -tags $a(-tags) -fill $a(-fill) return $npt } # # Horizontal time axis # proc timeAxis {canvas ox oy width height pps args} { array set a [list \ -tags snack_t_axis \ -font {Helvetica 8} \ -starttime 0.0 \ -fill black \ -format time \ -draw0 0 \ -drawvisible 0 ] if {[string match unix $::tcl_platform(platform)] } { set a(-font) {Helvetica 10} } array set a $args if {$pps <= 0.004} return switch -- $a(-format) { time - seconds { set deltalist [list .0001 .0002 .0005 .001 .002 .005 \ .01 .02 .05 .1 .2 .5 1 2 5 \ 10 20 30 60 120 240 360 600 900 1800 3600 7200 14400] } "PAL frames" { set deltalist [list .04 .08 .4 .8 2 4 \ 10 20 50 100 200 500 1000 2000 5000 10000 20000] } "NTSC frames" { set deltalist [list .03333333333334 .0666666666667 \ .3333333333334 .666666666667 1 2 4 \ 10 20 50 100 200 500 1000 2000 5000 10000 20000] } "10ms frames" { set deltalist [list .01 .02 .05 .1 .2 .5 1 2 5 \ 10 20 50 100 200 500 1000 2000 5000 10000 20000] } } set majTickH [expr {$height - [font metrics $a(-font) -linespace]}] set minTickH [expr {$majTickH / 2}] # Create a typical time label set maxtime [expr {double($width) / $pps + $a(-starttime)}] if {$maxtime < 60} { set wtime 00 } elseif {$maxtime < 3600} { set wtime 00:00 } else { set wtime 00:00:00 } if {$pps > 50} { append wtime .0 } elseif {$pps > 500} { append wtime .00 } elseif {$pps > 5000} { append wtime .000 } elseif {$pps > 50000} { append wtime .0000 } # Compute the distance in pixels (and time) between tick marks set dx [expr {10+[font measure $a(-font) $wtime]}] set dt [expr {double($dx) / $pps}] foreach elem $deltalist { if {$elem <= $dt} { continue } set dt $elem break } set dx [expr {$pps * $dt}] if {$dt < 0.00099} { set ndec 4 } elseif {$dt < 0.0099} { set ndec 3 } elseif {$dt < 0.099} { set ndec 2 } else { set ndec 1 } if {$a(-starttime) > 0.0} { set ft [expr {(int($a(-starttime) / $dt) + 1) * $dt}] set fx [expr {$pps * ($ft - $a(-starttime))}] } else { set ft 0 set fx 0.0 } set lx [expr {($ox + $width) * [lindex [$canvas xview] 0] - 50}] set rx [expr {($ox + $width) * [lindex [$canvas xview] 1] + 50}] set jinit 0 if {$a(-drawvisible)} { set jinit [expr {int($lx/$dx)}] set fx [expr {$fx + $jinit * $dx}] } for {set x $fx;set j $jinit} {$x < $width} \ {set x [expr {$x+$dx}];incr j} { if {$a(-drawvisible) && $x < $lx} continue if {$a(-drawvisible) && $x > $rx} break switch -- $a(-format) { time { set t [expr {$j * $dt + $ft}] if {$maxtime < 60} { set tmp [expr {int($t)}] } elseif {$maxtime < 3600} { set tmp x[clock format [expr {int($t)}] -format "%M:%S" -gmt 1] regsub x0 $tmp "" tmp regsub x $tmp "" tmp } else { set tmp [clock format [expr {int($t)}] -format "%H:%M:%S" -gmt 1] } if {$dt < 1.0} { set t $tmp[string trimleft [format "%.${ndec}f" \ [expr {($t-int($t))}]] 0] } else { set t $tmp } } "PAL frames" { set t [expr {int($j * $dt * 25.0 + $ft)}] } "NTSC frames" { set t [expr {int($j * $dt * 30.0 + $ft)}] } "10ms frames" { set t [expr {int($j * $dt * 100.0 + $ft)}] } seconds { set t [expr {double($j * $dt * 1.0 + $ft)}] } } if {$a(-draw0) == 1 || $j > 0 || $a(-starttime) > 0.0} { $canvas create text [expr {$ox+$x}] [expr {$oy+$height}] \ -text $t -font $a(-font) -anchor s -tags $a(-tags) \ -fill $a(-fill) } $canvas create line [expr {$ox+$x}] $oy [expr {$ox+$x}] \ [expr {$oy+$majTickH}] -tags $a(-tags) -fill $a(-fill) if {[string match *5 $dt] || [string match 5* $dt]} { set nt 5 } else { set nt 2 } for {set k 1} {$k < $nt} {incr k} { set xc [expr {$k * $dx / $nt}] $canvas create line [expr {$ox+$x+$xc}] $oy \ [expr {$ox+$x+$xc}] [expr {$oy+$minTickH}]\ -tags $a(-tags) -fill $a(-fill) } } } # # Snack icons # variable icon set icon(new) R0lGODlhEAAQALMAAAAAAMbGxv///////////////////////////////////////////////////////yH5BAEAAAEALAAAAAAQABAAAAQwMMhJ6wQ4YyuB+OBmeeDnAWNpZhWpmu0bxrKAUu57X7VNy7tOLxjIqYiapIjDbDYjADs= set icon(open) R0lGODlhEAAQALMAAAAAAISEAMbGxv//AP///////////////////////////////////////////////yH5BAEAAAIALAAAAAAQABAAAAQ4UMhJq6Ug3wpm7xsHZqBFCsBADGTLrbCqllIaxzSKt3wmA4GgUPhZAYfDEQuZ9ByZAVqPF6paLxEAOw== set icon(save) R0lGODlhEAAQALMAAAAAAISEAMbGxv///////////////////////////////////////////////////yH5BAEAAAIALAAAAAAQABAAAAQ3UMhJqwQ4a30DsJfwiR4oYt1oASWpVuwYm7NLt6y3YQHe/8CfrLfL+HQcGwmZSXWYKOWpmDSBIgA7 set icon(print) R0lGODlhEAAQALMAAAAAAISEhMbGxv//AP///////////////////////////////////////////////yH5BAEAAAIALAAAAAAQABAAAAQ5UMhJqwU450u67wCnAURYkZ9nUuRYbhKalkJoj1pdYxar40ATrxIoxn6WgTLGC4500J6N5Vz1roIIADs= # set icon(open) R0lGODlhFAATAOMAAAAAAFeEAKj/AYQAV5o2AP8BqP9bAQBXhC8AhJmZmWZmZszMzAGo/1sB/////9zc3CH5BAEAAAsALAAAAAAUABMAQARFcMlJq13ANc03uGAoTp+kACWpAUjruum4nAqI3hdOZVtz/zoS6/WKyY7I4wlnPKIqgB7waet1VqHoiliE+riw3PSXlEUAADs= # set icon(save) R0lGODlhFAATAOMAAAAAAAAAhAAA/wCEAACZmQD/AAD//4QAAISEAJmZmWZmZszMzP8AAP//AP///9zc3CH5BAEAAAsALAAAAAAUABMAQARBcMlJq5VACGDzvkAojiGocZWHUiopflcsL2p32lqu3+lJYrCZcCh0GVeTWi+Y5LGczY0RCtxZkVUXEEvzjbbEWQQAOw== # set icon(print) R0lGODlhFAATAOMAAAAAAAAAhAAA/wCEAACZmQD/AAD//4QAAISEAJmZmWZmZszMzP8AAP//AP///9zc3CH5BAEAAAsALAAAAAAUABMAQARHcMlJq53A6b2BEIAFjGQZXlTGdZX3vTAInmiNqqtGY3Ev76bgCGQrGo8toS3DdIycNWZTupMITbPUtfQBznyz6sLl84iRlAgAOw== # set icon(cut) R0lGODlhFAATAOMAAAAAAAAAhAAA/wCEAACZmQD/AAD//4QAAISEAJmZmWZmZszMzP8AAP//AP///9zc3CH5BAEAAAsALAAAAAAUABMAQAQ3cMlJq71LAYUvANPXVVsGjpImfiW6nK87aS8nS+x9gvvt/xgYzLUaEkVAI0r1ao1WMWSn1wNeIgA7 # set icon(copy) R0lGODlhFAATAOMAAAAAAAAAhAAA/wCEAACZmQD/AAD//4QAAISEAJmZmWZmZszMzP8AAP//AP///9zc3CH5BAEAAAsALAAAAAAUABMAQARFcMlJq5XAZSB0FqBwjSTmnF45ASzbbZojqrTJyqgMjDAXwzNSaAiqGY+UVsuYQRGDluap49RcpLjcNJqjaqEXbxdJLkUAADs= # set icon(paste) R0lGODlhFAATAOMAAAAAAFeEAKj/AYQAV5o2AP8BqP9bAQBXhC8AhJmZmWZmZszMzAGo/1sB/////9zc3CH5BAEAAAsALAAAAAAUABMAQARTcMlJq11A6c01uFXjAGNJNpMCrKvEroqVcSJ5NjgK7tWsUr5PryNyGB04GdHE1PGe0OjrGcR8qkPPCwsk5nLCLu1oFCUnPk2RfHSqXms2cvetJyMAOw== # set icon(undo) R0lGODlhFAATAOMAAAAAAAAAhAAA/wCEAACZmQD/AAD//4QAAISEAJmZmWZmZszMzP8AAP//AP///9zc3CH5BAEAAAsALAAAAAAUABMAQAQ7cMlJq6UKALmpvmCIaWQJZqXidWJboWr1XSgpszTu7nyv1IBYyCSBgWyWjHAUnE2cnBKyGDxNo72sKwIAOw== set icon(cut) R0lGODlhEAAQALMAAAAAAAAAhMbGxv///////////////////////////////////////////////////yH5BAEAAAIALAAAAAAQABAAAAQvUMhJqwUTW6pF314GZhjwgeXImSrXTgEQvMIc3ONtS7PV77XNL0isDGs9YZKmigAAOw== set icon(copy) R0lGODlhEAAQALMAAAAAAAAAhMbGxv///////////////////////////////////////////////////yH5BAEAAAIALAAAAAAQABAAAAQ+UMhJqwA4WwqGH9gmdV8HiKYZrCz3ecG7TikWf3EwvkOM9a0a4MbTkXCgTMeoHPJgG5+yF31SLazsTMTtViIAOw== set icon(paste) R0lGODlhEAAQALMAAAAAAAAAhISEAISEhMbGxv//AP///////////////////////////////////////yH5BAEAAAQALAAAAAAQABAAAARMkMhJqwUYWJlxKZ3GCYMAgCdQDqLKXmUrGGE2vIRK7usu94GgMNDqDQKGZDI4AiqXhkDOiMxEhQCeAPlUEqm0UDTX4XbHlaFaumlHAAA7 set icon(undo) R0lGODlhEAAQALMAAAAAhMbGxv///////////////////////////////////////////////////////yH5BAEAAAEALAAAAAAQABAAAAQgMMhJq704622BB93kUSAJlhUafJj6qaLJklxc33iuXxEAOw== set icon(redo) R0lGODlhFAATAKEAAMzMzGZmZgAAAAAAACH5BAEAAAAALAAAAAAUABMAAAI4hI+py+0fhBQhPDCztCzSkzWS4nFJZCLTMqrGxgrJBistmKUHqmo3jvBMdC9Z73MBEZPMpvOpKAAAOw== set icon(gain) R0lGODlhFAATAOMAAAAAAFpaWjMzZjMAmZlmmapV/729vY+Pj5mZ/+/v78zM/wAAAAAAAAAAAAAAAAAAACH5BAEAAAUALAAAAAAUABMAAARnsMhJqwU4a32T/6AHdF8WjhUAAoa6kqwhtyW8uUlG4Tl2DqoJjzUcIAIeyZAmAiBwyhUNADQCAsHCUoVBKBTERLQ0RRiftLGoPGgDk1qpC+N2qXPM5lscL/lAAj5CIYQ5gShaN4oVEQA7 set icon(zoom) R0lGODlhFAATAMIAAAAAAF9fXwAA/8zM/8zMzP///wAAAAAAACH5BAEAAAQALAAAAAAUABMAAAM/SLrc/jBKGYAFYapaes0U0I0VIIkjaUZo2q1Q68IP5r5UcFtgbL8YTOhS+mgWFcFAeCQEBMre8WlpLqrWrCYBADs= set icon(zoomIn) R0lGODlhFAATAMIAAMzMzF9fXwAAAP///wAA/8zM/wAAAAAAACH5BAEAAAAALAAAAAAUABMAAANBCLrc/jBKGYQVYao6es2U0FlDJUjimFbocF1u+5JnhKldHAUB7mKom+oTupiImo2AUAAmAQECE/SMWp6LK3arSQAAOw== set icon(zoomOut) R0lGODlhFAATAMIAAMzMzF9fXwAAAP///wAA/8zM/wAAAAAAACH5BAEAAAAALAAAAAAUABMAAANCCLrc/jBKGYQVYao6es2U0I2VIIkjaUbidQ0r1LrtGaRj/AQ3boEyTA6DCV1KH82iQigUlYAAoQlUSi3QBTbL1SQAADs= set icon(play) R0lGODlhFQAVAKEAANnZ2QAAAP///////yH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAh+QQBCgAAACwAAAAAFQAVAAACJISPqcvtD10IUc1Zz7157+h5Txg2pMicmESCqLt2VEbX9o1XBQA7 set icon(pause) R0lGODlhFQAVAKEAANnZ2QAAAP///////yH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAh+QQBCgAAACwAAAAAFQAVAAACLISPqcvtD12Y09DKbrC3aU55HfBlY7mUqKKO6emycGjSa9LSrx1H/g8MCiMFADs= set icon(stop) R0lGODlhFQAVAKEAANnZ2QAAAP///////yH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAh+QQBCgAAACwAAAAAFQAVAAACJISPqcvtD12YtM5mc8C68n4xIPWBZXdqabZarSeOW0TX9o3bBQA7 set icon(record) R0lGODlhFQAVAKEAANnZ2f8AAP///////yH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAh+QQBCgAAACwAAAAAFQAVAAACJoSPqcvtDyMINMhZM8zcuq41ICeOVWl6S0p95pNu4BVe9o3n+lIAADs= proc createIcons {} { variable icon image create photo snackOpen -data $icon(open) image create photo snackSave -data $icon(save) image create photo snackPrint -data $icon(print) image create photo snackCut -data $icon(cut) image create photo snackCopy -data $icon(copy) image create photo snackPaste -data $icon(paste) image create photo snackUndo -data $icon(undo) image create photo snackRedo -data $icon(redo) image create photo snackGain -data $icon(gain) image create photo snackZoom -data $icon(zoom) image create photo snackZoomIn -data $icon(zoomIn) image create photo snackZoomOut -data $icon(zoomOut) image create photo snackPlay -data $icon(play) image create photo snackPause -data $icon(pause) image create photo snackStop -data $icon(stop) image create photo snackRecord -data $icon(record) } # # Support routines for shape files # proc deleteInvalidShapeFile {fileName} { if {$fileName == ""} return if ![file exists $fileName] return set shapeName "" if [file exists [file rootname $fileName].shape] { set shapeName [file rootname $fileName].shape } if [file exists [file rootname [file tail $fileName]].shape] { set shapeName [file rootname [file tail $fileName]].shape } if {$shapeName != ""} { set fileTime [file mtime $fileName] set shapeTime [file mtime $shapeName] if {$fileTime > $shapeTime} { # Delete shape file if older than sound file file delete -force $shapeName } else { set s [snack::sound] $s config -file $fileName set soundSize [expr {200 * [$s length -unit seconds] * \ [$s cget -channels]}] set shapeSize [file size $shapeName] if {[expr {$soundSize*0.95}] > $shapeSize || \ [expr {$soundSize*1.05}] < $shapeSize} { # Delete shape file with incorrect size file delete -force $shapeName } $s destroy } } } proc makeShapeFileDeleteable {fileName} { if {$::tcl_platform(platform) == "unix"} { if [file exists [file rootname $fileName].shape] { set shapeName [file rootname $fileName].shape catch {file attributes $shapeName -permissions 0777} } if [file exists [file rootname [file tail $fileName]].shape] { set shapeName [file rootname [file tail $fileName]].shape catch {file attributes $shapeName -permissions 0777} } } } # # Snack default progress callback # proc progressCallback {message fraction} { set w .snackProgressDialog # if {$fraction == 0.0} return if {$fraction == 1.0} { # Task is finished close dialog destroy $w return } if {![winfo exists $w]} { # Open progress dialog if not currently shown toplevel $w pack [label $w.l] pack [canvas $w.c -width 200 -height 20 -relief sunken \ -borderwidth 2] $w.c create rect 0 0 0 20 -fill black -tags bar pack [button $w.b -text Stop -command "destroy $w.b"] wm title $w "Please wait..." wm transient $w . wm withdraw $w set x [expr {[winfo screenwidth $w]/2 - [winfo reqwidth $w]/2 \ - [winfo vrootx [winfo parent $w]]}] set y [expr {[winfo screenheight $w]/2 - [winfo reqheight $w]/2 \ - [winfo vrooty [winfo parent $w]]}] wm geom $w +$x+$y wm deiconify $w update idletasks } elseif {![winfo exists $w.b]} { # User hit Stop button, close dialog destroy $w return -code error } switch -- $message { "Converting rate" { set message "Converting sample rate..." } "Converting encoding" { set message "Converting sample encoding format..." } "Converting channels" { set message "Converting number of channels..." } "Computing pitch" { set message "Computing pitch..." } "Reading sound" { set message "Reading sound..." } "Writing sound" { set message "Writing sound..." } "Computing waveform" { set message "Waveform is being precomputed and\ stored on disk..." } "Reversing sound" { set message "Reversing sound..." } "Filtering sound" { set message "Filtering sound..." } } $w.l configure -text $message $w.c coords bar 0 0 [expr {$fraction * 200}] 20 update } # # Convenience function to create dialog boxes, derived from tk_messageBox # proc makeDialogBox {toplevel args} { variable tkPriv set w tkPrivMsgBox upvar #0 $w data # # The default value of the title is space (" ") not the empty string # because for some window managers, a # wm title .foo "" # causes the window title to be "foo" instead of the empty string. # set specs { {-default "" "" ""} {-message "" "" ""} {-parent "" "" .} {-title "" "" " "} {-type "" "" "okcancel"} } tclParseConfigSpec $w $specs "" $args if {![winfo exists $data(-parent)]} { error "bad window path name \"$data(-parent)\"" } switch -- $data(-type) { abortretryignore { set buttons { {abort -width 6 -text Abort -under 0} {retry -width 6 -text Retry -under 0} {ignore -width 6 -text Ignore -under 0} } } ok { set buttons { {ok -width 6 -text OK -under 0} } if {![string compare $data(-default) ""]} { set data(-default) "ok" } } okcancel { set buttons { {ok -width 6 -text OK -under 0} {cancel -width 6 -text Cancel -under 0} } } retrycancel { set buttons { {retry -width 6 -text Retry -under 0} {cancel -width 6 -text Cancel -under 0} } } yesno { set buttons { {yes -width 6 -text Yes -under 0} {no -width 6 -text No -under 0} } } yesnocancel { set buttons { {yes -width 6 -text Yes -under 0} {no -width 6 -text No -under 0} {cancel -width 6 -text Cancel -under 0} } } default { error "bad -type value \"$data(-type)\": must be abortretryignore, ok, okcancel, retrycancel, yesno, or yesnocancel" } } if {[string compare $data(-default) ""]} { set valid 0 foreach btn $buttons { if {![string compare [lindex $btn 0] $data(-default)]} { set valid 1 break } } if {!$valid} { error "invalid default button \"$data(-default)\"" } } # 2. Set the dialog to be a child window of $parent # # if {[string compare $data(-parent) .]} { set w $data(-parent)$toplevel } else { set w $toplevel } # 3. Create the top-level window and divide it into top # and bottom parts. # catch {destroy $w} # toplevel $w -class Dialog wm title $w $data(-title) wm iconname $w Dialog wm protocol $w WM_DELETE_WINDOW { } # Message boxes should be transient with respect to their parent so that # they always stay on top of the parent window. But some window managers # will simply create the child window as withdrawn if the parent is not # viewable (because it is withdrawn or iconified). This is not good for # "grab"bed windows. So only make the message box transient if the parent # is viewable. # if { [winfo viewable [winfo toplevel $data(-parent)]] } { wm transient $w $data(-parent) } if {![string compare $::tcl_platform(platform) "macintosh"]} { unsupported1 style $w dBoxProc } frame $w.bot pack $w.bot -side bottom -fill both if {[string compare $::tcl_platform(platform) "macintosh"]} { $w.bot configure -relief raised -bd 1 } # 4. Fill the top part with bitmap and message (use the option # database for -wraplength and -font so that they can be # overridden by the caller). option add *Dialog.msg.wrapLength 3i widgetDefault if {![string compare $::tcl_platform(platform) "macintosh"]} { option add *Dialog.msg.font system widgetDefault } else { option add *Dialog.msg.font {Times 18} widgetDefault } # 5. Create a row of buttons at the bottom of the dialog. set i 0 foreach but $buttons { set name [lindex $but 0] set opts [lrange $but 1 end] if {![llength $opts]} { # Capitalize the first letter of $name set capName [string toupper \ [string index $name 0]][string range $name 1 end] set opts [list -text $capName] } eval button [list $w.$name] $opts [list -command \ [list set [namespace current]::tkPriv(button) $name]] if {![string compare $name $data(-default)]} { $w.$name configure -default active } pack $w.$name -in $w.bot -side left -expand 1 -padx 3m -pady 2m # create the binding for the key accelerator, based on the underline # set underIdx [$w.$name cget -under] if {$underIdx >= 0} { set key [string index [$w.$name cget -text] $underIdx] bind $w [list $w.$name invoke] bind $w [list $w.$name invoke] } incr i } if {[string compare {} $data(-default)]} { bind $w { if {0 == [string compare Button [winfo class %W]]} { %W configure -default active } } bind $w { if {0 == [string compare Button [winfo class %W]]} { %W configure -default normal } } } # 6. Create a binding for on the dialog bind $w { if {0 == [string compare Button [winfo class %W]]} { if {$::tcl_version <= 8.3} { tkButtonInvoke %W } else { tk::ButtonInvoke %W } } } # 7. Withdraw the window, then update all the geometry information # so we know how big it wants to be, then center the window in the # display and de-iconify it. wm withdraw $w update idletasks set x [expr {[winfo screenwidth $w]/2 - [winfo reqwidth $w]/2 \ - [winfo vrootx [winfo parent $w]]}] set y [expr {[winfo screenheight $w]/2 - [winfo reqheight $w]/2 \ - [winfo vrooty [winfo parent $w]]}] wm geom $w +$x+$y wm deiconify $w # 8. Set a grab and claim the focus too. set oldFocus [focus] set oldGrab [grab current $w] if {[string compare $oldGrab ""]} { set grabStatus [grab status $oldGrab] } grab $w if {[string compare $data(-default) ""]} { focus $w.$data(-default) } else { focus $w } # 9. Wait for the user to respond, then restore the focus and # return the index of the selected button. Restore the focus # before deleting the window, since otherwise the window manager # may take the focus away so we can't redirect it. Finally, # restore any grab that was in effect. tkwait variable [namespace current]::tkPriv(button) catch {focus $oldFocus} destroy $w if {[string compare $oldGrab ""]} { if {![string compare $grabStatus "global"]} { grab -global $oldGrab } else { grab $oldGrab } } return $tkPriv(button) } # # Snack level meter implemented as minimal mega widget # proc levelMeter {w args} { array set a [list \ -oncolor red \ -offcolor grey10 \ -background black \ -width 6 \ -length 80 \ -level 0.0 \ -orient horizontal \ -type log \ ] array set a $args # Widget specific storage namespace eval [namespace current]::$w { variable levelmeter } upvar [namespace current]::${w}::levelmeter lm set lm(level) 0 set lm(orient) $a(-orient) set lm(oncolor) $a(-oncolor) set lm(offcolor) $a(-offcolor) set lm(bg) $a(-background) set lm(type) $a(-type) if {[string match horiz* $lm(orient)]} { set lm(height) $a(-width) set lm(width) $a(-length) } else { set lm(height) $a(-length) set lm(width) $a(-width) } set lm(maxtime) [clock seconds] set lm(maxlevel) 0.0 proc drawLevelMeter {w} { upvar [namespace current]::${w}::levelmeter lm set c ${w}_levelMeter $c configure -width $lm(width) -height $lm(height) $c delete all $c create rectangle 0 0 $lm(width) $lm(height) \ -fill $lm(oncolor) -outline "" $c create rectangle 0 0 0 0 -outline "" -fill $lm(offcolor) \ -tag mask1 $c create rectangle 0 0 0 0 -outline "" -fill $lm(offcolor) \ -tag mask2 $c create rectangle 0 0 [expr $lm(width)-1] [expr $lm(height)-1] \ -outline $lm(bg) if {[string match horiz* $lm(orient)]} { $c coords mask1 [expr {$lm(level)*$lm(width)}] 0 \ $lm(width) $lm(height) $c coords mask2 [expr {$lm(level)*$lm(width)}] 0 \ $lm(width) $lm(height) for {set x 5} {$x < $lm(width)} {incr x 5} { $c create line $x 0 $x [expr $lm(width)-1] -fill black \ -width 2 } } else { $c coords mask1 0 0 $lm(width) \ [expr {$lm(height)-$lm(level)*$lm(height)}] $c coords mask2 0 0 $lm(width) \ [expr {$lm(height)-$lm(level)*$lm(height)}] for {set y 5} {$y < $lm(height)} {incr y 5} { $c create line 0 [expr $lm(height)-$y] \ [expr $lm(width)-1] [expr $lm(height)-$y] \ -fill black -width 2 } } } proc levelMeterHandler {w cmd args} { upvar [namespace current]::${w}::levelmeter lm if {[string match conf* $cmd]} { switch -- [lindex $args 0] { -level { set arg [lindex $args 1] if {$arg < 1} { set arg 1 } if {$lm(type)=="linear"} { set lm(level) [expr {$arg/32760.0}] } else { set lm(level) [expr {log($arg)/10.3972}] } if {[clock seconds] - $lm(maxtime) > 2} { set lm(maxtime) [clock seconds] set lm(maxlevel) 0.0 } if {$lm(level) > $lm(maxlevel)} { set lm(maxlevel) $lm(level) } if {[string match horiz* $lm(orient)]} { set l1 [expr {5*int($lm(level)*$lm(width)/5)}] set l2 [expr {5*int($lm(maxlevel)*$lm(width)/5)}] ${w}_levelMeter coords mask1 $l2 0 \ $lm(width) $lm(height) ${w}_levelMeter coords mask2 [expr {$l2-5}] 0 \ $l1 $lm(height) } else { set l1 [expr {5*int($lm(level)*$lm(height)/5)}] set l2 [expr {5*int($lm(maxlevel)*$lm(height)/5)}] ${w}_levelMeter coords mask1 0 0 $lm(width) \ [expr {$lm(height)-$l2}] ${w}_levelMeter coords mask2 0 [expr {$lm(height)-$l2+5}] \ $lm(width) [expr {$lm(height)-$l1}] } } -length { if {[string match horiz* $lm(orient)]} { set lm(width) [lindex $args 1] } else { set lm(height) [lindex $args 1] } drawLevelMeter $w } -width { if {[string match horiz* $lm(orient)]} { set lm(height) [lindex $args 1] } else { set lm(width) [lindex $args 1] } drawLevelMeter $w } default { error "unknown option \"[lindex $args 0]\"" } } } else { error "bad option \"$cmd\": must be configure" } } # Create a canvas where the widget is to be rendered canvas $w -highlightthickness 0 # Replave the canvas widget command rename $w ${w}_levelMeter # Draw level meter drawLevelMeter $w # Create level meter widget command proc ::$w {cmd args} \ "return \[eval snack::levelMeterHandler $w \$cmd \$args\]" return $w } } amsn-0.98.9/utils/amsn-installer0000644000175000017500000000005510027735602016407 0ustar billiobbilliob^@  Om77'(amsn-0.98.9/utils/BWidget-1.9.0/0000755000175000017500000000000011757711612015531 5ustar billiobbilliobamsn-0.98.9/utils/BWidget-1.9.0/titleframe.tcl0000644000175000017500000001366010516120770020366 0ustar billiobbilliob# ------------------------------------------------------------------------------ # titleframe.tcl # This file is part of Unifix BWidget Toolkit # ------------------------------------------------------------------------------ # Index of commands: # - TitleFrame::create # - TitleFrame::configure # - TitleFrame::cget # - TitleFrame::getframe # - TitleFrame::_place # ------------------------------------------------------------------------------ namespace eval TitleFrame { Widget::define TitleFrame titleframe Widget::declare TitleFrame { {-relief TkResource groove 0 frame} {-borderwidth TkResource 2 0 frame} {-font TkResource "" 0 label} {-foreground TkResource "" 0 label} {-state TkResource "" 0 label} {-background TkResource "" 0 frame} {-text String "" 0} {-ipad Int 4 0 "%d >=0"} {-side Enum left 0 {left center right}} {-baseline Enum center 0 {top center bottom}} {-fg Synonym -foreground} {-bg Synonym -background} {-bd Synonym -borderwidth} } Widget::addmap TitleFrame "" :cmd {-background {}} Widget::addmap TitleFrame "" .l { -background {} -foreground {} -text {} -font {} } Widget::addmap TitleFrame "" .l {-state {}} Widget::addmap TitleFrame "" .p {-background {}} Widget::addmap TitleFrame "" .b { -background {} -relief {} -borderwidth {} } Widget::addmap TitleFrame "" .b.p {-background {}} Widget::addmap TitleFrame "" .f {-background {}} } # ------------------------------------------------------------------------------ # Command TitleFrame::create # ------------------------------------------------------------------------------ proc TitleFrame::create { path args } { Widget::init TitleFrame $path $args set frame [eval [list frame $path] [Widget::subcget $path :cmd] \ -class TitleFrame -relief flat -bd 0 -highlightthickness 0] set padtop [eval [list frame $path.p] [Widget::subcget $path :cmd] \ -relief flat -borderwidth 0] set border [eval [list frame $path.b] [Widget::subcget $path .b] -highlightthickness 0] set label [eval [list label $path.l] [Widget::subcget $path .l] \ -highlightthickness 0 \ -relief flat \ -bd 0 -padx 2 -pady 0] set padbot [eval [list frame $border.p] [Widget::subcget $path .p] \ -relief flat -bd 0 -highlightthickness 0] set frame [eval [list frame $path.f] [Widget::subcget $path .f] \ -relief flat -bd 0 -highlightthickness 0] set height [winfo reqheight $label] switch [Widget::getoption $path -side] { left { set relx 0.0; set x 5; set anchor nw } center { set relx 0.5; set x 0; set anchor n } right { set relx 1.0; set x -5; set anchor ne } } set bd [Widget::getoption $path -borderwidth] switch [Widget::getoption $path -baseline] { top { set y 0 set htop $height set hbot 1 } center { set y 0 set htop [expr {$height/2}] set hbot [expr {$height/2+$height%2+1}] } bottom { set y [expr {$bd+1}] set htop 1 set hbot $height } } $padtop configure -height $htop $padbot configure -height $hbot set pad [Widget::getoption $path -ipad] pack $padbot -side top -fill x pack $frame -in $border -fill both -expand yes -padx $pad -pady $pad pack $padtop -side top -fill x pack $border -fill both -expand yes place $label -relx $relx -x $x -anchor $anchor -y $y bind $label [list TitleFrame::_place $path] bind $path [list Widget::destroy %W] return [Widget::create TitleFrame $path] } # ------------------------------------------------------------------------------ # Command TitleFrame::configure # ------------------------------------------------------------------------------ proc TitleFrame::configure { path args } { set res [Widget::configure $path $args] if { [Widget::hasChanged $path -ipad pad] } { pack configure $path.f -padx $pad -pady $pad } if { [Widget::hasChanged $path -borderwidth val] | [Widget::hasChanged $path -font val] | [Widget::hasChanged $path -side val] | [Widget::hasChanged $path -baseline val] } { _place $path } return $res } # ------------------------------------------------------------------------------ # Command TitleFrame::cget # ------------------------------------------------------------------------------ proc TitleFrame::cget { path option } { return [Widget::cget $path $option] } # ------------------------------------------------------------------------------ # Command TitleFrame::getframe # ------------------------------------------------------------------------------ proc TitleFrame::getframe { path } { return $path.f } # ------------------------------------------------------------------------------ # Command TitleFrame::_place # ------------------------------------------------------------------------------ proc TitleFrame::_place { path } { set height [winfo height $path.l] switch [Widget::getoption $path -side] { left { set relx 0.0; set x 10; set anchor nw } center { set relx 0.5; set x 0; set anchor n } right { set relx 1.0; set x -10; set anchor ne } } set bd [Widget::getoption $path -borderwidth] switch [Widget::getoption $path -baseline] { top { set htop $height; set hbot 1; set y 0 } center { set htop [expr {$height/2}]; set hbot [expr {$height/2+$height%2+1}]; set y 0 } bottom { set htop 1; set hbot $height; set y [expr {$bd+1}] } } $path.p configure -height $htop $path.b.p configure -height $hbot place $path.l -relx $relx -x $x -anchor $anchor -y $y } amsn-0.98.9/utils/BWidget-1.9.0/labelframe.tcl0000644000175000017500000001307110516120770020320 0ustar billiobbilliob# ------------------------------------------------------------------------------ # labelframe.tcl # This file is part of Unifix BWidget Toolkit # $Id: labelframe.tcl,v 1.6 2003/10/20 21:23:52 damonc Exp $ # ------------------------------------------------------------------------------ # Index of commands: # - LabelFrame::create # - LabelFrame::getframe # - LabelFrame::configure # - LabelFrame::cget # - LabelFrame::align # ------------------------------------------------------------------------------ namespace eval LabelFrame { Widget::define LabelFrame labelframe Label Widget::bwinclude LabelFrame Label .l \ remove { -highlightthickness -highlightcolor -highlightbackground -takefocus -relief -borderwidth -cursor -dragenabled -draginitcmd -dragendcmd -dragevent -dragtype -dropenabled -droptypes -dropovercmd -dropcmd} \ initialize {-anchor w} Widget::declare LabelFrame { {-relief TkResource flat 0 frame} {-borderwidth TkResource 0 0 frame} {-side Enum left 1 {left right top bottom}} {-bd Synonym -borderwidth} } Widget::addmap LabelFrame "" :cmd {-background {}} Widget::addmap LabelFrame "" .f {-background {} -relief {} -borderwidth {}} Widget::syncoptions LabelFrame Label .l {-text {} -underline {}} bind BwLabelFrame [list Label::setfocus %W.l] bind BwLabelFrame [list LabelFrame::_destroy %W] } # ---------------------------------------------------------------------------- # Command LabelFrame::create # ---------------------------------------------------------------------------- proc LabelFrame::create { path args } { Widget::init LabelFrame $path $args set path [eval [list frame $path] [Widget::subcget $path :cmd] \ -relief flat -bd 0 -takefocus 0 -highlightthickness 0 \ -class LabelFrame] set label [eval [list Label::create $path.l] [Widget::subcget $path .l] \ -takefocus 0 -highlightthickness 0 -relief flat \ -borderwidth 0 -dropenabled 0 -dragenabled 0] set frame [eval [list frame $path.f] [Widget::subcget $path .f] \ -highlightthickness 0 -takefocus 0] switch [Widget::getoption $path -side] { left {set packopt "-side left"} right {set packopt "-side right"} top {set packopt "-side top -fill x"} bottom {set packopt "-side bottom -fill x"} } eval [list pack $label] $packopt pack $frame -fill both -expand yes bindtags $path [list $path BwLabelFrame [winfo toplevel $path] all] return [Widget::create LabelFrame $path] } # ---------------------------------------------------------------------------- # Command LabelFrame::getframe # ---------------------------------------------------------------------------- proc LabelFrame::getframe { path } { return $path.f } # ---------------------------------------------------------------------------- # Command LabelFrame::configure # ---------------------------------------------------------------------------- proc LabelFrame::configure { path args } { return [Widget::configure $path $args] } # ---------------------------------------------------------------------------- # Command LabelFrame::cget # ---------------------------------------------------------------------------- proc LabelFrame::cget { path option } { return [Widget::cget $path $option] } # ---------------------------------------------------------------------------- # Command LabelFrame::align # This command align label of all widget given by args of class LabelFrame # (or "derived") by setting their width to the max one +1 # ---------------------------------------------------------------------------- proc LabelFrame::align { args } { set maxlen 0 set wlist {} foreach wl $args { foreach w $wl { if { ![info exists Widget::_class($w)] } { continue } set class $Widget::_class($w) if { [string equal $class "LabelFrame"] } { set textopt -text set widthopt -width } else { upvar 0 Widget::${class}::map classmap set textopt "" set widthopt "" set notdone 2 foreach {option lmap} [array get classmap] { foreach {subpath subclass realopt} $lmap { if { [string equal $subclass "LabelFrame"] } { if { [string equal $realopt "-text"] } { set textopt $option incr notdone -1 break } if { [string equal $realopt "-width"] } { set widthopt $option incr notdone -1 break } } } if { !$notdone } { break } } if { $notdone } { continue } } set len [string length [$w cget $textopt]] if { $len > $maxlen } { set maxlen $len } lappend wlist $w $widthopt } } incr maxlen foreach {w widthopt} $wlist { $w configure $widthopt $maxlen } } proc LabelFrame::_destroy { path } { Widget::destroy $path } amsn-0.98.9/utils/BWidget-1.9.0/dropsite.tcl0000644000175000017500000003665711234370133020074 0ustar billiobbilliob# ------------------------------------------------------------------------------ # dropsite.tcl # This file is part of Unifix BWidget Toolkit # $Id: dropsite.tcl,v 1.8 2009/06/30 16:17:37 oehhar Exp $ # ------------------------------------------------------------------------------ # Index of commands: # - DropSite::include # - DropSite::setdrop # - DropSite::register # - DropSite::setcursor # - DropSite::setoperation # - DropSite::_update_operation # - DropSite::_compute_operation # - DropSite::_draw_operation # - DropSite::_init_drag # - DropSite::_motion # - DropSite::_release # ---------------------------------------------------------------------------- namespace eval DropSite { Widget::define DropSite dropsite -classonly Widget::declare DropSite [list \ [list -dropovercmd String "" 0] \ [list -dropcmd String "" 0] \ [list -droptypes String "" 0] \ ] proc use {} {} variable _top ".drag" variable _opw ".drag.\#op" variable _target "" variable _status 0 variable _tabops variable _defops variable _source variable _type variable _data variable _evt # key win unix # shift 1 | 1 -> 1 # control 4 | 4 -> 4 # alt 8 | 16 -> 24 # meta | 64 -> 88 array set _tabops { mod,none 0 mod,shift 1 mod,control 4 mod,alt 24 ops,copy 1 ops,move 1 ops,link 1 } if { $tcl_platform(platform) == "unix" } { set _tabops(mod,alt) 8 } else { set _tabops(mod,alt) 16 } array set _defops \ [list \ copy,mod shift \ move,mod control \ link,mod alt \ copy,img @[file join $::BWIDGET::LIBRARY "images" "opcopy.xbm"] \ move,img @[file join $::BWIDGET::LIBRARY "images" "opmove.xbm"] \ link,img @[file join $::BWIDGET::LIBRARY "images" "oplink.xbm"]] bind DragTop {DropSite::_update_operation [expr %s | 1]} bind DragTop {DropSite::_update_operation [expr %s | 1]} bind DragTop {DropSite::_update_operation [expr %s | 4]} bind DragTop {DropSite::_update_operation [expr %s | 4]} if { $tcl_platform(platform) == "unix" } { bind DragTop {DropSite::_update_operation [expr %s | 8]} bind DragTop {DropSite::_update_operation [expr %s | 8]} } else { bind DragTop {DropSite::_update_operation [expr %s | 16]} bind DragTop {DropSite::_update_operation [expr %s | 16]} } bind DragTop {DropSite::_update_operation [expr %s & ~1]} bind DragTop {DropSite::_update_operation [expr %s & ~1]} bind DragTop {DropSite::_update_operation [expr %s & ~4]} bind DragTop {DropSite::_update_operation [expr %s & ~4]} if { $tcl_platform(platform) == "unix" } { bind DragTop {DropSite::_update_operation [expr %s & ~8]} bind DragTop {DropSite::_update_operation [expr %s & ~8]} } else { bind DragTop {DropSite::_update_operation [expr %s & ~16]} bind DragTop {DropSite::_update_operation [expr %s & ~16]} } } # ---------------------------------------------------------------------------- # Command DropSite::include # ---------------------------------------------------------------------------- proc DropSite::include { class types } { set dropoptions [list \ [list -dropenabled Boolean 0 0] \ [list -dropovercmd String "" 0] \ [list -dropcmd String "" 0] \ [list -droptypes String $types 0] \ ] Widget::declare $class $dropoptions } # ---------------------------------------------------------------------------- # Command DropSite::setdrop # Widget interface to register # ---------------------------------------------------------------------------- proc DropSite::setdrop { path subpath dropover drop {force 0}} { set cen [Widget::hasChanged $path -dropenabled en] set ctypes [Widget::hasChanged $path -droptypes types] if { $en } { if { $force || $cen || $ctypes } { register $subpath \ -droptypes $types \ -dropcmd $drop \ -dropovercmd $dropover } } else { register $subpath } } # ---------------------------------------------------------------------------- # Command DropSite::register # ---------------------------------------------------------------------------- proc DropSite::register { path args } { variable _tabops variable _defops upvar \#0 DropSite::$path drop Widget::init DropSite .drop$path $args if { [info exists drop] } { unset drop } set dropcmd [Widget::getMegawidgetOption .drop$path -dropcmd] set types [Widget::getMegawidgetOption .drop$path -droptypes] set overcmd [Widget::getMegawidgetOption .drop$path -dropovercmd] Widget::destroy .drop$path if { $dropcmd != "" && $types != "" } { set drop(dropcmd) $dropcmd set drop(overcmd) $overcmd foreach {type ops} $types { set drop($type,ops) {} set masklist {} foreach {descop lmod} $ops { if { ![llength $descop] || [llength $descop] > 3 } { return -code error "invalid operation description \"$descop\"" } foreach {subop baseop imgop} $descop { set subop [string trim $subop] if { ![string length $subop] } { return -code error "sub operation is empty" } if { ![string length $baseop] } { set baseop $subop } if { [info exists drop($type,ops,$subop)] } { return -code error "operation \"$subop\" already defined" } if { ![info exists _tabops(ops,$baseop)] } { return -code error "invalid base operation \"$baseop\"" } if { ![string equal $subop $baseop] && [info exists _tabops(ops,$subop)] } { return -code error "sub operation \"$subop\" is a base operation" } if { ![string length $imgop] } { set imgop $_defops($baseop,img) } } if { [string equal $lmod "program"] } { set drop($type,ops,$subop) $baseop set drop($type,img,$subop) $imgop } else { if { ![string length $lmod] } { set lmod $_defops($baseop,mod) } set mask 0 foreach mod $lmod { if { ![info exists _tabops(mod,$mod)] } { return -code error "invalid modifier \"$mod\"" } set mask [expr {$mask | $_tabops(mod,$mod)}] } if { ($mask == 0) != ([string equal $subop "default"]) } { return -code error "sub operation default can only be used with modifier \"none\"" } set drop($type,mod,$mask) $subop set drop($type,ops,$subop) $baseop set drop($type,img,$subop) $imgop lappend masklist $mask } } if { ![info exists drop($type,mod,0)] } { set drop($type,mod,0) default set drop($type,ops,default) copy set drop($type,img,default) $_defops(copy,img) lappend masklist 0 } set drop($type,ops,force) copy set drop($type,img,force) $_defops(copy,img) foreach mask [lsort -integer -decreasing $masklist] { lappend drop($type,ops) $mask $drop($type,mod,$mask) } } } } # ---------------------------------------------------------------------------- # Command DropSite::setcursor # ---------------------------------------------------------------------------- proc DropSite::setcursor { cursor } { catch {.drag configure -cursor $cursor} } # ---------------------------------------------------------------------------- # Command DropSite::setoperation # ---------------------------------------------------------------------------- proc DropSite::setoperation { op } { variable _curop variable _dragops variable _target variable _type upvar \#0 DropSite::$_target drop if { [info exist drop($_type,ops,$op)] && $_dragops($drop($_type,ops,$op)) } { set _curop $op } else { # force to a copy operation set _curop force } } # ---------------------------------------------------------------------------- # Command DropSite::_init_drag # ---------------------------------------------------------------------------- proc DropSite::_init_drag { top evt source state X Y type ops data } { variable _top variable _source variable _type variable _data variable _target variable _status variable _state variable _dragops variable _opw variable _evt if {[info exists _dragops]} { unset _dragops } array set _dragops {copy 1 move 0 link 0} foreach op $ops { set _dragops($op) 1 } set _target "" set _status 0 set _top $top set _source $source set _type $type set _data $data label $_opw -relief flat -bd 0 -highlightthickness 0 \ -foreground black -background white bind $top {DropSite::_release %X %Y} bind $top {DropSite::_motion %X %Y} bind $top {DropSite::_release %X %Y} set _state $state set _evt $evt _motion $X $Y } # ---------------------------------------------------------------------------- # Command DropSite::_update_operation # ---------------------------------------------------------------------------- proc DropSite::_update_operation { state } { variable _top variable _status variable _state if { $_status & 3 } { set _state $state _motion [winfo pointerx $_top] [winfo pointery $_top] } } # ---------------------------------------------------------------------------- # Command DropSite::_compute_operation # ---------------------------------------------------------------------------- proc DropSite::_compute_operation { target state type } { variable _curop variable _dragops upvar \#0 DropSite::$target drop foreach {mask op} $drop($type,ops) { if { ($state & $mask) == $mask } { if { $_dragops($drop($type,ops,$op)) } { set _curop $op return } } } set _curop force } # ---------------------------------------------------------------------------- # Command DropSite::_draw_operation # ---------------------------------------------------------------------------- proc DropSite::_draw_operation { target type } { variable _opw variable _curop variable _dragops variable _tabops variable _status upvar \#0 DropSite::$target drop if { !($_status & 1) } { catch {place forget $_opw} return } if { 0 } { if { ![info exist drop($type,ops,$_curop)] || !$_dragops($drop($type,ops,$_curop)) } { # force to a copy operation set _curop copy catch { $_opw configure -bitmap $_tabops(img,copy) place $_opw -relx 1 -rely 1 -anchor se } } } elseif { [string equal $_curop "default"] } { catch {place forget $_opw} } else { catch { $_opw configure -bitmap $drop($type,img,$_curop) place $_opw -relx 1 -rely 1 -anchor se } } } # ---------------------------------------------------------------------------- # Command DropSite::_motion # ---------------------------------------------------------------------------- proc DropSite::_motion { X Y } { variable _top variable _target variable _status variable _state variable _curop variable _type variable _data variable _source variable _evt set script [bind $_top ] bind $_top {} bind $_top {} wm geometry $_top "+[expr {$X+1}]+[expr {$Y+1}]" update if { ![winfo exists $_top] } { return } set path [winfo containing $X $Y] if { ![string equal $path $_target] } { # path != current target if { $_status & 2 } { # current target is valid and has recall status # generate leave event upvar \#0 DropSite::$_target drop uplevel \#0 $drop(overcmd) [list $_target $_source leave $X $Y $_curop $_type $_data] } set _target $path upvar \#0 DropSite::$_target drop if { [info exists drop($_type,ops)] } { # path is a valid target _compute_operation $_target $_state $_type if { $drop(overcmd) != "" } { set arg [list $_target $_source enter $X $Y $_curop $_type $_data] set _status [uplevel \#0 $drop(overcmd) $arg] } else { set _status 1 catch {$_top configure -cursor based_arrow_down} } _draw_operation $_target $_type update catch { bind $_top {DropSite::_motion %X %Y} bind $_top {DropSite::_release %X %Y} } return } else { set _status 0 catch {$_top configure -cursor dot} _draw_operation "" "" } } elseif { $_status & 2 } { upvar \#0 DropSite::$_target drop _compute_operation $_target $_state $_type set arg [list $_target $_source motion $X $Y $_curop $_type $_data] set _status [uplevel \#0 $drop(overcmd) $arg] _draw_operation $_target $_type } update catch { bind $_top {DropSite::_motion %X %Y} bind $_top {DropSite::_release %X %Y} } } # ---------------------------------------------------------------------------- # Command DropSite::_release # ---------------------------------------------------------------------------- proc DropSite::_release { X Y } { variable _target variable _status variable _curop variable _source variable _type variable _data if { $_status & 1 } { upvar \#0 DropSite::$_target drop set res [uplevel \#0 $drop(dropcmd) [list $_target $_source $X $Y $_curop $_type $_data]] DragSite::_end_drag $_source $_target $drop($_type,ops,$_curop) $_type $_data $res } else { if { $_status & 2 } { # notify leave event upvar \#0 DropSite::$_target drop uplevel \#0 $drop(overcmd) [list $_target $_source leave $X $Y $_curop $_type $_data] } DragSite::_end_drag $_source "" "" $_type $_data 0 } } amsn-0.98.9/utils/BWidget-1.9.0/progressbar.tcl0000644000175000017500000001616010516120770020561 0ustar billiobbilliob# ---------------------------------------------------------------------------- # progressbar.tcl # This file is part of Unifix BWidget Toolkit # ---------------------------------------------------------------------------- # Index of commands: # - ProgressBar::create # - ProgressBar::configure # - ProgressBar::cget # - ProgressBar::_destroy # - ProgressBar::_modify # ---------------------------------------------------------------------------- namespace eval ProgressBar { Widget::define ProgressBar progressbar Widget::declare ProgressBar { {-type Enum normal 0 {normal incremental infinite nonincremental_infinite}} {-maximum Int 100 0 "%d > 0"} {-background TkResource "" 0 frame} {-foreground TkResource "blue" 0 label} {-borderwidth TkResource 2 0 frame} {-troughcolor TkResource "" 0 scrollbar} {-relief TkResource sunken 0 label} {-orient Enum horizontal 1 {horizontal vertical}} {-variable String "" 0} {-idle Boolean 0 0} {-width TkResource 100 0 frame} {-height TkResource 4m 0 frame} {-bg Synonym -background} {-fg Synonym -foreground} {-bd Synonym -borderwidth} } Widget::addmap ProgressBar "" :cmd {-background {} -width {} -height {}} Widget::addmap ProgressBar "" .bar { -troughcolor -background -borderwidth {} -relief {} } variable _widget } # ---------------------------------------------------------------------------- # Command ProgressBar::create # ---------------------------------------------------------------------------- proc ProgressBar::create { path args } { variable _widget array set maps [list ProgressBar {} :cmd {} .bar {}] array set maps [Widget::parseArgs ProgressBar $args] eval frame $path $maps(:cmd) -class ProgressBar -bd 0 \ -highlightthickness 0 -relief flat Widget::initFromODB ProgressBar $path $maps(ProgressBar) set c [eval [list canvas $path.bar] $maps(.bar) -highlightthickness 0] set fg [Widget::cget $path -foreground] if { [string equal [Widget::cget $path -orient] "horizontal"] } { $path.bar create rectangle -1 0 0 0 -fill $fg -outline $fg -tags rect } else { $path.bar create rectangle 0 1 0 0 -fill $fg -outline $fg -tags rect } set _widget($path,val) 0 set _widget($path,dir) 1 set _widget($path,var) [Widget::cget $path -variable] if {$_widget($path,var) != ""} { GlobalVar::tracevar variable $_widget($path,var) w \ [list ProgressBar::_modify $path] set _widget($path,afterid) \ [after idle [list ProgressBar::_modify $path]] } bind $path.bar [list ProgressBar::_destroy $path] bind $path.bar [list ProgressBar::_modify $path] return [Widget::create ProgressBar $path] } # ---------------------------------------------------------------------------- # Command ProgressBar::configure # ---------------------------------------------------------------------------- proc ProgressBar::configure { path args } { variable _widget set res [Widget::configure $path $args] if { [Widget::hasChangedX $path -variable] } { set newv [Widget::cget $path -variable] if { $_widget($path,var) != "" } { GlobalVar::tracevar vdelete $_widget($path,var) w \ [list ProgressBar::_modify $path] } if { $newv != "" } { set _widget($path,var) $newv GlobalVar::tracevar variable $newv w \ [list ProgressBar::_modify $path] if {![info exists _widget($path,afterid)]} { set _widget($path,afterid) \ [after idle [list ProgressBar::_modify $path]] } } else { set _widget($path,var) "" } } foreach {cbd cor cma} [Widget::hasChangedX $path -borderwidth \ -orient -maximum] break if { $cbd || $cor || $cma } { if {![info exists _widget($path,afterid)]} { set _widget($path,afterid) \ [after idle [list ProgressBar::_modify $path]] } } if { [Widget::hasChangedX $path -foreground] } { set fg [Widget::cget $path -foreground] $path.bar itemconfigure rect -fill $fg -outline $fg } return $res } # ---------------------------------------------------------------------------- # Command ProgressBar::cget # ---------------------------------------------------------------------------- proc ProgressBar::cget { path option } { return [Widget::cget $path $option] } # ---------------------------------------------------------------------------- # Command ProgressBar::_modify # ---------------------------------------------------------------------------- proc ProgressBar::_modify { path args } { variable _widget catch {unset _widget($path,afterid)} if { ![GlobalVar::exists $_widget($path,var)] || [set val [GlobalVar::getvar $_widget($path,var)]] < 0 } { catch {place forget $path.bar} } else { place $path.bar -relx 0 -rely 0 -relwidth 1 -relheight 1 set type [Widget::getoption $path -type] if { $val != 0 && $type != "normal" && \ $type != "nonincremental_infinite"} { set val [expr {$val+$_widget($path,val)}] } set _widget($path,val) $val set max [Widget::getoption $path -maximum] set bd [expr {2*[$path.bar cget -bd]}] set w [winfo width $path.bar] set h [winfo height $path.bar] if {$type == "infinite" || $type == "nonincremental_infinite"} { # JDC: New infinite behaviour set tval [expr {$val % $max}] if { $tval < ($max / 2.0) } { set x0 [expr {double($tval) / double($max) * 1.5}] } else { set x0 [expr {(1.0-(double($tval) / double($max))) * 1.5}] } set x1 [expr {$x0 + 0.25}] # convert coords to ints to prevent triggering canvas refresh # bug related to fractional coords if {[Widget::getoption $path -orient] == "horizontal"} { $path.bar coords rect [expr {int($x0*$w)}] 0 \ [expr {int($x1*$w)}] $h } else { $path.bar coords rect 0 [expr {int($h-$x0*$h)}] $w \ [expr {int($x1*$h)}] } } else { if { $val > $max } {set val $max} if {[Widget::getoption $path -orient] == "horizontal"} { $path.bar coords rect -1 0 [expr {int(double($val)*$w/$max)}] $h } else { $path.bar coords rect 0 [expr {$h+1}] $w \ [expr {int($h*(1.0 - double($val)/$max))}] } } } if {![Widget::cget $path -idle]} { update idletasks } } # ---------------------------------------------------------------------------- # Command ProgressBar::_destroy # ---------------------------------------------------------------------------- proc ProgressBar::_destroy { path } { variable _widget if {[info exists _widget($path,afterid)]} { after cancel $_widget($path,afterid) unset _widget($path,afterid) } if {[info exists _widget($path,var)]} { if {$_widget($path,var) != ""} { GlobalVar::tracevar vdelete $_widget($path,var) w \ [list ProgressBar::_modify $path] } unset _widget($path,var) } unset _widget($path,dir) Widget::destroy $path } amsn-0.98.9/utils/BWidget-1.9.0/buttonbox.tcl0000644000175000017500000003020411234370133020245 0ustar billiobbilliob# ---------------------------------------------------------------------------- # buttonbox.tcl # This file is part of Unifix BWidget Toolkit # ---------------------------------------------------------------------------- # Index of commands: # - ButtonBox::create # - ButtonBox::configure # - ButtonBox::cget # - ButtonBox::add # - ButtonBox::itemconfigure # - ButtonBox::itemcget # - ButtonBox::setfocus # - ButtonBox::invoke # - ButtonBox::index # - ButtonBox::_destroy # ---------------------------------------------------------------------------- namespace eval ButtonBox { Widget::define ButtonBox buttonbox Button Widget::declare ButtonBox { {-background TkResource "" 0 frame} {-orient Enum horizontal 1 {horizontal vertical}} {-state Enum "normal" 0 {normal disabled}} {-homogeneous Boolean 1 1} {-spacing Int 10 0 "%d >= 0"} {-padx TkResource "" 0 button} {-pady TkResource "" 0 button} {-default Int -1 0 "%d >= -1"} {-bg Synonym -background} } Widget::addmap ButtonBox "" :cmd {-background {}} bind ButtonBox [list ButtonBox::_destroy %W] } # ---------------------------------------------------------------------------- # Command ButtonBox::create # ---------------------------------------------------------------------------- proc ButtonBox::create { path args } { Widget::init ButtonBox $path $args variable $path upvar 0 $path data eval [list frame $path] [Widget::subcget $path :cmd] \ [list -class ButtonBox -takefocus 0 -highlightthickness 0] # For 8.4+ we don't want to inherit the padding catch {$path configure -padx 0 -pady 0} set data(max) 0 set data(nbuttons) 0 set data(buttons) [list] set data(default) [Widget::getoption $path -default] return [Widget::create ButtonBox $path] } # ---------------------------------------------------------------------------- # Command ButtonBox::configure # ---------------------------------------------------------------------------- proc ButtonBox::configure { path args } { variable $path upvar 0 $path data set res [Widget::configure $path $args] if { [Widget::hasChanged $path -default val] } { if { $data(default) != -1 && $val != -1 } { set but $path.b$data(default) if { [winfo exists $but] } { $but configure -default normal } set but $path.b$val if { [winfo exists $but] } { $but configure -default active } set data(default) $val } else { Widget::setoption $path -default $data(default) } } if {[Widget::hasChanged $path -state val]} { foreach i $data(buttons) { $path.b$i configure -state $val } } return $res } # ---------------------------------------------------------------------------- # Command ButtonBox::cget # ---------------------------------------------------------------------------- proc ButtonBox::cget { path option } { return [Widget::cget $path $option] } # ---------------------------------------------------------------------------- # Command ButtonBox::add # ---------------------------------------------------------------------------- proc ButtonBox::add { path args } { return [eval [linsert $args 0 insert $path end]] } proc ButtonBox::insert { path idx args } { variable $path upvar 0 $path data set but $path.b$data(nbuttons) set spacing [Widget::getoption $path -spacing] ## Save the current spacing setting for this button. Buttons ## appended to the end of the box have their spacing applied ## to their left while all other have their spacing applied ## to their right. if {$idx == "end"} { set data(spacing,$data(nbuttons)) [list left $spacing] lappend data(buttons) $data(nbuttons) } else { set data(spacing,$data(nbuttons)) [list right $spacing] set data(buttons) [linsert $data(buttons) $idx $data(nbuttons)] } if { $data(nbuttons) == $data(default) } { set style active } elseif { $data(default) == -1 } { set style disabled } else { set style normal } array set flags $args set tags "" if { [info exists flags(-tags)] } { set tags $flags(-tags) unset flags(-tags) set args [array get flags] } eval [list Button::create $but \ -background [Widget::getoption $path -background]\ -padx [Widget::getoption $path -padx] \ -pady [Widget::getoption $path -pady]] \ $args [list -default $style] # ericm@scriptics.com: set up tags, just like the menu items foreach tag $tags { lappend data(tags,$tag) $but if { ![info exists data(tagstate,$tag)] } { set data(tagstate,$tag) 0 } } set data(buttontags,$but) $tags # ericm@scriptics.com _redraw $path incr data(nbuttons) return $but } proc ButtonBox::delete { path idx } { variable $path upvar 0 $path data set i [lindex $data(buttons) $idx] set data(buttons) [lreplace $data(buttons) $idx $idx] destroy $path.b$i } # ButtonBox::setbuttonstate -- # # Set the state of a given button tag. If this makes any buttons # enable-able (ie, all of their tags are TRUE), enable them. # # Arguments: # path the button box widget name # tag the tag to modify # state the new state of $tag (0 or 1) # # Results: # None. proc ButtonBox::setbuttonstate {path tag state} { variable $path upvar 0 $path data # First see if this is a real tag if { [info exists data(tagstate,$tag)] } { set data(tagstate,$tag) $state foreach but $data(tags,$tag) { set expression "1" foreach buttontag $data(buttontags,$but) { append expression " && $data(tagstate,$buttontag)" } if { [expr $expression] } { set state normal } else { set state disabled } $but configure -state $state } } return } # ButtonBox::getbuttonstate -- # # Retrieve the state of a given button tag. # # Arguments: # path the button box widget name # tag the tag to modify # # Results: # None. proc ButtonBox::getbuttonstate {path tag} { variable $path upvar 0 $path data # First see if this is a real tag if { [info exists data(tagstate,$tag)] } { return $data(tagstate,$tag) } else { error "unknown tag $tag" } } # ---------------------------------------------------------------------------- # Command ButtonBox::itemconfigure # ---------------------------------------------------------------------------- proc ButtonBox::itemconfigure { path index args } { if { [set idx [lsearch $args -default]] != -1 } { set args [lreplace $args $idx [expr {$idx+1}]] } return [eval [list Button::configure $path.b[index $path $index]] $args] } # ---------------------------------------------------------------------------- # Command ButtonBox::itemcget # ---------------------------------------------------------------------------- proc ButtonBox::itemcget { path index option } { return [Button::cget $path.b[index $path $index] $option] } # ---------------------------------------------------------------------------- # Command ButtonBox::setfocus # ---------------------------------------------------------------------------- proc ButtonBox::setfocus { path index } { set but $path.b[index $path $index] if { [winfo exists $but] } { focus $but } } # ---------------------------------------------------------------------------- # Command ButtonBox::invoke # ---------------------------------------------------------------------------- proc ButtonBox::invoke { path index } { set but $path.b[index $path $index] if { [winfo exists $but] } { Button::invoke $but } } # ---------------------------------------------------------------------------- # Command ButtonBox::index # ---------------------------------------------------------------------------- proc ButtonBox::index { path index } { variable $path upvar 0 $path data set n [expr {$data(nbuttons) - 1}] if {[string equal $index "default"]} { set res [Widget::getoption $path -default] } elseif {$index == "end" || $index == "last"} { set res $n } elseif {![string is integer -strict $index]} { ## It's not an integer. Search the text of each button ## in the box and return the index that matches. foreach i $data(buttons) { set w $path.b$i lappend text [$w cget -text] lappend names [$w cget -name] } set res [lsearch -exact [concat $names $text] $index] } else { set res $index if {$index > $n} { set res $n } } return $res } # ButtonBox::gettags -- # # Return a list of all the tags on all the buttons in a buttonbox. # # Arguments: # path the buttonbox to query. # # Results: # taglist a list of tags on the buttons in the buttonbox proc ButtonBox::gettags {path} { upvar ::ButtonBox::$path data set taglist {} foreach tag [array names data "tags,*"] { lappend taglist [string range $tag 5 end] } return $taglist } # ---------------------------------------------------------------------------- # Command ButtonBox::_redraw # ---------------------------------------------------------------------------- proc ButtonBox::_redraw { path } { variable $path upvar 0 $path data Widget::getVariable $path buttons # For tk >= 8.4, -uniform gridding option is used. # Otherwise, there is the constraint, that button size may not change after # creation. set uniformAvailable [expr {0 <= [package vcompare [info patchlevel] 8.4.0]}] ## We re-grid the buttons from left-to-right. As we go through ## each button, we check its spacing and which direction the ## spacing applies to. Once spacing has been applied to an index, ## it is not changed. This means spacing takes precedence from ## left-to-right. set idx 0 set idxs [list] foreach i $data(buttons) { set dir [lindex $data(spacing,$i) 0] set spacing [lindex $data(spacing,$i) 1] set but $path.b$i if {[string equal [Widget::getoption $path -orient] "horizontal"]} { grid $but -column $idx -row 0 -sticky nsew if { [Widget::getoption $path -homogeneous] } { if {$uniformAvailable} { grid columnconfigure $path $idx -uniform koen -weight 1 } else { set req [winfo reqwidth $but] if { $req > $data(max) } { grid columnconfigure $path [expr {2*$i}] -minsize $req set data(max) $req } grid columnconfigure $path $idx -weight 1 } } else { grid columnconfigure $path $idx -weight 0 } set col [expr {$idx - 1}] if {[string equal $dir "right"]} { set col [expr {$idx + 1}] } if {$col > 0 && [lsearch $idxs $col] < 0} { lappend idxs $col grid columnconfigure $path $col -minsize $spacing } } else { grid $but -column 0 -row $idx -sticky nsew grid rowconfigure $path $idx -weight 0 set row [expr {$idx - 1}] if {[string equal $dir "right"]} { set row [expr {$idx + 1}] } if {$row > 0 && [lsearch $idxs $row] < 0} { lappend idxs $row grid rowconfigure $path $row -minsize $spacing } } incr idx 2 } if {!$uniformAvailable} { # Now that the maximum size has been calculated, go back through # and correctly set the size for homogeneous horizontal buttons. if { [string equal [Widget::getoption $path -orient] "horizontal"] && [Widget::getoption $path -homogeneous] } { set idx 0 foreach i $data(buttons) { grid columnconfigure $path $idx -minsize $data(max) incr idx 2 } } } } # ---------------------------------------------------------------------------- # Command ButtonBox::_destroy # ---------------------------------------------------------------------------- proc ButtonBox::_destroy { path } { variable $path upvar 0 $path data Widget::destroy $path unset data } amsn-0.98.9/utils/BWidget-1.9.0/spinbox.tcl0000644000175000017500000002671710516120770017723 0ustar billiobbilliob# spinbox.tcl -- # # BWidget SpinBox implementation. # # Copyright (c) 1999 by Unifix # Copyright (c) 2000 by Ajuba Solutions # All rights reserved. # # RCS: @(#) $Id: spinbox.tcl,v 1.12 2003/10/20 21:23:52 damonc Exp $ # ----------------------------------------------------------------------------- # Index of commands: # - SpinBox::create # - SpinBox::configure # - SpinBox::cget # - SpinBox::setvalue # - SpinBox::_destroy # - SpinBox::_modify_value # - SpinBox::_test_options # ----------------------------------------------------------------------------- namespace eval SpinBox { Widget::define SpinBox spinbox Entry ArrowButton Widget::tkinclude SpinBox frame :cmd \ include {-background -borderwidth -bg -bd -relief} \ initialize {-relief sunken -borderwidth 2} Widget::bwinclude SpinBox Entry .e \ remove {-relief -bd -borderwidth -fg -bg} \ rename {-foreground -entryfg -background -entrybg} Widget::declare SpinBox { {-range String "" 0} {-values String "" 0} {-modifycmd String "" 0} {-repeatdelay Int 400 0 {%d >= 0}} {-repeatinterval Int 100 0 {%d >= 0}} {-foreground TkResource black 0 {button}} } Widget::addmap SpinBox "" :cmd {-background {}} Widget::addmap SpinBox ArrowButton .arrup { -foreground {} -background {} -disabledforeground {} -state {} \ -repeatinterval {} -repeatdelay {} } Widget::addmap SpinBox ArrowButton .arrdn { -foreground {} -background {} -disabledforeground {} -state {} \ -repeatinterval {} -repeatdelay {} } ::bind SpinBox [list after idle {BWidget::refocus %W %W.e}] ::bind SpinBox [list SpinBox::_destroy %W] variable _widget } # ----------------------------------------------------------------------------- # Command SpinBox::create # ----------------------------------------------------------------------------- proc SpinBox::create { path args } { array set maps [list SpinBox {} :cmd {} .e {} .arrup {} .arrdn {}] array set maps [Widget::parseArgs SpinBox $args] eval [list frame $path] $maps(:cmd) \ [list -highlightthickness 0 -takefocus 0 -class SpinBox] Widget::initFromODB SpinBox $path $maps(SpinBox) set entry [eval [list Entry::create $path.e] $maps(.e) -relief flat -bd 0] bindtags $path.e [linsert [bindtags $path.e] 1 SpinBoxEntry] set farr [frame $path.farr -relief flat -bd 0 -highlightthickness 0] set height [expr {[winfo reqheight $path.e]/2-2}] set width 11 set arrup [eval [list ArrowButton::create $path.arrup -dir top] \ $maps(.arrup) \ [list -highlightthickness 0 -borderwidth 1 -takefocus 0 \ -type button -width $width -height $height \ -armcommand [list SpinBox::_modify_value $path next arm] \ -disarmcommand [list SpinBox::_modify_value $path next disarm]]] set arrdn [eval [list ArrowButton::create $path.arrdn -dir bottom] \ $maps(.arrdn) \ [list -highlightthickness 0 -borderwidth 1 -takefocus 0 \ -type button -width $width -height $height \ -armcommand [list SpinBox::_modify_value $path previous arm] \ -disarmcommand [list SpinBox::_modify_value $path previous disarm]]] # --- update SpinBox value --- _test_options $path set val [Entry::cget $path.e -text] if { [string equal $val ""] } { Entry::configure $path.e -text $::SpinBox::_widget($path,curval) } else { set ::SpinBox::_widget($path,curval) $val } grid $arrup -in $farr -column 0 -row 0 -sticky nsew grid $arrdn -in $farr -column 0 -row 2 -sticky nsew grid rowconfigure $farr 0 -weight 1 grid rowconfigure $farr 2 -weight 1 pack $farr -side right -fill y pack $entry -side left -fill both -expand yes ::bind $entry [list SpinBox::_modify_value $path next activate] ::bind $entry [list SpinBox::_modify_value $path previous activate] ::bind $entry [list SpinBox::_modify_value $path last activate] ::bind $entry [list SpinBox::_modify_value $path first activate] ::bind $farr {grid rowconfigure %W 1 -minsize [expr {%h%%2}]} return [Widget::create SpinBox $path] } # ----------------------------------------------------------------------------- # Command SpinBox::configure # ----------------------------------------------------------------------------- proc SpinBox::configure { path args } { set res [Widget::configure $path $args] if { [Widget::hasChangedX $path -values] || [Widget::hasChangedX $path -range] } { _test_options $path } return $res } # ----------------------------------------------------------------------------- # Command SpinBox::cget # ----------------------------------------------------------------------------- proc SpinBox::cget { path option } { return [Widget::cget $path $option] } # ----------------------------------------------------------------------------- # Command SpinBox::setvalue # ----------------------------------------------------------------------------- proc SpinBox::setvalue { path index } { variable _widget set values [Widget::getMegawidgetOption $path -values] set value [Entry::cget $path.e -text] if { [llength $values] } { # --- -values SpinBox --- switch -- $index { next { if { [set idx [lsearch $values $value]] != -1 } { incr idx } elseif { [set idx [lsearch $values "$value*"]] == -1 } { set idx [lsearch $values $_widget($path,curval)] } } previous { if { [set idx [lsearch $values $value]] != -1 } { incr idx -1 } elseif { [set idx [lsearch $values "$value*"]] == -1 } { set idx [lsearch $values $_widget($path,curval)] } } first { set idx 0 } last { set idx [expr {[llength $values]-1}] } default { if { [string index $index 0] == "@" } { set idx [string range $index 1 end] if { [catch {string compare [expr {int($idx)}] $idx} res] || $res != 0 } { return -code error "bad index \"$index\"" } } else { return -code error "bad index \"$index\"" } } } if { $idx >= 0 && $idx < [llength $values] } { set newval [lindex $values $idx] } else { return 0 } } else { # --- -range SpinBox --- foreach {vmin vmax incr} [Widget::getMegawidgetOption $path -range] { break } # Allow zero padding on the value; strip it out for calculation by # scanning the value into a floating point number. scan $value %f value switch -- $index { next { if { [catch {expr {double($value-$vmin)/$incr}} idx] } { set newval $_widget($path,curval) } else { set newval [expr {$vmin+(round($idx)+1)*$incr}] if { $newval < $vmin } { set newval $vmin } elseif { $newval > $vmax } { set newval $vmax } } } previous { if { [catch {expr {double($value-$vmin)/$incr}} idx] } { set newval $_widget($path,curval) } else { set newval [expr {$vmin+(round($idx)-1)*$incr}] if { $newval < $vmin } { set newval $vmin } elseif { $newval > $vmax } { set newval $vmax } } } first { set newval $vmin } last { set newval $vmax } default { if { [string index $index 0] == "@" } { set idx [string range $index 1 end] if { [catch {string compare [expr {int($idx)}] $idx} res] || $res != 0 } { return -code error "bad index \"$index\"" } set newval [expr {$vmin+int($idx)*$incr}] if { $newval < $vmin || $newval > $vmax } { return 0 } } else { return -code error "bad index \"$index\"" } } } } set _widget($path,curval) $newval Entry::configure $path.e -text $newval return 1 } # ----------------------------------------------------------------------------- # Command SpinBox::getvalue # ----------------------------------------------------------------------------- proc SpinBox::getvalue { path } { variable _widget set values [Widget::getMegawidgetOption $path -values] set value [Entry::cget $path.e -text] if { [llength $values] } { # --- -values SpinBox --- return [lsearch $values $value] } else { foreach {vmin vmax incr} [Widget::getMegawidgetOption $path -range] { break } if { ![catch {expr {double($value-$vmin)/$incr}} idx] && $idx == int($idx) } { return [expr {int($idx)}] } return -1 } } # ----------------------------------------------------------------------------- # Command SpinBox::bind # ----------------------------------------------------------------------------- proc SpinBox::bind { path args } { return [eval [list ::bind $path.e] $args] } # ----------------------------------------------------------------------------- # Command SpinBox::_modify_value # ----------------------------------------------------------------------------- proc SpinBox::_modify_value { path direction reason } { if { $reason == "arm" || $reason == "activate" } { SpinBox::setvalue $path $direction } if { ($reason == "disarm" || $reason == "activate") && [set cmd [Widget::getMegawidgetOption $path -modifycmd]] != "" } { uplevel \#0 $cmd } } # ----------------------------------------------------------------------------- # Command SpinBox::_test_options # ----------------------------------------------------------------------------- proc SpinBox::_test_options { path } { set values [Widget::getMegawidgetOption $path -values] if { [llength $values] } { set ::SpinBox::_widget($path,curval) [lindex $values 0] } else { foreach {vmin vmax incr} [Widget::getMegawidgetOption $path -range] { break } set update 0 if { [catch {expr {int($vmin)}}] } { set vmin 0 set update 1 } if { [catch {expr {$vmax<$vmin}} res] || $res } { set vmax $vmin set update 1 } if { [catch {expr {$incr<0}} res] || $res } { set incr 1 set update 1 } # Only do the set back (which is expensive) if we changed a value if { $update } { Widget::setMegawidgetOption $path -range [list $vmin $vmax $incr] } set ::SpinBox::_widget($path,curval) $vmin } } # ----------------------------------------------------------------------------- # Command SpinBox::_destroy # ----------------------------------------------------------------------------- proc SpinBox::_destroy { path } { variable _widget unset _widget($path,curval) Widget::destroy $path } amsn-0.98.9/utils/BWidget-1.9.0/LICENSE.txt0000644000175000017500000000425710572640472017363 0ustar billiobbilliobBWidget ToolKit Copyright (c) 1998-1999 UNIFIX. Copyright (c) 2001-2002 ActiveState Corp. The following terms apply to all files associated with the software unless explicitly disclaimed in individual files. The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. GOVERNMENT USE: If you are acquiring this software on behalf of the U.S. government, the Government shall have only "Restricted Rights" in the software and related documentation as defined in the Federal Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are acquiring the software on behalf of the Department of Defense, the software shall be classified as "Commercial Computer Software" and the Government shall have only "Restricted Rights" as defined in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license. amsn-0.98.9/utils/BWidget-1.9.0/color.tcl0000644000175000017500000003454210516120770017352 0ustar billiobbilliobnamespace eval SelectColor { Widget::define SelectColor color Dialog Widget::declare SelectColor { {-title String "Select a color" 0} {-parent String "" 0} {-color TkResource "" 0 {label -background}} {-type Enum "dialog" 1 {dialog popup}} {-placement String "center" 1} } variable _baseColors { \#0000ff \#00ff00 \#00ffff \#ff0000 \#ff00ff \#ffff00 \#000099 \#009900 \#009999 \#990000 \#990099 \#999900 \#000000 \#333333 \#666666 \#999999 \#cccccc \#ffffff } variable _userColors { \#ffffff \#ffffff \#ffffff \#ffffff \#ffffff \#ffffff \#ffffff \#ffffff \#ffffff \#ffffff \#ffffff } if {[string equal $::tcl_platform(platform) "unix"]} { set useTkDialogue 0 } else { set useTkDialogue 1 } variable _selectype variable _selection variable _wcolor variable _image variable _hsv } proc SelectColor::create { path args } { Widget::init SelectColor $path $args set type [Widget::cget $path -type] switch -- [Widget::cget $path -type] { "dialog" { return [eval [list SelectColor::dialog $path] $args] } "popup" { set list [list at center left right above below] set placement [Widget::cget $path -placement] set where [lindex $placement 0] if {[lsearch $list $where] < 0} { return -code error \ [BWidget::badOptionString placement $placement $list] } ## If they specified a parent and didn't pass a second argument ## in the placement, set the placement relative to the parent. set parent [Widget::cget $path -parent] if {[string length $parent]} { if {[llength $placement] == 1} { lappend placement $parent } } return [eval [list SelectColor::menu $path $placement] $args] } } } proc SelectColor::menu {path placement args} { variable _baseColors variable _userColors variable _wcolor variable _selectype variable _selection Widget::init SelectColor $path $args set top [toplevel $path] set parent [winfo toplevel [winfo parent $top]] wm withdraw $top wm transient $top $parent wm overrideredirect $top 1 catch { wm attributes $top -topmost 1 } set frame [frame $top.frame \ -highlightthickness 0 \ -relief raised -borderwidth 2] set col 0 set row 0 set count 0 set colors [concat $_baseColors $_userColors] foreach color $colors { set f [frame $frame.c$count \ -highlightthickness 2 \ -highlightcolor white \ -relief solid -borderwidth 1 \ -width 16 -height 16 -background $color] bind $f <1> "set SelectColor::_selection $count; break" bind $f {focus %W} grid $f -column $col -row $row incr count if {[incr col] == 6 } { set col 0 incr row } } set f [label $frame.c$count \ -highlightthickness 2 \ -highlightcolor white \ -relief flat -borderwidth 0 \ -width 16 -height 16 -image [Bitmap::get palette]] grid $f -column $col -row $row bind $f <1> "set SelectColor::_selection $count; break" bind $f {focus %W} pack $frame bind $top <1> {set SelectColor::_selection -1} bind $top {set SelectColor::_selection -2} bind $top [subst {if {"%W" == "$top"} \ {set SelectColor::_selection -2}}] eval [list BWidget::place $top 0 0] $placement wm deiconify $top raise $top if {$::tcl_platform(platform) == "unix"} { tkwait visibility $top update } BWidget::SetFocusGrab $top $frame.c0 vwait SelectColor::_selection BWidget::RestoreFocusGrab $top $frame.c0 destroy Widget::destroy $top if {$_selection == $count} { array set opts { -parent -parent -title -title -color -initialcolor } if {[Widget::theme]} { set native 1 set nativecmd [list tk_chooseColor -parent $parent] foreach {key val} $args { if {![info exists opts($key)]} { set native 0 break } lappend nativecmd $opts($key) $val } if {$native} { return [eval $nativecmd] } } return [eval [list dialog $path] $args] } else { return [lindex $colors $_selection] } } proc SelectColor::dialog {path args} { variable _baseColors variable _userColors variable _widget variable _selection variable _image variable _hsv Widget::init SelectColor $path:SelectColor $args set top [Dialog::create $path \ -title [Widget::cget $path:SelectColor -title] \ -parent [Widget::cget $path:SelectColor -parent] \ -separator 1 -default 0 -cancel 1 -anchor e] wm resizable $top 0 0 set dlgf [$top getframe] set fg [frame $dlgf.fg] set desc [list \ base _baseColors "Base colors" \ user _userColors "User colors"] set count 0 foreach {type varcol defTitle} $desc { set col 0 set lin 0 set title [lindex [BWidget::getname "${type}Colors"] 0] if {![string length $title]} { set title $defTitle } set titf [TitleFrame $fg.$type -text $title] set subf [$titf getframe] foreach color [set $varcol] { set fround [frame $fg.round$count \ -highlightthickness 1 \ -relief sunken -borderwidth 2] set fcolor [frame $fg.color$count -width 16 -height 12 \ -highlightthickness 0 \ -relief flat -borderwidth 0 \ -background $color] pack $fcolor -in $fround grid $fround -in $subf -row $lin -column $col -padx 1 -pady 1 bind $fround [list SelectColor::_select_rgb $count] bind $fcolor [list SelectColor::_select_rgb $count] bind $fround \ "SelectColor::_select_rgb [list $count]; [list $top] invoke 0" bind $fcolor \ "SelectColor::_select_rgb [list $count]; [list $top] invoke 0" incr count if {[incr col] == 6} { incr lin set col 0 } } pack $titf -anchor w -pady 2 } set fround [frame $fg.round \ -highlightthickness 0 \ -relief sunken -borderwidth 2] set fcolor [frame $fg.color \ -width 50 \ -highlightthickness 0 \ -relief flat -borderwidth 0] pack $fcolor -in $fround -fill y -expand yes pack $fround -anchor e -pady 2 -fill y -expand yes set fd [frame $dlgf.fd] set f1 [frame $fd.f1 -relief sunken -borderwidth 2] set f2 [frame $fd.f2 -relief sunken -borderwidth 2] set c1 [canvas $f1.c -width 200 -height 200 -bd 0 -highlightthickness 0] set c2 [canvas $f2.c -width 15 -height 200 -bd 0 -highlightthickness 0] for {set val 0} {$val < 40} {incr val} { $c2 create rectangle 0 [expr {5*$val}] 15 [expr {5*$val+5}] -tags val[expr {39-$val}] } $c2 create polygon 0 0 10 5 0 10 -fill black -outline white -tags target pack $c1 $c2 pack $f1 $f2 -side left -padx 10 -anchor n pack $fg $fd -side left -anchor n -fill y bind $c1 [list SelectColor::_select_hue_sat %x %y] bind $c1 [list SelectColor::_select_hue_sat %x %y] bind $c2 [list SelectColor::_select_value %x %y] bind $c2 [list SelectColor::_select_value %x %y] if {![info exists _image] || [catch {image type $_image}]} { set _image [image create photo -width 200 -height 200] for {set x 0} {$x < 200} {incr x 4} { for {set y 0} {$y < 200} {incr y 4} { $_image put \ [eval [list format "\#%04x%04x%04x"] \ [hsvToRgb [expr {$x/196.0}] [expr {(196-$y)/196.0}] 0.85]] \ -to $x $y [expr {$x+4}] [expr {$y+4}] } } } $c1 create image 0 0 -anchor nw -image $_image $c1 create bitmap 0 0 \ -bitmap @[file join $::BWIDGET::LIBRARY "images" "target.xbm"] \ -anchor nw -tags target set _selection -1 set _widget(fcolor) $fg set _widget(chs) $c1 set _widget(cv) $c2 set rgb [winfo rgb $path [Widget::cget $path:SelectColor -color]] set _hsv [eval rgbToHsv $rgb] _set_rgb [eval [list format "\#%04x%04x%04x"] $rgb] _set_hue_sat [lindex $_hsv 0] [lindex $_hsv 1] _set_value [lindex $_hsv 2] $top add -name ok $top add -name cancel set res [$top draw] if {$res == 0} { set color [$fg.color cget -background] } else { set color "" } destroy $top return $color } proc SelectColor::setcolor { idx color } { variable _userColors set _userColors [lreplace $_userColors $idx $idx $color] } proc SelectColor::_select_rgb {count} { variable _baseColors variable _userColors variable _selection variable _widget variable _hsv set frame $_widget(fcolor) if {$_selection >= 0} { $frame.round$_selection configure \ -relief sunken -highlightthickness 1 -borderwidth 2 } $frame.round$count configure \ -relief flat -highlightthickness 2 -borderwidth 1 focus $frame.round$count set _selection $count set bg [$frame.color$count cget -background] set user [expr {$_selection-[llength $_baseColors]}] if {$user >= 0 && [string equal \ [winfo rgb $frame.color$_selection $bg] \ [winfo rgb $frame.color$_selection white]]} { set bg [$frame.color cget -bg] $frame.color$_selection configure -background $bg set _userColors [lreplace $_userColors $user $user $bg] } else { set _hsv [eval rgbToHsv [winfo rgb $frame.color$count $bg]] _set_hue_sat [lindex $_hsv 0] [lindex $_hsv 1] _set_value [lindex $_hsv 2] $frame.color configure -background $bg } } proc SelectColor::_set_rgb {rgb} { variable _selection variable _baseColors variable _userColors variable _widget set frame $_widget(fcolor) $frame.color configure -background $rgb set user [expr {$_selection-[llength $_baseColors]}] if {$user >= 0} { $frame.color$_selection configure -background $rgb set _userColors [lreplace $_userColors $user $user $rgb] } } proc SelectColor::_select_hue_sat {x y} { variable _widget variable _hsv if {$x < 0} { set x 0 } elseif {$x > 200} { set x 200 } if {$y < 0 } { set y 0 } elseif {$y > 200} { set y 200 } set hue [expr {$x/200.0}] set sat [expr {(200-$y)/200.0}] set _hsv [lreplace $_hsv 0 1 $hue $sat] $_widget(chs) coords target [expr {$x-9}] [expr {$y-9}] _draw_values $hue $sat _set_rgb [eval [list format "\#%04x%04x%04x"] [eval [list hsvToRgb] $_hsv]] } proc SelectColor::_set_hue_sat {hue sat} { variable _widget set x [expr {$hue*200-9}] set y [expr {(1-$sat)*200-9}] $_widget(chs) coords target $x $y _draw_values $hue $sat } proc SelectColor::_select_value {x y} { variable _widget variable _hsv if {$y < 0} { set y 0 } elseif {$y > 200} { set y 200 } $_widget(cv) coords target 0 [expr {$y-5}] 10 $y 0 [expr {$y+5}] set _hsv [lreplace $_hsv 2 2 [expr {(200-$y)/200.0}]] _set_rgb [eval [list format "\#%04x%04x%04x"] [eval [list hsvToRgb] $_hsv]] } proc SelectColor::_draw_values {hue sat} { variable _widget for {set val 0} {$val < 40} {incr val} { set l [hsvToRgb $hue $sat [expr {$val/39.0}]] set col [eval [list format "\#%04x%04x%04x"] $l] $_widget(cv) itemconfigure val$val -fill $col -outline $col } } proc SelectColor::_set_value {value} { variable _widget set y [expr {int((1-$value)*200)}] $_widget(cv) coords target 0 [expr {$y-5}] 10 $y 0 [expr {$y+5}] } # -- # Taken from tk8.0/demos/tcolor.tcl # -- # The procedure below converts an HSB value to RGB. It takes hue, saturation, # and value components (floating-point, 0-1.0) as arguments, and returns a # list containing RGB components (integers, 0-65535) as result. The code # here is a copy of the code on page 616 of "Fundamentals of Interactive # Computer Graphics" by Foley and Van Dam. proc SelectColor::hsvToRgb {hue sat val} { set v [expr {round(65535.0*$val)}] if {$sat == 0} { return [list $v $v $v] } else { set hue [expr {$hue*6.0}] if {$hue >= 6.0} { set hue 0.0 } set i [expr {int($hue)}] set f [expr {$hue-$i}] set p [expr {round(65535.0*$val*(1 - $sat))}] set q [expr {round(65535.0*$val*(1 - ($sat*$f)))}] set t [expr {round(65535.0*$val*(1 - ($sat*(1 - $f))))}] switch $i { 0 {return [list $v $t $p]} 1 {return [list $q $v $p]} 2 {return [list $p $v $t]} 3 {return [list $p $q $v]} 4 {return [list $t $p $v]} 5 {return [list $v $p $q]} } } } # -- # Taken from tk8.0/demos/tcolor.tcl # -- # The procedure below converts an RGB value to HSB. It takes red, green, # and blue components (0-65535) as arguments, and returns a list containing # HSB components (floating-point, 0-1) as result. The code here is a copy # of the code on page 615 of "Fundamentals of Interactive Computer Graphics" # by Foley and Van Dam. proc SelectColor::rgbToHsv {red green blue} { if {$red > $green} { set max $red.0 set min $green.0 } else { set max $green.0 set min $red.0 } if {$blue > $max} { set max $blue.0 } else { if {$blue < $min} { set min $blue.0 } } set range [expr {$max-$min}] if {$max == 0} { set sat 0 } else { set sat [expr {($max-$min)/$max}] } if {$sat == 0} { set hue 0 } else { set rc [expr {($max - $red)/$range}] set gc [expr {($max - $green)/$range}] set bc [expr {($max - $blue)/$range}] if {$red == $max} { set hue [expr {.166667*($bc - $gc)}] } else { if {$green == $max} { set hue [expr {.166667*(2 + $rc - $bc)}] } else { set hue [expr {.166667*(4 + $gc - $rc)}] } } if {$hue < 0.0} { set hue [expr {$hue + 1.0}] } } return [list $hue $sat [expr {$max/65535}]] } amsn-0.98.9/utils/BWidget-1.9.0/bitmap.tcl0000644000175000017500000000514710516120770017507 0ustar billiobbilliob# ------------------------------------------------------------------------------ # bitmap.tcl # This file is part of Unifix BWidget Toolkit # $Id: bitmap.tcl,v 1.4 2003/10/20 21:23:52 damonc Exp $ # ------------------------------------------------------------------------------ # Index of commands: # - Bitmap::get # - Bitmap::_init # ---------------------------------------------------------------------------- namespace eval Bitmap { Widget::define Bitmap bitmap -classonly variable path variable _bmp variable _types { photo .gif photo .ppm bitmap .xbm photo .xpm } proc use {} {} } # ---------------------------------------------------------------------------- # Command Bitmap::get # ---------------------------------------------------------------------------- proc Bitmap::get { name } { variable path variable _bmp variable _types if {[info exists _bmp($name)]} { return $_bmp($name) } # --- Nom de fichier avec extension --------------------------------- set ext [file extension $name] if { $ext != "" } { if { ![info exists _bmp($ext)] } { error "$ext not supported" } if { [file exists $name] } { if {[string equal $ext ".xpm"]} { set _bmp($name) [xpm-to-image $name] return $_bmp($name) } if {![catch {set _bmp($name) [image create $_bmp($ext) -file $name]}]} { return $_bmp($name) } } } foreach dir $path { foreach {type ext} $_types { if { [file exists [file join $dir $name$ext]] } { if {[string equal $ext ".xpm"]} { set _bmp($name) [xpm-to-image [file join $dir $name$ext]] return $_bmp($name) } else { if {![catch {set _bmp($name) [image create $type -file [file join $dir $name$ext]]}]} { return $_bmp($name) } } } } } return -code error "$name not found" } # ---------------------------------------------------------------------------- # Command Bitmap::_init # ---------------------------------------------------------------------------- proc Bitmap::_init { } { global env variable path variable _bmp variable _types set path [list "." [file join $::BWIDGET::LIBRARY images]] set supp [image types] foreach {type ext} $_types { if { [lsearch $supp $type] != -1} { set _bmp($ext) $type } } } Bitmap::_init amsn-0.98.9/utils/BWidget-1.9.0/messagedlg.tcl0000644000175000017500000001070210516120770020337 0ustar billiobbilliob# ------------------------------------------------------------------------------ # messagedlg.tcl # This file is part of Unifix BWidget Toolkit # ------------------------------------------------------------------------------ # Index of commands: # - MessageDlg::create # ------------------------------------------------------------------------------ namespace eval MessageDlg { Widget::define MessageDlg messagedlg Dialog Widget::tkinclude MessageDlg message .frame.msg \ remove [list -cursor -highlightthickness \ -highlightbackground -highlightcolor \ -relief -borderwidth -takefocus -textvariable \ ] \ rename [list -text -message] \ initialize [list -aspect 800 -anchor c -justify center] Widget::bwinclude MessageDlg Dialog :cmd \ remove [list -modal -image -bitmap -side -anchor -separator \ -homogeneous -padx -pady -spacing] Widget::declare MessageDlg { {-icon Enum info 0 {none error info question warning}} {-type Enum user 0 {abortretryignore ok okcancel \ retrycancel yesno yesnocancel user}} {-buttons String "" 0} {-buttonwidth String 0 0} } Widget::addmap MessageDlg "" tkMBox { -parent {} -message {} -default {} -title {} } } # ------------------------------------------------------------------------------ # Command MessageDlg::create # ------------------------------------------------------------------------------ proc MessageDlg::create { path args } { global tcl_platform array set maps [list MessageDlg {} :cmd {} .frame.msg {} tkMBox {}] array set maps [Widget::parseArgs MessageDlg $args] Widget::initFromODB MessageDlg "$path#Message" $maps(MessageDlg) array set dialogArgs $maps(:cmd) set type [Widget::cget "$path#Message" -type] set icon [Widget::cget "$path#Message" -icon] set width [Widget::cget "$path#Message" -buttonwidth] set defb -1 set canb -1 switch -- $type { abortretryignore {set lbut {abort retry ignore}; set defb 0} ok {set lbut {ok}; set defb 0 } okcancel {set lbut {ok cancel}; set defb 0; set canb 1} retrycancel {set lbut {retry cancel}; set defb 0; set canb 1} yesno {set lbut {yes no}; set defb 0; set canb 1} yesnocancel {set lbut {yes no cancel}; set defb 0; set canb 2} user {set lbut [Widget::cget "$path#Message" -buttons]} } # If the user didn't specify a default button, use our type-specific # default, adding its flag/value to the "user" settings and to the tkMBox # settings if { ![info exists dialogArgs(-default)] } { lappend maps(:cmd) -default $defb lappend maps(tkMBox) -default $defb } if { ![info exists dialogArgs(-cancel)] } { lappend maps(:cmd) -cancel $canb } # Same with title as with default if { ![info exists dialogArgs(-title)] } { set frame [frame $path -class MessageDlg] set title [option get $frame "${icon}Title" MessageDlg] destroy $frame if { $title == "" } { set title "Message" } lappend maps(:cmd) -title $title lappend maps(tkMBox) -title $title } # Create the "user" type dialog if { $type == "user" } { if { $icon != "none" } { set image [Bitmap::get $icon] } else { set image "" } eval [list Dialog::create $path] $maps(:cmd) \ [list -image $image -modal local -side bottom -anchor e] foreach but $lbut { Dialog::add $path -text $but -name $but -width $width } set frame [Dialog::getframe $path] eval [list message $frame.msg] $maps(.frame.msg) \ [list -relief flat -borderwidth 0 -highlightthickness 0 \ -textvariable ""] pack $frame.msg -side left -padx 3m -pady 1m -fill x -expand yes set res [Dialog::draw $path] destroy $path } else { # Do some translation of args into tk_messageBox syntax, then create # the tk_messageBox array set tkMBoxArgs $maps(tkMBox) set tkMBoxArgs(-default) [lindex $lbut $tkMBoxArgs(-default)] if { ![string equal $icon "none"] } { set tkMBoxArgs(-icon) $icon } if {[info exists tkMBoxArgs(-parent)] && ![winfo exists $tkMBoxArgs(-parent)]} { unset tkMBoxArgs(-parent) } set tkMBoxArgs(-type) $type set res [eval [list tk_messageBox] [array get tkMBoxArgs]] set res [lsearch $lbut $res] } Widget::destroy "$path#Message" return $res } amsn-0.98.9/utils/BWidget-1.9.0/combobox.tcl0000644000175000017500000006713511234370133020046 0ustar billiobbilliob# ---------------------------------------------------------------------------- # combobox.tcl # This file is part of Unifix BWidget Toolkit # $Id: combobox.tcl,v 1.42 2009/07/07 17:28:14 oehhar Exp $ # ---------------------------------------------------------------------------- # Index of commands: # - ComboBox::create # - ComboBox::configure # - ComboBox::cget # - ComboBox::setvalue # - ComboBox::getvalue # - ComboBox::clearvalue # - ComboBox::_create_popup # - ComboBox::_mapliste # - ComboBox::_unmapliste # - ComboBox::_select # - ComboBox::_modify_value # ---------------------------------------------------------------------------- # ComboBox uses the 8.3 -listvariable listbox option package require Tk 8.3 namespace eval ComboBox { Widget::define ComboBox combobox ArrowButton Entry ListBox Widget::tkinclude ComboBox frame :cmd \ include {-relief -borderwidth -bd -background} \ initialize {-relief sunken -borderwidth 2} Widget::bwinclude ComboBox Entry .e \ remove {-relief -bd -borderwidth -bg} \ rename {-background -entrybg} Widget::declare ComboBox { {-height TkResource 0 0 listbox} {-values String "" 0} {-images String "" 0} {-indents String "" 0} {-modifycmd String "" 0} {-postcommand String "" 0} {-expand Enum none 0 {none tab}} {-autocomplete Boolean 0 0} {-autopost Boolean 0 0} {-bwlistbox Boolean 0 0} {-listboxwidth Int 0 0} {-hottrack Boolean 0 0} } Widget::addmap ComboBox ArrowButton .a { -background {} -foreground {} -disabledforeground {} -state {} } Widget::syncoptions ComboBox Entry .e {-text {}} ::bind BwComboBox [list after idle {BWidget::refocus %W %W.e}] ::bind BwComboBox [list ComboBox::_destroy %W] ::bind ListBoxHotTrack { %W selection clear 0 end %W activate @%x,%y %W selection set @%x,%y } variable _index } # ComboBox::create -- # # Create a combobox widget with the given options. # # Arguments: # path name of the new widget. # args optional arguments to the widget. # # Results: # path name of the new widget. proc ComboBox::create { path args } { array set maps [list ComboBox {} :cmd {} .e {} .a {}] array set maps [Widget::parseArgs ComboBox $args] eval [list frame $path] $maps(:cmd) \ [list -highlightthickness 0 -takefocus 0 -class ComboBox] Widget::initFromODB ComboBox $path $maps(ComboBox) bindtags $path [list $path BwComboBox [winfo toplevel $path] all] set entry [eval [list Entry::create $path.e] $maps(.e) \ [list -relief flat -borderwidth 0 -takefocus 1]] ::bind $path.e [list $path _focus_out] ::bind $path <> [list $path _traverse_in] if {[Widget::cget $path -autocomplete]} { ::bind $path.e [list $path _auto_complete %K] } if {[Widget::cget $path -autopost]} { ::bind $path.e +[list $path _auto_post %K] } else { ::bind $entry [list ComboBox::_unmapliste $path] ::bind $entry [list ComboBox::_mapliste $path] } if {[string equal [tk windowingsystem] "x11"]} { set ipadx 0 set width 11 } else { set ipadx 2 set width 15 } set height [winfo reqheight $entry] set arrow [eval [list ArrowButton::create $path.a] $maps(.a) \ [list -width $width -height $height \ -highlightthickness 0 -borderwidth 1 -takefocus 0 \ -dir bottom -type button -ipadx $ipadx \ -command [list ComboBox::_mapliste $path] \ ]] pack $arrow -side right -fill y pack $entry -side left -fill both -expand yes set editable [Widget::cget $path -editable] Entry::configure $path.e -editable $editable if {$editable} { ::bind $entry [list ComboBox::_unmapliste $path] } else { ::bind $entry [list ArrowButton::invoke $path.a] if { ![string equal [Widget::cget $path -state] "disabled"] } { Entry::configure $path.e -takefocus 1 } } ::bind $path [list ComboBox::_unmapliste $path] ::bind $entry [list ComboBox::_modify_value $path previous] ::bind $entry [list ComboBox::_modify_value $path next] ::bind $entry [list ComboBox::_modify_value $path first] ::bind $entry [list ComboBox::_modify_value $path last] if {$editable} { set expand [Widget::cget $path -expand] if {[string equal "tab" $expand]} { # Expand entry value on Tab (from -values) ::bind $entry "[list ComboBox::_expand $path]; break" } elseif {[string equal "auto" $expand]} { # Expand entry value anytime (from -values) #::bind $entry "[list ComboBox::_expand $path]; break" } } ## If we have images, we have to use a BWidget ListBox. set bw [Widget::cget $path -bwlistbox] if {[llength [Widget::cget $path -images]]} { Widget::configure $path [list -bwlistbox 1] } else { Widget::configure $path [list -bwlistbox $bw] } set ComboBox::_index($path) -1 return [Widget::create ComboBox $path] } # ComboBox::configure -- # # Configure subcommand for ComboBox widgets. Works like regular # widget configure command. # # Arguments: # path Name of the ComboBox widget. # args Additional optional arguments: # ?-option? # ?-option value ...? # # Results: # Depends on arguments. If no arguments are given, returns a complete # list of configuration information. If one argument is given, returns # the configuration information for that option. If more than one # argument is given, returns nothing. proc ComboBox::configure { path args } { set res [Widget::configure $path $args] set entry $path.e set list [list -images -values -bwlistbox -hottrack -autocomplete -autopost] foreach {ci cv cb ch cac cap} [eval [linsert $list 0 Widget::hasChangedX $path]] { break } if { $ci } { set images [Widget::cget $path -images] if {[llength $images]} { Widget::configure $path [list -bwlistbox 1] } else { Widget::configure $path [list -bwlistbox 0] } } ## If autocomplete toggled, turn bindings on/off if { $cac } { if {[Widget::cget $path -autocomplete]} { ::bind $entry +[list $path _auto_complete %K] } else { set bindings [split [::bind $entry ] \n] if {[set idx [lsearch $bindings [list $path _auto_complete %K]]] != -1} { ::bind $entry [join [lreplace $bindings $idx $idx] \n] } } } ## If autopost toggled, turn bindings on/off if { $cap } { if {[Widget::cget $path -autopost]} { ::bind $entry +[list $path _auto_post %K] set bindings [split [::bind $entry ] \n] if {[set idx [lsearch $bindings [list ComboBox::_unmapliste $path]]] != -1} { ::bind $entry [join [lreplace $bindings $idx $idx] \n] } set bindings [split [::bind $entry ] \n] if {[set idx [lsearch $bindings [list ComboBox::_mapliste $path]]] != -1} { ::bind $entry [join [lreplace $bindings $idx $idx] \n] } } else { set bindings [split [::bind $entry ] \n] if {[set idx [lsearch $bindings [list $path _auto_post %K]]] != -1} { ::bind $entry [join [lreplace $bindings $idx $idx] \n] } ::bind $entry +[list ComboBox::_unmapliste $path] ::bind $entry +[list ComboBox::_mapliste $path] } } set bw [Widget::cget $path -bwlistbox] ## If the images, bwlistbox, hottrack or values have changed, ## destroy the shell so that it will re-create itself the next ## time around. if { $ci || $cb || $ch || ($bw && $cv) } { destroy $path.shell } set chgedit [Widget::hasChangedX $path -editable] if {$chgedit} { if {[Widget::cget $path -editable]} { ::bind $entry [list ComboBox::_unmapliste $path] Entry::configure $entry -editable true } else { ::bind $entry [list ArrowButton::invoke $path.a] Entry::configure $entry -editable false # Make sure that non-editable comboboxes can still be tabbed to. if { ![string equal [Widget::cget $path -state] "disabled"] } { Entry::configure $entry -takefocus 1 } } } if {$chgedit || [Widget::hasChangedX $path -expand]} { # Unset what we may have created. ::bind $entry {} if {[Widget::cget $path -editable]} { set expand [Widget::cget $path -expand] if {[string equal "tab" $expand]} { # Expand entry value on Tab (from -values) ::bind $entry "[list ComboBox::_expand $path]; break" } elseif {[string equal "auto" $expand]} { # Expand entry value anytime (from -values) #::bind $entry "[list ComboBox::_expand $path]; break" } } } # if state changed to normal and -editable false, the edit must take focus if { [Widget::hasChangedX $path -state] \ && ![string equal [Widget::cget $path -state] "disabled"] \ && ![Widget::cget $path -editable] } { Entry::configure $entry -takefocus 1 } # if the dropdown listbox is shown, simply force the actual entry # colors into it. If it is not shown, the next time the dropdown # is shown it'll get the actual colors anyway if {[winfo exists $path.shell.listb]} { $path.shell.listb configure \ -bg [Widget::cget $path -entrybg] \ -fg [Widget::cget $path -foreground] \ -selectbackground [Widget::cget $path -selectbackground] \ -selectforeground [Widget::cget $path -selectforeground] } return $res } # ---------------------------------------------------------------------------- # Command ComboBox::cget # ---------------------------------------------------------------------------- proc ComboBox::cget { path option } { return [Widget::cget $path $option] } # ---------------------------------------------------------------------------- # Command ComboBox::setvalue # ---------------------------------------------------------------------------- proc ComboBox::setvalue { path index } { variable _index set values [Widget::getMegawidgetOption $path -values] set value [Entry::cget $path.e -text] switch -- $index { next { if { [set idx [lsearch -exact $values $value]] != -1 } { incr idx } else { set idx [lsearch -exact $values "$value*"] } } previous { if { [set idx [lsearch -exact $values $value]] != -1 } { incr idx -1 } else { set idx [lsearch -exact $values "$value*"] } } first { set idx 0 } last { set idx [expr {[llength $values]-1}] } default { if { [string index $index 0] == "@" } { set idx [string range $index 1 end] if { ![string is integer -strict $idx] } { return -code error "bad index \"$index\"" } } else { return -code error "bad index \"$index\"" } } } if { $idx >= 0 && $idx < [llength $values] } { set newval [lindex $values $idx] set _index($path) $idx Entry::configure $path.e -text $newval return 1 } return 0 } proc ComboBox::icursor { path idx } { return [$path.e icursor $idx] } proc ComboBox::get { path } { return [$path.e get] } # ---------------------------------------------------------------------------- # Command ComboBox::getvalue # ---------------------------------------------------------------------------- proc ComboBox::getvalue { path } { variable _index set values [Widget::getMegawidgetOption $path -values] set value [Entry::cget $path.e -text] # Check if an index was saved by the last setvalue operation # If this index still matches it is returned # This is necessary for the case when values is not unique if { $_index($path) >= 0 \ && $_index($path) < [llength $values] \ && $value eq [lindex $values $_index($path)]} { return $_index($path) } return [lsearch -exact $values $value] } proc ComboBox::getlistbox { path } { _create_popup $path return $path.shell.listb } # ---------------------------------------------------------------------------- # Command ComboBox::post # ---------------------------------------------------------------------------- proc ComboBox::post { path } { _mapliste $path return } proc ComboBox::unpost { path } { _unmapliste $path return } # ---------------------------------------------------------------------------- # Command ComboBox::bind # ---------------------------------------------------------------------------- proc ComboBox::bind { path args } { return [eval [list ::bind $path.e] $args] } proc ComboBox::insert { path idx args } { upvar #0 [Widget::varForOption $path -values] values if {[Widget::cget $path -bwlistbox]} { set l [$path getlistbox] set i [eval [linsert $args 0 $l insert $idx #auto]] set text [$l itemcget $i -text] if {$idx == "end"} { lappend values $text } else { set values [linsert $values $idx $text] } } else { set values [eval [list linsert $values $idx] $args] } } # ---------------------------------------------------------------------------- # Command ComboBox::clearvalue # ---------------------------------------------------------------------------- proc ComboBox::clearvalue { path } { Entry::configure $path.e -text "" } # ---------------------------------------------------------------------------- # Command ComboBox::_create_popup # ---------------------------------------------------------------------------- proc ComboBox::_create_popup { path } { set shell $path.shell if {[winfo exists $shell]} { return } set lval [Widget::cget $path -values] set h [Widget::cget $path -height] set bw [Widget::cget $path -bwlistbox] if { $h <= 0 } { set len [llength $lval] if { $len < 3 } { set h 3 } elseif { $len > 10 } { set h 10 } else { set h $len } } if {[string equal [tk windowingsystem] "x11"]} { set sbwidth 11 } else { set sbwidth 15 } toplevel $shell -relief solid -bd 1 wm withdraw $shell wm overrideredirect $shell 1 # these commands cause the combobox to behave strangely on OS X if {![string equal [tk windowingsystem] "aqua"]} { update idle wm transient $shell [winfo toplevel $path] catch { wm attributes $shell -topmost 1 } } set sw [ScrolledWindow $shell.sw -managed 1 -size $sbwidth -ipad 0] if {$bw} { set listb [ListBox $shell.listb \ -relief flat -borderwidth 0 -highlightthickness 0 \ -selectmode single -selectfill 1 -autofocus 0 -height $h \ -font [Widget::cget $path -font] \ -bg [Widget::cget $path -entrybg] \ -fg [Widget::cget $path -foreground] \ -selectbackground [Widget::cget $path -selectbackground] \ -selectforeground [Widget::cget $path -selectforeground]] set values [Widget::cget $path -values] set images [Widget::cget $path -images] foreach value $values image $images { $listb insert end #auto -text $value -image $image } $listb bindText <1> [list ComboBox::_select $path] $listb bindImage <1> [list ComboBox::_select $path] if {[Widget::cget $path -hottrack]} { $listb bindText [list $listb selection set] $listb bindImage [list $listb selection set] } } else { set listb [listbox $shell.listb \ -relief flat -borderwidth 0 -highlightthickness 0 \ -exportselection false \ -font [Widget::cget $path -font] \ -height $h \ -bg [Widget::cget $path -entrybg] \ -fg [Widget::cget $path -foreground] \ -selectbackground [Widget::cget $path -selectbackground] \ -selectforeground [Widget::cget $path -selectforeground] \ -listvariable [Widget::varForOption $path -values]] ::bind $listb [list ComboBox::_select $path @%x,%y] if {[Widget::cget $path -hottrack]} { bindtags $listb [concat [bindtags $listb] ListBoxHotTrack] } } pack $sw -fill both -expand yes $sw setwidget $listb ::bind $listb "ComboBox::_select [list $path] \[$listb curselection\]" ::bind $listb [list ComboBox::_unmapliste $path] ::bind $listb [list ComboBox::_focus_out $path] } proc ComboBox::_recreate_popup { path } { variable background variable foreground set shell $path.shell set lval [Widget::cget $path -values] set h [Widget::cget $path -height] set bw [Widget::cget $path -bwlistbox] if { $h <= 0 } { set len [llength $lval] if { $len < 3 } { set h 3 } elseif { $len > 10 } { set h 10 } else { set h $len } } if { [string equal [tk windowingsystem] "x11"] } { set sbwidth 11 } else { set sbwidth 15 } _create_popup $path if {![Widget::cget $path -editable]} { if {[info exists background]} { $path.e configure -bg $background $path.e configure -fg $foreground unset background unset foreground } } set listb $shell.listb destroy $shell.sw set sw [ScrolledWindow $shell.sw -managed 1 -size $sbwidth -ipad 0] $listb configure \ -height $h \ -font [Widget::cget $path -font] \ -bg [Widget::cget $path -entrybg] \ -fg [Widget::cget $path -foreground] \ -selectbackground [Widget::cget $path -selectbackground] \ -selectforeground [Widget::cget $path -selectforeground] pack $sw -fill both -expand yes $sw setwidget $listb raise $listb } # ---------------------------------------------------------------------------- # Command ComboBox::_mapliste # ---------------------------------------------------------------------------- proc ComboBox::_mapliste { path } { set listb $path.shell.listb if {[winfo exists $path.shell] && [string equal [wm state $path.shell] "normal"]} { _unmapliste $path return } if { [Widget::cget $path -state] == "disabled" } { return } if {[llength [set cmd [Widget::getMegawidgetOption $path -postcommand]]]} { uplevel \#0 $cmd } if { ![llength [Widget::getMegawidgetOption $path -values]] } { return } _recreate_popup $path ArrowButton::configure $path.a -relief sunken update set bw [Widget::cget $path -bwlistbox] $listb selection clear 0 end set values [Widget::getMegawidgetOption $path -values] set curval [Entry::cget $path.e -text] if { [set idx [lsearch -exact $values $curval]] != -1 || [set idx [lsearch -exact $values "$curval*"]] != -1 } { if {$bw} { set idx [$listb items $idx] } else { $listb activate $idx } $listb selection set $idx $listb see $idx } else { set idx 0 if {$bw} { set idx [$listb items 0] } else { $listb activate $idx } $listb selection set $idx $listb see $idx } set width [Widget::cget $path -listboxwidth] if {!$width} { set width [winfo width $path] } BWidget::place $path.shell $width 0 below $path wm deiconify $path.shell raise $path.shell BWidget::focus set $listb if { ! [string equal [tk windowingsystem] "aqua"] } { BWidget::grab global $path } } # ---------------------------------------------------------------------------- # Command ComboBox::_unmapliste # ---------------------------------------------------------------------------- proc ComboBox::_unmapliste { path {refocus 1} } { # On aqua, state is zoomed, otherwise normal if {[winfo exists $path.shell] && \ ( [string equal [wm state $path.shell] "normal"] || [string equal [wm state $path.shell] "zoomed"] ) } { if {![string equal [tk windowingsystem] "aqua"]} { BWidget::grab release $path BWidget::focus release $path.shell.listb $refocus # Update now because otherwise [focus -force...] makes the app hang! if {$refocus} { update focus -force $path.e } } wm withdraw $path.shell ArrowButton::configure $path.a -relief raised } } # ---------------------------------------------------------------------------- # Command ComboBox::_select # ---------------------------------------------------------------------------- proc ComboBox::_select { path index } { set index [$path.shell.listb index $index] _unmapliste $path if { $index != -1 } { if { [setvalue $path @$index] } { set cmd [Widget::getMegawidgetOption $path -modifycmd] if {[llength $cmd]} { uplevel \#0 $cmd } } } $path.e selection clear if {[$path.e cget -exportselection]} { $path.e selection range 0 end } } # ---------------------------------------------------------------------------- # Command ComboBox::_modify_value # ---------------------------------------------------------------------------- proc ComboBox::_modify_value { path direction } { if {[setvalue $path $direction] && [llength [set cmd [Widget::getMegawidgetOption $path -modifycmd]]]} { uplevel \#0 $cmd } } # ---------------------------------------------------------------------------- # Command ComboBox::_expand # ---------------------------------------------------------------------------- proc ComboBox::_expand {path} { set values [Widget::getMegawidgetOption $path -values] if {![llength $values]} { bell return 0 } set found {} set curval [Entry::cget $path.e -text] set curlen [$path.e index insert] if {$curlen < [string length $curval]} { # we are somewhere in the middle of a string. # if the full value matches some string in the listbox, # reorder values to start matching after that string. set idx [lsearch -exact $values $curval] if {$idx >= 0} { set values [concat [lrange $values [expr {$idx+1}] end] \ [lrange $values 0 $idx]] } } if {$curlen == 0} { set found $values } else { foreach val $values { if {[string equal -length $curlen $curval $val]} { lappend found $val } } } if {[llength $found]} { Entry::configure $path.e -text [lindex $found 0] if {[llength $found] > 1} { set best [_best_match $found [string range $curval 0 $curlen]] set blen [string length $best] $path.e icursor $blen $path.e selection range $blen end } } else { bell } return [llength $found] } # best_match -- # finds the best unique match in a list of names # The extra $e in this argument allows us to limit the innermost loop a # little further. # Arguments: # l list to find best unique match in # e currently best known unique match # Returns: # longest unique match in the list # proc ComboBox::_best_match {l {e {}}} { set ec [lindex $l 0] if {[llength $l]>1} { set e [string length $e]; incr e -1 set ei [string length $ec]; incr ei -1 foreach l $l { while {$ei>=$e && [string first $ec $l]} { set ec [string range $ec 0 [incr ei -1]] } } } return $ec } # possibly faster #proc match {string1 string2} { # set i 1 # while {[string equal -length $i $string1 $string2]} { incr i } # return [string range $string1 0 [expr {$i-2}]] #} #proc matchlist {list} { # set list [lsort $list] # return [match [lindex $list 0] [lindex $list end]] #} # ---------------------------------------------------------------------------- # Command ComboBox::_traverse_in # Called when widget receives keyboard focus due to keyboard traversal. # ---------------------------------------------------------------------------- proc ComboBox::_traverse_in { path } { if {[$path.e selection present] != 1} { # Autohighlight the selection, but not if one existed $path.e selection range 0 end } } # ---------------------------------------------------------------------------- # Command ComboBox::_focus_out # ---------------------------------------------------------------------------- proc ComboBox::_focus_out { path } { if {[string first $path [focus]] != 0} { # we lost focus to some other app or window, so remove the listbox return [_unmapliste $path 0] } } proc ComboBox::_auto_complete { path key } { ## Any key string with more than one character and is not entirely ## lower-case is considered a function key and is thus ignored. if {[string length $key] > 1 && [string tolower $key] != $key} { return } set text [string map [list {[} {\[} {]} {\]}] [$path.e get]] if {[string equal $text ""]} { return } set values [Widget::cget $path -values] set x [lsearch $values $text*] if {$x < 0} { return } set idx [$path.e index insert] $path.e configure -text [lindex $values $x] $path.e icursor $idx $path.e select range insert end } proc ComboBox::_auto_post { path key } { if {[string equal $key "Escape"] || [string equal $key "Return"]} { _unmapliste $path return } if {[catch {$path.shell.listb curselection} x] || $x == ""} { if {[string equal $key "Up"]} { _unmapliste $path return } set x -1 } if {([string length $key] > 1 && [string tolower $key] != $key) && \ [string equal $key "BackSpace"] != 0 && \ [string equal $key "Up"] != 0 && \ [string equal $key "Down"] != 0} { return } # post the listbox _create_popup $path set width [Widget::cget $path -listboxwidth] if {!$width} { set width [winfo width $path] } BWidget::place $path.shell $width 0 below $path wm deiconify $path.shell BWidget::grab release $path BWidget::focus release $path.shell.listb 1 focus -force $path.e set values [Widget::cget $path -values] switch -- $key { Up { if {[incr x -1] < 0} { set x 0 } else { Entry::configure $path.e -text [lindex $values $x] } } Down { if {[incr x] >= [llength $values]} { set x [expr {[llength $values] - 1}] } else { Entry::configure $path.e -text [lindex $values $x] } } default { # auto-select within the listbox the item closest to the entry's value set text [string map [list {[} {\[} {]} {\]}] [$path.e get]] if {[string equal $text ""]} { set x 0 } else { set x [lsearch $values $text*] } } } if {$x >= 0} { $path.shell.listb selection clear 0 end $path.shell.listb selection set $x $path.shell.listb see $x } } # ------------------------------------------------------------------------------ # Command ComboBox::_destroy # ------------------------------------------------------------------------------ proc ComboBox::_destroy { path } { variable _index Widget::destroy $path unset _index($path) } amsn-0.98.9/utils/BWidget-1.9.0/statusbar.tcl0000644000175000017500000003154610516120770020245 0ustar billiobbilliob# ------------------------------------------------------------------------ # statusbar.tcl # Create a status bar Tk widget # # Provides a status bar to be placed at the bottom of a toplevel. # Currently does not support being placed in a toplevel that has # gridding applied (via widget -setgrid or wm grid). # # Ensure that the widget is placed at the very bottom of the toplevel, # otherwise the resize behavior may behave oddly. # ------------------------------------------------------------------------ package require Tk 8.3 if {0} { proc sample {} { # sample usage eval destroy [winfo children .] pack [text .t -width 0 -height 0] -fill both -expand 1 set sbar .s StatusBar $sbar pack $sbar -side bottom -fill x set f [$sbar getframe] # Specify -width 1 for the label widget so it truncates nicely # instead of requesting large sizes for long messages set w [label $f.status -width 1 -anchor w -textvariable ::STATUS] set ::STATUS "This is a status message" # give the entry weight, as we want it to be the one that expands $sbar add $w -weight 1 # BWidget's progressbar set w [ProgressBar $f.bpbar -orient horizontal \ -variable ::PROGRESS -bd 1 -relief sunken] set ::PROGRESS 50 $sbar add $w } } namespace eval StatusBar { Widget::define StatusBar statusbar Widget::declare StatusBar { {-background TkResource "" 0 frame} {-borderwidth TkResource 0 0 frame} {-relief TkResource flat 0 frame} {-showseparator Boolean 1 0} {-showresizesep Boolean 0 0} {-showresize Boolean 1 0} {-width TkResource 100 0 frame} {-height TkResource 18 0 frame} {-ipad String 1 0} {-pad String 0 0} {-bg Synonym -background} {-bd Synonym -borderwidth} } # -background, -borderwidth and -relief apply to outer frame, but relief # should be left flat for proper look Widget::addmap StatusBar "" :cmd { -background {} -width {} -height {} -borderwidth {} -relief {} } Widget::addmap StatusBar "" .sbar { -background {} } Widget::addmap StatusBar "" .resize { -background {} } Widget::addmap StatusBar "" .hsep { -background {} } # -pad provides general padding around the status bar # -ipad provides padding around each status bar item # Padding can be a list of {padx pady} variable HaveMarlett \ [expr {[lsearch -exact [font families] "Marlett"] != -1}] bind StatusResize <1> \ [namespace code [list begin_resize %W %X %Y]] bind StatusResize \ [namespace code [list continue_resize %W %X %Y]] bind StatusResize \ [namespace code [list end_resize %W %X %Y]] bind StatusBar [list StatusBar::_destroy %W] # PNG version has partial alpha transparency for better look variable pngdata { iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAFM0aXcAAAABGdBTUEAAYagM eiWXwAAAGJJREFUGJW9kVEOgCAMQzs8GEezN69fkKlbUAz2r3l5NGTA+pCU+Q IA5sv39wGgZKClZGBhJMVTklRr3VNwMz04mVfQzQiEm79EkrYZycxIkq8kkv2 v6RFGku9TUrj8RGr9AGy6mhv2ymLwAAAAAElFTkSuQmCC } variable gifdata { R0lGODlhDwAPAJEAANnZ2f///4CAgD8/PyH5BAEAAAAALAAAAAAPAA8AAAJEh I+py+1IQvh4IZlG0Qg+QshkAokGQfAvZCBIhG8hA0Ea4UPIQJBG+BAyEKQhCH bIQAgNEQCAIA0hAyE0AEIGgjSEDBQAOw== } if {[package provide img::png] != ""} { image create photo ::StatusBar::resizer -format PNG -data $pngdata } else { image create photo ::StatusBar::resizer -format GIF -data $gifdata } } # ------------------------------------------------------------------------ # Command StatusBar::create # ------------------------------------------------------------------------ proc StatusBar::create { path args } { variable _widget variable HaveMarlett # Allow for img::png loaded after initial source if {[package provide img::png] != ""} { variable pngdata ::StatusBar::resizer configure -format PNG -data $pngdata } Widget::init StatusBar $path $args eval [list frame $path -class StatusBar] [Widget::subcget $path :cmd] foreach {padx pady} [_padval [Widget::cget $path -pad]] \ {ipadx ipady} [_padval [Widget::cget $path -ipad]] { break } if {[Widget::theme]} { set sbar [ttk::frame $path.sbar -padding [list $padx $pady]] } else { set sbar [eval [list frame $path.sbar -padx $padx -pady $pady] \ [Widget::subcget $path .sbar]] } if {[string equal $::tcl_platform(platform) "windows"]} { set cursor size_nw_se } else { set cursor sizing; # bottom_right_corner ?? } set resize [eval [list label $path.resize] \ [Widget::subcget $path .resize] \ [list -borderwidth 0 -relief flat -anchor se \ -cursor $cursor -anchor se -padx 0 -pady 0]] if {$HaveMarlett} { $resize configure -font "Marlett -16" -text \u006f } else { $resize configure -image ::StatusBar::resizer } bindtags $resize [list all [winfo toplevel $path] StatusResize $resize] if {[Widget::theme]} { set fsep [ttk::separator $path.hsep -orient horizontal] } else { set fsep [eval [list frame $path.hsep -bd 1 -height 2 -relief sunken] \ [Widget::subcget $path .hsep]] } set sep [_sep $path sepresize {}] grid $fsep -row 0 -column 0 -columnspan 3 -sticky ew grid $sbar -row 1 -column 0 -sticky news grid $sep -row 1 -column 1 -sticky ns -padx $ipadx -pady $ipady grid $resize -row 1 -column 2 -sticky news grid columnconfigure $path 0 -weight 1 if {![Widget::cget $path -showseparator]} { grid remove $fsep } if {![Widget::cget $path -showresize]} { grid remove $sep $resize } elseif {![Widget::cget $path -showresizesep]} { grid remove $sep } set _widget($path,items) {} return [Widget::create StatusBar $path] } # ------------------------------------------------------------------------ # Command StatusBar::configure # ------------------------------------------------------------------------ proc StatusBar::configure { path args } { variable _widget set res [Widget::configure $path $args] foreach {chshow chshowrsep chshowsep chipad chpad} \ [Widget::hasChangedX $path -showresize -showresizesep -showseparator \ -ipad -pad] { break } if {$chshow} { set show [Widget::cget $path -showresize] set showrsep [Widget::cget $path -showresizesep] if {$show} { if {$showrsep} { grid $path.sepresize } grid $path.resize } else { grid remove $path.sepresize $path.resize } } if {$chshowsep} { if {$show} { grid $path.hsep } else { grid remove $path.hsep } } if {$chipad} { foreach {ipadx ipady} [_padval [Widget::cget $path -ipad]] { break } foreach w [grid slaves $path.sbar] { grid configure $w -padx $ipadx -pady $ipady } } if {$chpad} { foreach {padx pady} [_padval [Widget::cget $path -pad]] { break } if {[string equal [winfo class $path.sbar] "TFrame"]} { $path.sbar configure -padding [list $padx $pady] } else { $path.sbar configure -padx $padx -pady $pady } } return $res } # ------------------------------------------------------------------------ # Command StatusBar::cget # ------------------------------------------------------------------------ proc StatusBar::cget { path option } { return [Widget::cget $path $option] } # ------------------------------------------------------------------------ # Command StatusBar::getframe # ------------------------------------------------------------------------ proc StatusBar::getframe {path} { # This is the frame that users should place their statusbar widgets in return $path.sbar } # ------------------------------------------------------------------------ # Command StatusBar::add # ------------------------------------------------------------------------ proc StatusBar::add {path w args} { variable _widget array set opts [list \ -weight 0 \ -separator 1 \ -sticky news \ -pad [Widget::cget $path -ipad] \ ] foreach {key val} $args { if {[info exists opts($key)]} { set opts($key) $val } else { set msg "unknown option \"$key\", must be one of: " append msg [join [lsort [array names opts]] {, }] return -code error $msg } } foreach {ipadx ipady} [_padval $opts(-pad)] { break } set sbar $path.sbar foreach {cols rows} [grid size $sbar] break # Add separator if requested, and we aren't the first element if {$opts(-separator) && $cols != 0} { set sep [_sep $path sep[winfo name $w]] # only append name, to distinguish us from them lappend _widget($path,items) [winfo name $sep] grid $sep -in $sbar -row 0 -column $cols \ -sticky ns -padx $ipadx -pady $ipady incr cols } lappend _widget($path,items) $w grid $w -in $sbar -row 0 -column $cols -sticky $opts(-sticky) \ -padx $ipadx -pady $ipady grid columnconfigure $sbar $cols -weight $opts(-weight) return $w } # ------------------------------------------------------------------------ # Command StatusBar::delete # ------------------------------------------------------------------------ proc StatusBar::remove {path args} { variable _widget set destroy [string equal [lindex $args 0] "-destroy"] if {$destroy} { set args [lrange $args 1 end] } foreach w $args { set idx [lsearch -exact $_widget($path,items) $w] if {$idx == -1 || ![winfo exists $w]} { # ignore unknown or non-widget items (like our separators) continue } # separator is always previous item set sidx [expr {$idx - 1}] set sep [lindex $_widget($path,items) $sidx] if {[string match .* $sep]} { # not one of our separators incr sidx } elseif {$sep != ""} { # destroy separator too set sep $path.sbar.$sep destroy $sep } if {$destroy} { destroy $w } else { grid forget $w } if {$idx == 0} { # separator of next item is no longer necessary set sep [lindex $_widget($path,items) [expr {$idx + 1}]] if {$sep != "" && ![string match .* $sep]} { incr idx set sep $path.sbar.$sep destroy $sep } } set _widget($path,items) [lreplace $_widget($path,items) $sidx $idx] } } # ------------------------------------------------------------------------ # Command StatusBar::delete # ------------------------------------------------------------------------ proc StatusBar::delete {path args} { return [StatusBar::remove $path -destroy $args] } # ------------------------------------------------------------------------ # Command StatusBar::items # ------------------------------------------------------------------------ proc StatusBar::items {path} { variable _widget return $_widget($path,items) } proc StatusBar::_sep {path name {sub .sbar}} { if {[Widget::theme]} { return [ttk::separator $path$sub.$name -orient vertical] } else { return [frame $path$sub.$name -bd 1 -width 2 -relief sunken] } } proc StatusBar::_padval {padval} { set len [llength $padval] foreach {a b} $padval { break } if {$len == 0 || $len > 2} { return -code error \ "invalid pad value \"$padval\", must be 1 or 2 pixel values" } elseif {$len == 1} { return [list $a $a] } elseif {$len == 2} { return $padval } } # ------------------------------------------------------------------------ # Command StatusBar::_destroy # ------------------------------------------------------------------------ proc StatusBar::_destroy { path } { variable _widget variable resize array unset widget $path,* array unset resize $path.resize,* Widget::destroy $path } # The following proc handles the mouse click on the resize control. It stores # the original size of the window and the initial coords of the mouse relative # to the root. proc StatusBar::begin_resize {w rootx rooty} { variable resize set t [winfo toplevel $w] set relx [expr {$rootx - [winfo rootx $t]}] set rely [expr {$rooty - [winfo rooty $t]}] set resize($w,x) $relx set resize($w,y) $rely set resize($w,w) [winfo width $t] set resize($w,h) [winfo height $t] set resize($w,winc) 1 set resize($w,hinc) 1 set resize($w,grid) [wm grid $t] } # The following proc handles mouse motion on the resize control by asking the # wm to adjust the size of the window. proc StatusBar::continue_resize {w rootx rooty} { variable resize if {[llength $resize($w,grid)]} { # at this time, we don't know how to handle gridded resizing return } set t [winfo toplevel $w] set relx [expr {$rootx - [winfo rootx $t]}] set rely [expr {$rooty - [winfo rooty $t]}] set width [expr {$relx - $resize($w,x) + $resize($w,w)}] set height [expr {$rely - $resize($w,y) + $resize($w,h)}] if {$width < 0} { set width 0 } if {$height < 0} { set height 0 } wm geometry $t ${width}x${height} } # The following proc cleans up when the user releases the mouse button. proc StatusBar::end_resize {w rootx rooty} { variable resize #continue_resize $w $rootx $rooty #wm grid $t $resize($w,grid) array unset resize $w,* } amsn-0.98.9/utils/BWidget-1.9.0/dynhelp.tcl0000644000175000017500000005637511234370133017705 0ustar billiobbilliob# ---------------------------------------------------------------------------- # dynhelp.tcl # This file is part of Unifix BWidget Toolkit # $Id: dynhelp.tcl,v 1.20 2009/07/15 16:50:16 oehhar Exp $ # ---------------------------------------------------------------------------- # Index of commands: # - DynamicHelp::configure # - DynamicHelp::include # - DynamicHelp::sethelp # - DynamicHelp::register # - DynamicHelp::_motion_balloon # - DynamicHelp::_motion_info # - DynamicHelp::_leave_info # - DynamicHelp::_menu_info # - DynamicHelp::_show_help # - DynamicHelp::_init # ---------------------------------------------------------------------------- namespace eval DynamicHelp { Widget::define DynamicHelp dynhelp -classonly Widget::declare DynamicHelp { {-foreground TkResource black 0 label} {-topbackground TkResource black 0 {label -foreground}} {-background TkResource "#FFFFC0" 0 label} {-borderwidth TkResource 1 0 label} {-justify TkResource left 0 label} {-font TkResource "helvetica 8" 0 label} {-delay Int 600 0 "%d >= 100 & %d <= 2000"} {-state Enum "normal" 0 {normal disabled}} {-padx TkResource 1 0 label} {-pady TkResource 1 0 label} {-bd Synonym -borderwidth} {-bg Synonym -background} {-fg Synonym -foreground} {-topbg Synonym -topbackground} } proc use {} {} variable _registered variable _canvases variable _texts variable _top ".help_shell" variable _id "" variable _delay 600 variable _current_balloon "" variable _current_variable "" variable _saved Widget::init DynamicHelp $_top {} bind BwHelpBalloon {DynamicHelp::_motion_balloon enter %W %X %Y} bind BwHelpBalloon {DynamicHelp::_motion_balloon motion %W %X %Y} bind BwHelpBalloon {DynamicHelp::_motion_balloon leave %W %X %Y} bind BwHelpBalloon