~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Open Mash Cross Reference
mash/tcl/applications/collaborator/source.tcl

Component: ~ [ mash ] ~ [ apps ] ~ [ gsm ] ~ [ lib ] ~ [ otcl ] ~ [ srm ] ~ [ tcl8.3 ] ~ [ tclcl ] ~ [ tk8.3 ] ~ [ tutorials ] ~

  1 # source.tcl --
  2 #
  3 #       FIXME: This file needs a description here.
  4 #
  5 # Copyright (c) 1998-2002 The Regents of the University of California.
  6 # All rights reserved.
  7 #
  8 # Redistribution and use in source and binary forms, with or without
  9 # modification, are permitted provided that the following conditions are met:
 10 #
 11 # A. Redistributions of source code must retain the above copyright notice,
 12 #    this list of conditions and the following disclaimer.
 13 # B. Redistributions in binary form must reproduce the above copyright notice,
 14 #    this list of conditions and the following disclaimer in the documentation
 15 #    and/or other materials provided with the distribution.
 16 # C. Neither the names of the copyright holders nor the names of its
 17 #    contributors may be used to endorse or promote products derived from this
 18 #    software without specific prior written permission.
 19 #
 20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
 21 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 22 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 23 # ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
 24 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 25 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 26 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 27 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 28 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 30 #
 31 #  @(#) $Header: /usr/mash/src/repository/mash/mash-1/tcl/applications/collaborator/source.tcl,v 1.15 2002/02/03 04:21:46 lim Exp $
 32 
 33 
 34 import WidgetClass MultiSourceIcons VideoWidget Rank DragNDrop CompoundButton
 35 
 36 Class MultiSource
 37 WidgetClass UIMultiSource -configspec {
 38         { -value       value       Value       {}            config_option }
 39         { -select      select      Select      0             config_option }
 40         { -highlight   highlight   Highlight   0             config_option }
 41 
 42         { -relief relief Relief flat config_option }
 43         { -normalbackground normalBackground NormalBackground \
 44                         WidgetDefault(-background) config_option }
 45         { -normalforeground normalForeground NormalForeground \
 46                         WidgetDefault(-foreground) config_option }
 47         { -normalrelief normalRelief NormalRelief flat config_option }
 48         { -selectbackground selectBackground SelectBackground WidgetDefault \
 49                         config_option }
 50         { -selectforeground selectForeground SelectForeground WidgetDefault \
 51                         config_option }
 52         { -selectrelief selectRelief SelectRelief sunken config_option }
 53         { -highlightrelief highlightRelief HighlightRelief raised \
 54                         config_option }
 55 } -default {
 56         { *activeColor white }
 57         { *defaultColor WidgetDefault(-background) }
 58         { *disabledColor WidgetDefault(-disabledforeground) }
 59 }
 60 
 61 
 62 
 63 WidgetClass UISource -default {
 64         { *defaultColor WidgetDefault(-background) }
 65         { *disabledColor WidgetDefault(-disabledforeground) }
 66 }
 67 
 68 
 69 
 70 UIMultiSource public init { args } {
 71         $self instvar config_
 72         set config_(-value) {}
 73         set config_(-select) 0
 74         set config_(-highlight) 0
 75         set config_(-normalbackground) Black
 76         set config_(-normalforeground) Black
 77         set config_(-normalrelief)     flat
 78         set config_(-selectbackground) Black
 79         set config_(-selectforeground) Black
 80         set config_(-selectrelief)     sunken
 81         set config_(-highlightrelief)  raised
 82 
 83         eval [list $self] next $args
 84 }
 85 
 86 
 87 UIMultiSource public config_option { option args } {
 88         $self instvar config_
 89         if { [llength $args]==0 } {
 90                 return $config_($option)
 91         } else {
 92                 set value [lindex $args 0]
 93                 set config_($option) $value
 94                 if { $option == "-relief" } {
 95                         $self widget_proc configure $option $value
 96                 }
 97         }
 98 }
 99 
100 
101 
102 WidgetClass UISource/RTP     -superclass UISource
103 WidgetClass UISource/Audio   -superclass UISource/RTP
104 WidgetClass UISource/Video   -superclass UISource/RTP
105 WidgetClass UISource/Mb      -superclass UISource
106 WidgetClass UISource/Mbv2    -superclass UISource
107 WidgetClass UISource/Unknown -superclass UISource
108 
109 
110 UISource/Audio   set image_ MultiSourceIcons(audio)
111 UISource/Video   set image_ MultiSourceIcons(video)
112 UISource/Mb      set image_ MultiSourceIcons(mb)
113 UISource/Mbv2    set image_ MultiSourceIcons(mb)
114 UISource/Unknown set image_ MultiSourceIcons(unknown)
115 
116 
117 UISource public init { widget observer src msrc args } {
118         $self set src_ $src
119         $self set msrc_ $msrc
120         $self set observer_ $observer
121         eval $self next $widget $args
122 }
123 
124 
125 UISource public destroy { } {
126         $self next
127 }
128 
129 
130 UISource public src {} { return [$self set src_] }
131 
132 
133 UISource public create_root_widget {path} {
134         [$self info class] instvar image_
135         button $path -image $image_ -bd 1 -relief raised -padx 1000 \
136                         -highlightthickness 0 -takefocus 0
137         $path configure -activebackground [option get $path defaultColor \
138                         UISource]
139 }
140 
141 
142 UISource public msrc {msrc} {
143         $self set msrc_ $msrc
144 }
145 
146 
147 UISource public save_state { state } {
148 }
149 
150 
151 UISource public restore_state { state } {
152 }
153 
154 
155 UISource public tip {} {
156         return {}
157 }
158 
159 
160 UISource/Audio public tip {} {
161         return Audio
162 }
163 
164 
165 UISource/Video public tip {} {
166         return Video
167 }
168 
169 
170 UISource/Mb public tip {} {
171         return Mediaboard
172 }
173 
174 
175 UISource/Video public name { } {
176         $self instvar msrc_
177         return [$msrc_ name]
178 }
179 
180 
181 UISource/Video public save_state { state_var } {
182         upvar $state_var state
183         set state(have_thumbnail) [$self have_thumbnail]
184 }
185 
186 
187 UISource/Video public restore_state { state_var } {
188         $self instvar msrc_ src_
189         upvar $state_var state
190         if $state(have_thumbnail) {
191                 $msrc_ add_thumbnail video $src_
192         }
193 }
194 
195 
196 UISource/RTP public destroy {} {
197         $self instvar info_win_ rtp_win_ decoder_win_
198         if [info exists info_win_] {
199                 delete $info_win_
200         }
201         if [info exists rtp_win_] {
202                 delete $rtp_win_
203         }
204         if [info exists decoder_win_] {
205                 delete $decoder_win_
206         }
207         $self next
208 }
209 
210 
211 UISource/Video public destroy {} {
212         $self instvar src_ thumbnail_ thumbnail_path_ info_path_ observer_ src_
213 
214         $observer_ detach_windows $src_
215         if [info exists thumbnail_] {
216                 $self destroy_thumbnail
217         }
218         if [info exists info_path_] {
219                 $self destroy_info
220         }
221 
222         $self instvar scuba_win_
223         if [info exists scuba_win_] {
224                 $self delete-scuba-window
225         }
226 
227         $self next
228 }
229 
230 
231 UISource/Video public build_widget {path} {
232         $self tkvar mute_ color_
233         $self instvar observer_ src_ userwindows_
234         $path configure -command "tk_popup $path.menu \[winfo pointerx $path\]\
235                         \[winfo pointery $path\]"
236 
237         set userwindows_ {}
238         set mute_ [$observer_ mute_new_sources]
239         $src_ mute $mute_
240         set color_ 1
241 
242         menu $path.menu
243         $path.menu add checkbutton -label "Mute" \
244                         -variable [$self tkvarname mute_] \
245                         -command "$self mute \$\{[$self tkvarname mute_]\}"
246         $path.menu add checkbutton -label "Color" \
247                         -variable [$self tkvarname color_] \
248                         -command "$self color \$\{[$self tkvarname color_]\}"
249         $path.menu add cascade -label "Info..." -menu $path.menu.info
250         $self build_info_menu $path.menu.info
251 }
252 
253 
254 UISource/Video public have_thumbnail {} {
255         $self instvar thumbnail_
256         return [info exists thumbnail_]
257 }
258 
259 
260 UISource/Video public create_thumbnail {path} {
261         $self instvar src_ thumbnail_ thumbnail_path_
262         set thumbnail_path_ $path.thumbnail$src_
263         frame $thumbnail_path_ -bd 1 -relief raised
264         set thumbnail_ [new VideoWidget $thumbnail_path_.src 80 60]
265         $thumbnail_ set is_slow_ 1
266         pack $thumbnail_path_.src -fill both -expand 1
267         pack $thumbnail_path_ -in $path -side left
268 
269         $self bind_thumbnail $thumbnail_path_.src
270         $self attach_thumbnail
271 }
272 
273 
274 UISource/Video public destroy_thumbnail {} {
275         $self instvar src_ thumbnail_ thumbnail_path_ dragdrop_
276         if [info exists thumbnail_] {
277                 $self detach_thumbnail
278                 delete $dragdrop_
279                 delete $thumbnail_
280                 destroy $thumbnail_path_
281                 unset thumbnail_
282                 unset thumbnail_path_
283                 unset dragdrop_
284         }
285 }
286 
287 
288 UISource/Video private bind_thumbnail t {
289         $self instvar dragdrop_
290         bind $t <Double-ButtonPress-1> "$self select_thumbnail"
291         set dragdrop_ [new DragNDrop $t "$self dragNdrop_thumbnail"]
292         $dragdrop_ proc select_widget  w "$self build_dragdrop \$self \$w"
293         $dragdrop_ proc release_widget w "$self delete_dragdrop \$self \$w"
294 }
295 
296 
297 UISource/Video private build_dragdrop { dragdrop w } {
298         $self instvar src_
299         set vw [new VideoWidget $w.video 80 60]
300         pack $w.video -fill both -expand 1
301 
302         $vw attach-decoder $src_ [UISource/Video set colorModel_] \
303                         [UISource/Video set use_hw_decode_]
304         $vw set is_slow_ 1
305         $dragdrop set vw_ $vw
306 }
307 
308 
309 UISource/Video private delete_dragdrop { dragdrop w } {
310         $dragdrop instvar vw_
311         $self instvar src_
312         $vw_ detach-decoder $src_
313         destroy $w.video
314         delete $vw_
315         unset vw_
316 }
317 
318 
319 #
320 # Called when user double-clicks on thumbnail video window.
321 # Create a new window only if the window already
322 # isn't being displayed (in locked mode).  In this
323 # case, delete the existing window (i.e., clicking
324 # on the thumbnail gives a toggle action, but not
325 # for voice-switched or browse-mode windows).
326 #
327 UISource/Video public select_thumbnail {} {
328         foreach uw [$self user_windows] {
329                 if { [$uw attached-source] == "$self" && ![$uw is-switched] &&\
330                                 [[$uw info class] info heritage VideoWidget] \
331                                 == {} } {
332                         delete $uw
333                         return
334                 }
335         }
336 
337         $self create_user_window
338 }
339 
340 
341 #
342 # Create a UserWindow for this ActiveSource.
343 #
344 UISource/Video private create_user_window { } {
345         $self instvar observer_
346         new UserWindow $observer_ $self [$self yesno useCues] \
347                         [$observer_ can_voiceswitch] {} 1
348 }
349 
350 
351 #
352 # Returns true if the represented source is h261 format.
353 #
354 UISource/Video public isCIF {} {
355         $self instvar src_
356         return [expr [string compare [$src_ format_name] h261] == 0]
357 }
358 
359 
360 UISource/Video private dragNdrop_thumbnail { dragndrop x y } {
361         $self instvar observer_
362         if ![[$observer_ video_container] drop_thumbnail $dragndrop $self \
363                         $x $y] {
364                 $dragndrop zoom_back
365         }
366 }
367 
368 
369 UISource/Video proc.public decoder_params { colorModel use_hw_decode } {
370         $self set colorModel_ $colorModel
371         $self set use_hw_decode_ $use_hw_decode
372 }
373 
374 
375 #
376 UISource/Video public attach_thumbnail {} {
377         $self instvar src_ thumbnail_
378         $thumbnail_ attach-decoder $src_ [UISource/Video set colorModel_] \
379                         [UISource/Video set use_hw_decode_]
380 }
381 
382 #
383 UISource/Video public detach_thumbnail {} {
384         $self instvar src_ thumbnail_
385         $thumbnail_ detach-decoder $src_
386 }
387 
388 
389 UISource/Video public create_info {path} {
390         $self instvar src_ msrc_ timer_id_ info_path_
391         $self tkvar ftext_ btext_ ltext_ info_
392         set ftext_ "0.0 f/s"
393         set btext_ "0.0 kb/s"
394         set ltext_ "(0%)"
395         set info_ [$msrc_ cname]
396 
397         set path $path.info$src_
398         set info_path_ $path
399         frame $path -bd 2 -relief groove
400         frame $path.frame
401         label $path.info -textvariable [$self tkvarname info_] \
402                         -anchor w -pady 0
403         label $path.ftext -textvariable [$self tkvarname ftext_] \
404                         -anchor w -pady 0
405         label $path.btext -textvariable [$self tkvarname btext_] \
406                         -anchor w -pady 0
407         label $path.ltext -textvariable [$self tkvarname ltext_] \
408                         -anchor w -pady 0
409         pack $path.ftext $path.btext $path.ltext -fill both -expand 1 \
410                         -pady 0 -side left -in $path.frame
411         pack $path.info -side top -pady 0 -fill x -expand 1
412         pack $path.frame -side top -fill x -expand 1
413         pack $path -fill both -expand 1
414 
415         set timer_id_ [after 1000 "$self update_info"]
416 }
417 
418 
419 UISource/Video public destroy_info { } {
420         $self instvar info_path_ timer_id_
421         if ![info exists info_path_] return
422 
423         $self tkvar info_ ftext_ btext_ ltext_
424         if [info exists timer_id_] {
425                 after cancel $timer_id_
426                 unset timer_id_
427         }
428 
429         destroy $info_path_
430         unset info_path_
431         unset info_ ftext_ btext_ ltext_
432 }
433 
434 
435 UISource/Video private update_info {} {
436         $self tkvar ftext_
437         $self instvar src_ msrc_ timer_id_
438         if ![info exists ftext_] {
439                 return
440         }
441 
442         $self update_rate
443         set timer_id_ [after 1000 "$self update_info"]
444 }
445 
446 
447 #
448 # Using the specified video source, <i>src_</i>, as an index, update the
449 # global arrays bpshat(), fpshat(), shat(), lhat(), ltext(), ftext(), btext().
450 #
451 UISource/Video private update_rate {} {
452         $self instvar src_
453         $self tkvar ftext_ btext_ ltext_
454         global fpshat bpshat lhat shat
455 
456         set key $src_
457         if [string match Session/* [$src_ info class]] {
458                 set bpshat($key) [expr 8 * [$src_ set nb_]]
459                 set fpshat($key) [$src_ set nf_]
460         } else {
461                 # only compute loss statistic for network side
462                 set p [$src_ layer-stat np_]
463                 set s [$src_ ns]
464                 set shat($key) $s
465                 set lhat($key) [expr $s-$p]
466                 if {$shat($key) <= 0.} {
467                         set loss 0
468                 } else {
469                         set loss [expr 100*$lhat($key)/$shat($key)]
470                 }
471                 if {$loss < .1} {
472                         set ltext_ (0%)
473                 } elseif {$loss < 9.9} {
474                         set ltext_ [format "(%.1f%%)" $loss]
475                 } else {
476                         set ltext_ [format "(%.0f%%)" $loss]
477                 }
478                 set bpshat($key) [expr 8 * [$src_ layer-stat nb_]]
479                 set fpshat($key) [$src_ layer-stat nf_]
480         }
481 
482         set fps $fpshat($key)
483         set bps $bpshat($key)
484 
485         if { $fps < .1 } {
486                 set fps "0 f/s"
487         } elseif { $fps < 10 } {
488                 set fps [format "%.1f f/s" $fps]
489         } else {
490                 set fps [format "%2.0f f/s" $fps]
491         }
492         if { $bps < 1 } {
493                 set bps "0 bps"
494         } elseif { $bps < 1000 } {
495                 set bps [format "%3.0f bps" $bps]
496         } elseif { $bps < 1000000 } {
497                 set bps [format "%3.0f kb/s" [expr $bps / 1000]]
498         } else {
499                 set bps [format "%.1f Mb/s" [expr $bps / 1000000]]
500         }
501         set ftext_ $fps
502         set btext_ $bps
503 
504         # FIXME: need this to update the video ctrlmenu
505         $self instvar observer_
506         $observer_ instvar agent_
507         if { $src_ == [$agent_ local] } {
508                 global ftext btext
509                 set key [$agent_ set session_]
510                 set ftext($key) $fps
511                 set btext($key) $bps
512         }
513 }
514 
515 
516 UISource/Video public change_info { info } {
517         $self tkvar info_
518         set info_ $info
519 }
520 
521 
522 UISource/Video public get_info {} {
523         $self tkvar info_
524         if [info exists info_] { return $info_ }  else { return "" }
525 }
526 
527 
528 
529 #
530 # Create a menu for accessing information and data associated with the represented source: <br>
531 #    <dd> "Site Info"
532 #    <dd> "RTP Stats"
533 #    <dd> "Decoder Stats"
534 #    <dd> "Mtrace from"
535 #    <dd> "Mtrace to"
536 #    <dd> and possibly "Scuba Info"
537 #
538 UISource/RTP private build_info_menu { m } {
539         $self instvar observer_
540         menu $m
541         set f [$self get_option smallfont]
542         $m add command -label "Site Info" \
543                 -command "$self create-info-window" -font $f
544         $m add command -label "RTP Stats"\
545                 -command "$self create-rtp-window" -font $f
546         $m add command -label "Decoder Stats" \
547                 -command "$self create-decoder-window" -font $f
548         if [in_multicast [[$observer_ agent] session-addr]] {
549                 $m add command -label "Mtrace from" \
550                         -command "$self create-mtrace-window from" -font $f
551                 $m add command -label "Mtrace to" \
552                         -command "$self create-mtrace-window to" -font $f
553         }
554 }
555 
556 
557 UISource/Video private build_info_menu { m } {
558         $self instvar observer_
559         $self next $m
560         if { [$observer_ scuba_session] != {} } {
561                 set f [$self get_option smallfont]
562                 $m add command -label "Scuba Info" -font $f \
563                                 -command "$self create-scuba-window"
564         }
565 }
566 
567 
568 #
569 # If a window exists for displaying the Scuba Votes for this source,
570 # delete it.  Else, create one.
571 #
572 UISource/Video private create-scuba-window {} {
573         UISource/Video instvar scubaInfoCnt_
574         if ![info exists scubaInfoCnt_] { set scubaInfoCnt_ 0 }
575         $self instvar scuba_win_ src_ observer_
576         if [info exists scuba_win_] {
577                 $self delete-scuba-window
578         } else {
579                 set scuba_sess [$observer_ scuba_session]
580                 set scuba_win_ [new ScubaInfoWindow \
581                                 .scubainfo_for_uisrc_video$scubaInfoCnt_ \
582                                 $src_ $self $scuba_sess]
583                 incr scubaInfoCnt_
584                 [$scuba_sess source-manager] attach $scuba_win_
585                 $scuba_win_ timeout
586         }
587 }
588 
589 #
590 # Delete the Scuba Votes window for this source.
591 #
592 UISource/Video private delete-scuba-window {} {
593         $self instvar scuba_win_ observer_
594         set scuba_sess [$observer_ scuba_session]
595         [$scuba_sess source-manager] detach $scuba_win_
596         delete $scuba_win_
597         unset scuba_win_
598 }
599 
600 
601 #
602 # If an InfoWindow exists for this source, delete it.  Else, create one.
603 #
604 UISource/RTP instproc create-info-window {} {
605         $self instvar src_ info_win_
606         if [info exists info_win_] {
607                 $self delete-info-window
608         } else {
609                 set info_win_ [new InfoWindow .info$src_ $src_ $self]
610         }
611 }
612 
613 #
614 # Delete the InfoWindow for this source.
615 #
616 UISource/RTP instproc delete-info-window {} {
617         $self instvar info_win_
618         delete $info_win_
619         unset info_win_
620 }
621 
622 #
623 # For the represented source, return a string
624 # describing its network statistics.
625 #
626 UISource/RTP instproc stats {} {
627         $self instvar src_
628         return "Kilobits [expr [$src_ layer-stat nb_] >> (10-3)] \
629                 Frames [$src_ layer-stat nf_] \
630                 Packets [$src_ layer-stat np_] \
631                 Missing [$src_ missing] \
632                 Misordered [$src_ layer-stat nm_] \
633                 Runts [$src_ layer-stat nrunt_] \
634                 Dups [$src_ layer-stat ndup_] \
635                 Bad-S-Len [$src_ set badsesslen_] \
636                 Bad-S-Ver [$src_ set badsessver_] \
637                 Bad-S-Opt [$src_ set badsessopt_] \
638                 Bad-Sdes [$src_ set badsdes_] \
639                 Bad-Bye [$src_ set badbye_]"
640 }
641 
642 #
643 # For the represented source, return the decoder statistics.
644 #
645 UISource/RTP instproc decoder-stats {} {
646         $self instvar src_
647         set d [$src_ handler]
648         #FIXME
649         return [$d stats]
650 }
651 
652 #
653 # If a window exists for displaying the RTP Statistics of this source, delete it.  Else, create one.
654 #
655 UISource/RTP instproc create-rtp-window {} {
656         $self instvar src_ rtp_win_
657         if [info exists rtp_win_] {
658                 $self delete-rtp-window
659         } else {
660                 set rtp_win_ [new RtpStatWindow .rtp$src_ $src_ \
661                                         "RTP Statistics" \
662                                         "$self stats" \
663                                         "$self delete-rtp-window"]
664         }
665 }
666 
667 #
668 # Delete the RTP Statisctics window for this source.
669 #
670 UISource/RTP instproc delete-rtp-window {} {
671         $self instvar rtp_win_
672         delete $rtp_win_
673         unset rtp_win_
674 }
675 
676 #
677 # If a window exists for displaying the Decoder Statistics of this source, delete it.  Else, create one.
678 #
679 UISource/RTP instproc create-decoder-window {} {
680         $self instvar src_ decoder_win_
681         if [info exists decoder_win_] {
682                 $self delete-decoder-window
683         } else {
684                 if { "[$src_ handler]" == "" } {
685                         new ErrorWindow "no decoder stats yet"
686                         return
687                 }
688                 set decoder_win_ [new RtpStatWindow .decoder$src_ $src_  \
689                                 "Decoder Statistics" \
690                                 "$self decoder-stats" \
691                                 "$self delete-decoder-window"]
692         }
693 }
694 
695 #
696 # Delete the Decoder Statisctics window for this source.
697 #
698 UISource/RTP instproc delete-decoder-window {} {
699         $self instvar decoder_win_
700         if [info exists decoder_win_] {
701                 delete $decoder_win_
702                 unset decoder_win_
703         }
704 }
705 
706 
707 UISource public change_info { info } {
708         # FIXME
709 }
710 
711 
712 UISource public get_info {} {
713         # FIXME
714         return ""
715 }
716 
717 
718 UISource/Video public user_windows {} {
719         return [$self set userwindows_]
720 }
721 
722 
723 UISource/Video public detach_windows {} {
724         $self instvar userwindows_
725         foreach uw $userwindows_ {
726                 $self detach-window $uw
727         }
728 }
729 
730 
731 
732 #
733 # Bind a source to a window so that the video stream from the
734 # represented source appears in UserWindow <i>uw</i>.
735 #
736 UISource/Video public attach_window { uw } {
737         $self instvar src_ observer_
738         UISource/Video instvar colorModel_ use_hw_decode_
739         [$uw video-widget] attach-decoder $src_ $colorModel_ $use_hw_decode_
740         $self instvar userwindows_
741         lappend userwindows_ $uw
742         $uw set-name [$src_ getid]
743 
744         set scuba_sess [$observer_ scuba_session]
745         if { $scuba_sess != {} } {
746                 $scuba_sess scuba_focus $src_
747         }
748 }
749 
750 
751 #
752 # Discontinue the representation of this ActiveSource in UserWindow <i>uw</i>.
753 #
754 UISource/Video public detach_window uw {
755         $self instvar userwindows_ src_ observer_
756         set scuba_sess [$observer_ scuba_session]
757         if { $scuba_sess != {} } {
758                 $scuba_sess scuba_unfocus $src_
759         }
760         [$uw video-widget] detach-decoder $src_
761         # there must be an easier way to do this
762         set k [lsearch -exact $userwindows_ $uw]
763         if { $k < 0 } {
764                 puts "[$self get_option appname]: detach-window: FIXME"
765                 exit 1
766         }
767         set userwindows_ [lreplace $userwindows_ $k $k]
768 }
769 
770 
771 # FIXME: required for UserWindow
772 UISource/Video public attach-window {w} {
773         $self attach_window $w
774 }
775 UISource/Video public detach-window {w} {
776         $self detach_window $w
777 }
778 
779 
780 UISource/Video public color { { c {} } } {
781         $self instvar src_ userwindows_ thumbnail_
782         $self tkvar color_
783         if { $c == {} } { return $color_ }
784         set h [$src_ handler]
785         if { $h != {} } {
786                 $h color $c
787                 foreach uw $userwindows_ {
788                         [$uw video-widget] redraw
789                 }
790                 if [info exists thumbnail_] {
791                         $thumbnail_ redraw
792                 }
793         }
794         set color_ $c
795 }
796 
797 
798 UISource/Video public mute { { m {} } } {
799         $self instvar src_
800         $self tkvar mute_
801         if { $m == {} } { return $mute_ }
802         $src_ mute $m
803         set mute_ $m
804 }
805 
806 
807 UISource/Audio public mute { { m {} } } {
808         $self instvar src_
809         $self tkvar mute_
810         if { $m == {} } { return $mute_ }
811         $src_ mute $m
812         set mute_ $m
813         $self draw_indicator
814 }
815 
816 
817 UISource/Audio public create_root_widget {path} {
818         [$self info class] instvar image_
819         # need the container frame becoz the root widget cannot be
820         # another WidgetObject; this'll horribly confuse the
821         # WidgetClass library
822         frame $path
823         set path [CompoundButton $path.b -bd 1 -relief raised \
824                         -highlightthickness 0]
825         $path add button icon -image $image_ -bd 0 -relief flat \
826                         -highlightthickness 0 -takefocus 0
827         $path.icon configure -activebackground [option get $path defaultColor \
828                         UISource]
829         $path add canvas indicator -width 0 -height 0 -bg \
830                         [option get $path defaultColor UISource] \
831                         -bd 0 -relief sunken
832         pack $path.icon -side left
833         pack $path.indicator -padx 6 -side left
834         pack $path -fill both -expand 1
835         $self set_subwidget indicator $path.indicator
836         $self set_subwidget icon $path.icon
837 
838 
839         $path configure -command "tk_popup $path.menu \[winfo pointerx $path\]\
840                         \[winfo pointery $path\]"
841         menu $path.menu
842         $path.menu add checkbutton -label "Mute" \
843                         -variable [$self tkvarname mute_] \
844                         -command "$self mute \$\{[$self tkvarname mute_]\}"
845         $path.menu add cascade -label "Info..." -menu $path.menu.info
846         $self build_info_menu $path.menu.info
847 }
848 
849 
850 UISource/Audio public create_root_widget1 {path} {
851         frame $path -bd 1 -relief raised
852         [$self info class] instvar image_
853         button $path.icon -image $image_ -bd 0 -relief flat \
854                         -highlightthickness 0 -takefocus 0
855         $path.icon configure -activebackground [option get $path defaultColor \
856                         UISource]
857         frame $path.indicator -width 0 -height 0 -bg [option get $path \
858                         defaultColor UISource] -bd 0 -relief sunken
859         pack $path.icon -side left
860         pack $path.indicator -padx 7 -side left
861 }
862 
863 
864 UISource/Audio public rank { {rank {}} } {
865         # FIXME
866         $self instvar rank_
867         if ![info exists rank_] { set rank_ 4 }
868         if { $rank == {} } { return $rank_ } else {
869                 set rank_ $rank
870                 $self draw_indicator
871         }
872 }
873 
874 
875 UISource/Audio private draw_indicator {} {
876         $self instvar src_ disabled_
877 
878         set indicator [$self subwidget indicator]
879         if { [info exists disabled_] && $disabled_ } {
880                 $indicator configure -width 10 -height 10 -bd 1 \
881                                 -bg [option get [$self info path] \
882                                 disabledColor UISource/Audio]
883                 pack configure $indicator -padx 1
884         } elseif [$src_ mute] {
885                 $indicator configure -width 9 -height 9 -bd 1 \
886                                 -bg red
887                 pack configure $indicator -padx 1
888         } else {
889                 switch [$self rank] {
890                         0 {
891                                 $indicator configure -width 9 -height 9 \
892                                                 -bg green -bd 1
893                                 pack configure $indicator -padx 1
894                         }
895                         1 {
896                                 $indicator configure -width 7 -height 7 \
897                                                 -bg green -bd 1
898                                 pack configure $indicator -padx 2
899                         }
900                         2 {
901                                 $indicator configure -width 3 -height 3 \
902                                                 -bg green -bd 1
903                                 pack configure $indicator -padx 5
904                         }
905                         default {
906                                 $indicator configure -width 0 -height 0 -bg \
907                                                 [option get [$self info path]\
908                                                 defaultColor UISource] -bd 0
909                                 pack configure $indicator -padx 6
910                         }
911                 }
912         }
913 }
914 
915 
916 UISource/Audio public disable {flag} {
917         $self instvar disabled_
918         set disabled_ $flag
919         $self draw_indicator
920 }
921 
922 
923 UISource public highlight {flag} {
924         $self instvar msrc_
925         if $flag { set relief sunken } else { set relief raised }
926         $self set_relief $relief
927         $msrc_ highlight $flag
928 }
929 
930 
931 UISource public set_relief {relief} {
932         [$self info path] configure -relief $relief
933 }
934 
935 
936 UISource/Audio public set_relief {relief} {
937         $self subwidget b configure -relief $relief
938 }
939 
940 
941 MultiSource public init {sm cname} {
942         $self next
943         $self instvar sm_ widget_ cname_ highlight_
944         set list [$sm list_ui]
945         $list insert end [list -id $self ""]
946         set widget_ [$list info widget -id $self]
947         set sm_ $sm
948         set cname_ $cname
949         set highlight_ 0
950 
951         $self build_widget $widget_
952 }
953 
954 
955 MultiSource public destroy {} {
956         $self instvar sm_
957         set list [$sm_ list_ui]
958</