#!/usr/bin/env python
# -*- Mode: Python -*-
# vi:si:et:sw=4:sts=4:ts=4

import pygtk
pygtk.require('2.0')

import sys

import gobject

import pygst
pygst.require('0.10')
import gst
import gst.interfaces
import gtk

baseball_xpm = [
"32 32 519 2",
"  	c None",
". 	c #000000",
"+ 	c #160000",
"@ 	c #5F0000",
"# 	c #875956",
"$ 	c #9F9992",
"% 	c #ACA59C",
"& 	c #AAA397",
"* 	c #999285",
"= 	c #797468",
"- 	c #4C483F",
"; 	c #15130F",
"> 	c #2A2726",
", 	c #948B87",
"' 	c #E39B97",
") 	c #EE6966",
"! 	c #DCCAC2",
"~ 	c #DFABA3",
"{ 	c #EB5F59",
"] 	c #D0C9BA",
"^ 	c #CDC6B4",
"/ 	c #CAC2AF",
"( 	c #C7BFAA",
"_ 	c #C0B9A0",
": 	c #89836E",
"< 	c #2E2C23",
"[ 	c #090909",
"} 	c #827C79",
"| 	c #DCD3CF",
"1 	c #DED6D1",
"2 	c #DCD4CE",
"3 	c #D9D1C8",
"4 	c #D5CDC3",
"5 	c #EF4844",
"6 	c #FE0000",
"7 	c #DA8478",
"8 	c #C8C0AD",
"9 	c #C5BDA8",
"0 	c #C2BBA2",
"a 	c #BFB89E",
"b 	c #BCB599",
"c 	c #B8B193",
"d 	c #7A745C",
"e 	c #0F0E0A",
"f 	c #1B1A19",
"g 	c #B8B1AE",
"h 	c #DED6D2",
"i 	c #DDD5D1",
"j 	c #DAD2CB",
"k 	c #D7CEC6",
"l 	c #D3CBC0",
"m 	c #D0C8BB",
"n 	c #D1B4A6",
"o 	c #F60808",
"p 	c #E92F2A",
"q 	c #C3BBA6",
"r 	c #C0B8A1",
"s 	c #BEB69C",
"t 	c #BBB397",
"u 	c #B8B092",
"v 	c #B5AE8E",
"w 	c #B3AC8A",
"x 	c #9E9776",
"y 	c #222018",
"z 	c #1B1A1A",
"A 	c #C5BDBB",
"B 	c #DCD3CE",
"C 	c #D8CFC9",
"D 	c #D5CCC3",
"E 	c #D1C9BE",
"F 	c #CEC5B8",
"G 	c #CBC2B3",
"H 	c #C8BFAE",
"I 	c #DD5A51",
"J 	c #DD4941",
"K 	c #BFB69F",
"L 	c #BCB49A",
"M 	c #B9B195",
"N 	c #B7AF91",
"O 	c #B4AD8C",
"P 	c #B1AA88",
"Q 	c #AFA884",
"R 	c #ADA680",
"S 	c #A19A74",
"T 	c #222017",
"U 	c #B7B1AD",
"V 	c #DDD5D0",
"W 	c #DAD1CC",
"X 	c #D6CDC6",
"Y 	c #D3CAC1",
"Z 	c #D0C6BB",
"` 	c #CCC3B6",
" .	c #C9C0B1",
"..	c #C6BDAC",
"+.	c #C3BAA6",
"@.	c #C0B7A2",
"#.	c #BDB49D",
"$.	c #BBB298",
"%.	c #B8AF94",
"&.	c #B5AD8F",
"*.	c #B3AB8B",
"=.	c #B1A987",
"-.	c #AEA683",
";.	c #ACA57F",
">.	c #AAA37B",
",.	c #A8A177",
"'.	c #968F67",
").	c #100F0A",
"!.	c #807C79",
"~.	c #D5CBC3",
"{.	c #D1C8BE",
"].	c #CEC4B9",
"^.	c #CBC1B3",
"/.	c #C8BEAE",
"(.	c #C5BBA9",
"_.	c #C2B8A5",
":.	c #BFB5A0",
"<.	c #D74139",
"[.	c #CE584C",
"}.	c #B7AD92",
"|.	c #B4AB8E",
"1.	c #B2A98A",
"2.	c #B0A786",
"3.	c #ADA582",
"4.	c #ABA37E",
"5.	c #A9A17A",
"6.	c #A7A076",
"7.	c #A59E73",
"8.	c #A49D6F",
"9.	c #736E4C",
"0.	c #242322",
"a.	c #D7CFC8",
"b.	c #D6CDC5",
"c.	c #D3CAC0",
"d.	c #C9BFB1",
"e.	c #C6BCAC",
"f.	c #C3B9A7",
"g.	c #C0B6A3",
"h.	c #BDB39E",
"i.	c #C58574",
"j.	c #E00404",
"k.	c #CD483D",
"l.	c #B3AA8C",
"m.	c #B1A888",
"n.	c #AFA584",
"o.	c #ACA380",
"p.	c #AAA27C",
"q.	c #A8A079",
"r.	c #A69E75",
"s.	c #A49D72",
"t.	c #A39B6F",
"u.	c #A19A6C",
"v.	c #9F9868",
"w.	c #2E2C1D",
"x.	c #847F7A",
"y.	c #D4CBC2",
"z.	c #D1C8BD",
"A.	c #CEC4B8",
"B.	c #C7BDAE",
"C.	c #C4BAA9",
"D.	c #C1B7A5",
"E.	c #BFB4A0",
"F.	c #BCB29C",
"G.	c #B9AF97",
"H.	c #D52924",
"I.	c #D90908",
"J.	c #B79279",
"K.	c #B0A687",
"L.	c #ADA483",
"M.	c #ABA27F",
"N.	c #A9A07B",
"O.	c #A79E78",
"P.	c #A59D74",
"Q.	c #A39B71",
"R.	c #A29A6E",
"S.	c #A0986B",
"T.	c #9E9768",
"U.	c #9D9765",
"V.	c #76714A",
"W.	c #060606",
"X.	c #C8C0B5",
"Y.	c #CFC6B9",
"Z.	c #CCC3B5",
"`.	c #C9BFB0",
" +	c #C6BCAB",
".+	c #C0B6A2",
"++	c #BAB099",
"@+	c #B8AD95",
"#+	c #B6AB91",
"$+	c #BD7A66",
"%+	c #C15F4E",
"&+	c #AEA485",
"*+	c #ACA281",
"=+	c #AAA07E",
"-+	c #A89F7A",
";+	c #A69D77",
">+	c #A49B74",
",+	c #A29A70",
"'+	c #A1986D",
")+	c #9F976A",
"!+	c #9E9667",
"~+	c #9C9565",
"{+	c #9B9462",
"]+	c #99935F",
"^+	c #13120C",
"/+	c #35332F",
"(+	c #CDC5B6",
"_+	c #CAC1B1",
":+	c #C7BEAD",
"<+	c #C4BAA8",
"[+	c #C1B7A4",
"}+	c #BEB4A0",
"|+	c #BCB19B",
"1+	c #B9AE97",
"2+	c #B7AC93",
"3+	c #B5A68D",
"4+	c #BC7260",
"5+	c #A49A7F",
"6+	c #ADA384",
"7+	c #ABA180",
"8+	c #A99F7C",
"9+	c #A79D79",
"0+	c #A69B76",
"a+	c #A39A72",
"b+	c #A29970",
"c+	c #A0976D",
"d+	c #9E966A",
"e+	c #9D9567",
"f+	c #9C9464",
"g+	c #9A9362",
"h+	c #999360",
"i+	c #98925D",
"j+	c #3D3A24",
"k+	c #5A574F",
"l+	c #C8C0AE",
"m+	c #C5BCAA",
"n+	c #C2B9A5",
"o+	c #C0B6A1",
"p+	c #BDB39D",
"q+	c #B5AA91",
"r+	c #B3A88D",
"s+	c #BF6554",
"t+	c #C20606",
"u+	c #7F5847",
"v+	c #AA9F7E",
"w+	c #A89E7B",
"x+	c #A69C78",
"y+	c #A59A75",
"z+	c #A39972",
"A+	c #A1976F",
"B+	c #9F966C",
"C+	c #9E9569",
"D+	c #9D9466",
"E+	c #9C9364",
"F+	c #9A9262",
"G+	c #99754D",
"H+	c #973A29",
"I+	c #95432E",
"J+	c #573321",
"K+	c #6E695E",
"L+	c #C4BBA7",
"M+	c #C1B7A2",
"N+	c #BEB49E",
"O+	c #BBB19A",
"P+	c #B9AE96",
"Q+	c #B6AC92",
"R+	c #B4A98F",
"S+	c #B1A78B",
"T+	c #B19E82",
"U+	c #CB1613",
"V+	c #C71512",
"W+	c #AA9777",
"X+	c #A79D7A",
"Y+	c #A59B76",
"Z+	c #A49974",
"`+	c #A29871",
" @	c #A0966E",
".@	c #9E956B",
"+@	c #9D9468",
"@@	c #9C9366",
"#@	c #9B9263",
"$@	c #9B5C40",
"%@	c #988A5A",
"&@	c #97774E",
"*@	c #921010",
"=@	c #8E1010",
"-@	c #610B0B",
";@	c #716C5F",
">@	c #BCB39B",
",@	c #BAB097",
"'@	c #B7AD93",
")@	c #B5AB90",
"!@	c #B2A88C",
"~@	c #B0A689",
"{@	c #AEA385",
"]@	c #B2846B",
"^@	c #C51814",
"/@	c #B45E4A",
"(@	c #A49A75",
"_@	c #A39872",
":@	c #A19770",
"<@	c #9F956D",
"[@	c #9E946A",
"}@	c #9D9368",
"|@	c #9B9265",
"1@	c #9A9163",
"2@	c #9A5D40",
"3@	c #980F0F",
"4@	c #964B33",
"5@	c #968E5A",
"6@	c #958B57",
"7@	c #94804F",
"8@	c #69482D",
"9@	c #666154",
"0@	c #B8AF95",
"a@	c #B6AC91",
"b@	c #B3AA8D",
"c@	c #B1A78A",
"d@	c #AFA586",
"e@	c #ADA283",
"f@	c #ABA080",
"g@	c #A99E7D",
"h@	c #A89876",
"i@	c #A69774",
"j@	c #A39974",
"k@	c #A29771",
"l@	c #9E956C",
"m@	c #9D9369",
"n@	c #9C9367",
"o@	c #9B9165",
"p@	c #9A9062",
"q@	c #997F56",
"r@	c #961412",
"s@	c #931F19",
"t@	c #958455",
"u@	c #958E59",
"v@	c #958E58",
"w@	c #958E56",
"x@	c #65613A",
"y@	c #4C493D",
"z@	c #B7AE92",
"A@	c #B2A98B",
"B@	c #AEA384",
"C@	c #ABA181",
"D@	c #AB8A6C",
"E@	c #B73C30",
"F@	c #AA785C",
"G@	c #A19670",
"H@	c #9E946B",
"I@	c #9D9268",
"J@	c #9B9266",
"K@	c #9A9064",
"L@	c #999062",
"M@	c #988F60",
"N@	c #977B52",
"O@	c #912D21",
"P@	c #936D47",
"Q@	c #948E57",
"R@	c #948E55",
"S@	c #53502F",
"T@	c #26241E",
"U@	c #B3AA8B",
"V@	c #AFA585",
"W@	c #ACA382",
"X@	c #AAA07F",
"Y@	c #A99E7B",
"Z@	c #A79C79",
"`@	c #AC6E55",
" #	c #BA0909",
".#	c #AA624A",
"+#	c #A0956E",
"@#	c #9E946C",
"##	c #9C9267",
"$#	c #9A9063",
"%#	c #998F61",
"&#	c #988F5F",
"*#	c #978357",
"=#	c #968B5B",
"-#	c #958D5B",
";#	c #958D59",
">#	c #958D58",
",#	c #948D57",
"'#	c #948D56",
")#	c #34321E",
"!#	c #020201",
"~#	c #9F9779",
"{#	c #ADA482",
"]#	c #A9A07C",
"^#	c #A89E79",
"/#	c #A69C76",
"(#	c #A49A74",
"_#	c #A96D52",
":#	c #B40A0A",
"<#	c #A66148",
"[#	c #9C9268",
"}#	c #9B9166",
"|#	c #998F62",
"1#	c #988F61",
"2#	c #988E5F",
"3#	c #978E5D",
"4#	c #904631",
"5#	c #8A231C",
"6#	c #948655",
"7#	c #948D58",
"8#	c #918C53",
"9#	c #0C0B07",
"0#	c #5B5744",
"a#	c #AAA17D",
"b#	c #A79D77",
"c#	c #A59B74",
"d#	c #A28461",
"e#	c #AC201A",
"f#	c #A16E50",
"g#	c #9A8F63",
"h#	c #988E60",
"i#	c #978E5E",
"j#	c #978D5D",
"k#	c #958B5B",
"l#	c #871F1A",
"m#	c #84211B",
"n#	c #948C58",
"o#	c #636039",
"p#	c #100F0B",
"q#	c #9F9772",
"r#	c #A59C75",
"s#	c #A29870",
"t#	c #A0976E",
"u#	c #9F956B",
"v#	c #9D9469",
"w#	c #9B9064",
"x#	c #9B7E58",
"y#	c #978D5E",
"z#	c #968D5C",
"A#	c #8F6744",
"B#	c #801212",
"C#	c #895035",
"D#	c #948C57",
"E#	c #928D53",
"F#	c #1D1C10",
"G#	c #494633",
"H#	c #A1986E",
"I#	c #9E956A",
"J#	c #9C9266",
"K#	c #9B9164",
"L#	c #9C392A",
"M#	c #9A1714",
"N#	c #976747",
"O#	c #968D5D",
"P#	c #968C5C",
"Q#	c #958C5B",
"R#	c #938556",
"S#	c #948B58",
"T#	c #8A5C3D",
"U#	c #928553",
"V#	c #938E54",
"W#	c #575531",
"X#	c #010101",
"Y#	c #706A4C",
"Z#	c #9B9264",
"`#	c #986C49",
" $	c #941714",
".$	c #901010",
"+$	c #925339",
"@$	c #958B5A",
"#$	c #8D573B",
"$$	c #873F2C",
"%$	c #7D1B17",
"&$	c #8F794D",
"*$	c #787444",
"=$	c #060503",
"-$	c #070705",
";$	c #79724F",
">$	c #9B9364",
",$	c #999061",
"'$	c #988F5E",
")$	c #957F54",
"!$	c #8F402D",
"~$	c #93784E",
"{$	c #948857",
"]$	c #7E1212",
"^$	c #7A1313",
"/$	c #7D2E22",
"($	c #8E764A",
"_$	c #7E7B48",
":$	c #0F0F08",
"<$	c #060604",
"[$	c #686242",
"}$	c #999060",
"|$	c #978F5D",
"1$	c #968E5C",
"2$	c #958D5A",
"3$	c #958C59",
"4$	c #948C59",
"5$	c #8D6D46",
"6$	c #907E4F",
"7$	c #948D55",
"8$	c #726F40",
"9$	c #0D0D07",
"0$	c #3B3825",
"a$	c #8B8455",
"b$	c #958E5B",
"c$	c #948E54",
"d$	c #8D8950",
"e$	c #484628",
"f$	c #030301",
"g$	c #0A0906",
"h$	c #47432B",
"i$	c #80794C",
"j$	c #85804C",
"k$	c #4F4C2D",
"l$	c #100F09",
"m$	c #19170E",
"n$	c #3A3722",
"o$	c #4F4C2E",
"p$	c #5B5635",
"q$	c #5C5735",
"r$	c #524E2F",
"s$	c #3D3B23",
"t$	c #1E1D11",
"                                                                ",
"                          . . . . . .                           ",
"                    . . . . . . . . . . . . .                   ",
"                . . . + @ # $ % & * = - ; . . .                 ",
"            . . . > , ' ) ! ~ { ] ^ / ( _ : < . . .             ",
"          . . [ } | 1 2 3 4 5 6 7 8 9 0 a b c d e . .           ",
"        . . f g h i j k l m n o p q r s t u v w x y . .         ",
"      . . z A h B C D E F G H I J K L M N O P Q R S T . .       ",
"      . [ U V W X Y Z `  ...+.@.#.$.%.&.*.=.-.;.>.,.'.)..       ",
"    . . !.B C ~.{.].^./.(._.:.<.[.}.|.1.2.3.4.5.6.7.8.9.. .     ",
"    . 0.a.b.c.Z ` d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.. .   ",
"  . . x.y.z.A.^.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.. .   ",
"  . W.X.Y.Z.`. +f..+h.++@+#+$+%+&+*+=+-+;+>+,+'+)+!+~+{+]+^+.   ",
"  . /+(+_+:+<+[+}+|+1+2+3+4+5+6+7+8+9+0+a+b+c+d+e+f+g+h+i+j+.   ",
"  . k+l+m+n+o+p+++@+q+r+s+t+u+v+w+x+y+z+A+B+C+D+E+F+G+H+I+J+. . ",
". . K+L+M+N+O+P+Q+R+S+T+U+V+W+X+Y+Z+`+ @.@+@@@#@$@%@&@*@=@-@. . ",
". . ;@K >@,@'@)@!@~@{@]@^@/@x+(@_@:@<@[@}@|@1@2@3@4@5@6@7@8@. . ",
". . 9@$.0@a@b@c@d@e@f@g@h@i@j@k@ @l@m@n@o@p@q@r@s@t@u@v@w@x@. . ",
"  . y@z@|.A@K.B@C@v+D@E@F@_@G@<@H@I@J@K@L@M@N@O@P@u@v@Q@R@S@. . ",
"  . T@U@m.V@W@X@Y@Z@`@ #.#+#@#m@##o@$#%#&#*#=#-#;#>#,#'#R@)#.   ",
"  . !#~#{#M.]#^#/#(#_#:#<#[@[#}#K@|#1#2#3#4#5#6#7#,#'#R@8#9#.   ",
"  . . 0#a#-+b#c#z+:@d#e#f###o@g#%#h#i#j#k#l#m#n#,#'#'#R@o#. .   ",
"    . p#q#r#a+s#t#u#v###w#x#|#M@2#y#z#-#A#B#C#D#,#'#R@E#F#.     ",
"    . . G#,+H#B+I#}@J#K#L#M#N#y#O#P#Q#R#S#T#U#,#'#R@V#W#. .     ",
"      . X#Y#d++@@@Z#1@%#`# $.$+$@$#$$$%$&$D#,#'#R@V#*$=$.       ",
"        . -$;$>$1@,$M@'$3#)$!$~${$]$^$/$($'#'#R@V#_$:$. .       ",
"        . . <$[$}$'$|$1$-#2$3$4$S#5$6$,#'#7$R@V#8$9$. .         ",
"          . . . 0$a$b$2$;#7#n#n#D#,#'#'#R@c$d$e$f$. .           ",
"              . . g$h$i$7#D#D#,#'#'#R@R@j$k$l$. . .             ",
"                . . . . m$n$o$p$q$r$s$t$!#. . .                 ",
"                    . . . . . . . . . . . .                     ",
"                            . . . .                             "];
class GstPlayer:
    def __init__(self, videowidget):
        self.playing = False
        self.player = gst.element_factory_make("playbin", "player")
        self.videowidget = videowidget
        self.on_eos = False

        bus = self.player.get_bus()
        bus.enable_sync_message_emission()
        bus.add_signal_watch()
        bus.connect('sync-message::element', self.on_sync_message)
        bus.connect('message', self.on_message)

    def on_sync_message(self, bus, message):
        if message.structure is None:
            return
        if message.structure.get_name() == 'prepare-xwindow-id':
            # Sync with the X server before giving the X-id to the sink
            gtk.gdk.display_get_default().sync()
            self.videowidget.set_sink(message.src)
            message.src.set_property('force-aspect-ratio', True)
            
    def on_message(self, bus, message):
        t = message.type
        if t == gst.MESSAGE_ERROR:
            err, debug = message.parse_error()
            print "Error: %s" % err, debug
            if self.on_eos:
                self.on_eos()
            self.playing = False
        elif t == gst.MESSAGE_EOS:
            if self.on_eos:
                self.on_eos()
            self.playing = False

    def set_location(self, location):
        self.player.set_property('uri', location)

    def get_location(self):
        return self.player.get_property('uri')

    def query_position(self):
        "Returns a (position, duration) tuple"
        try:
            position, format = self.player.query_position(gst.FORMAT_TIME)
        except:
            position = gst.CLOCK_TIME_NONE

        try:
            duration, format = self.player.query_duration(gst.FORMAT_TIME)
        except:
            duration = gst.CLOCK_TIME_NONE

        return (position, duration)

    def seek(self, location):
        """
        @param location: time to seek to, in nanoseconds
        """
        gst.debug("seeking to %r" % location)
        event = gst.event_new_seek(1.0, gst.FORMAT_TIME,
            gst.SEEK_FLAG_FLUSH | gst.SEEK_FLAG_ACCURATE,
            gst.SEEK_TYPE_SET, location,
            gst.SEEK_TYPE_NONE, 0)

        res = self.player.send_event(event)
        if res:
            gst.info("setting new stream time to 0")
            self.player.set_new_stream_time(0L)
        else:
            gst.error("seek to %r failed" % location)

    def pause(self):
        gst.info("pausing player")
        self.player.set_state(gst.STATE_PAUSED)
        self.playing = False

    def play(self):
        gst.info("playing player")
        self.player.set_state(gst.STATE_PLAYING)
        self.playing = True
        
    def stop(self):
        self.player.set_state(gst.STATE_NULL)
        gst.info("stopped player")
        self.playing = False

    def get_state(self, timeout=1):
        return self.player.get_state(timeout=timeout)

    def is_playing(self):
        return self.playing
    
class VideoWidget(gtk.DrawingArea):
    def __init__(self):
        gtk.DrawingArea.__init__(self)
        self.imagesink = None
        self.unset_flags(gtk.DOUBLE_BUFFERED)

    def do_expose_event(self, event):
        if self.imagesink:
            self.imagesink.expose()
            return False
        else:
            return True

    def set_sink(self, sink):
        assert self.window.xid
        self.imagesink = sink
        self.imagesink.set_xwindow_id(self.window.xid)

class PlayerWindow(gtk.Window):
    UPDATE_INTERVAL = 500
    CHANNELS =  [
            '',
            "mms://media.dhs.hinet.net/DHS?PPoint=OLYMPIC_Live120101;DHS_SESSION_ID=a82cbde6-001f-4d64-876c-f162bcb3540d",
            "mms://media.dhs.hinet.net/DHS?PPoint=OLYMPIC_Live120102;DHS_SESSION_ID=9ea3b9c2-c9ed-43f1-aac0-3894aca03dd6",
            "mms://media.dhs.hinet.net/DHS?PPoint=OLYMPIC_Live120103;DHS_SESSION_ID=eaf98861-fc22-47c5-9e56-2b0ab9d8ea70",
            "mms://media.dhs.hinet.net/DHS?PPoint=OLYMPIC_Live120104;DHS_SESSION_ID=861e0a80-eee6-4dfa-a73d-fa3320860f60",
            "mms://media.dhs.hinet.net/DHS?PPoint=OLYMPIC_Live120105;DHS_SESSION_ID=cfa1d676-eec7-4cb2-9661-5b303848dd12",
            ]

    def __init__(self):
        gtk.Window.__init__(self)
        self.set_default_size(640, 480)
        self.set_title("OLYMPIC Game Live!")
        self.set_icon(gtk.gdk.pixbuf_new_from_xpm_data(baseball_xpm))

        self.create_ui()

        self.player = GstPlayer(self.videowidget)

        def on_eos():
            self.player.seek(0L)
            self.play_toggled()

        self.player.on_eos = lambda *x: on_eos()
        
        self.update_id = -1
        self.changed_id = -1
        self.seek_timeout_id = -1

        self.p_position = gst.CLOCK_TIME_NONE
        self.p_duration = gst.CLOCK_TIME_NONE

        def on_delete_event():
            self.player.stop()
            gtk.main_quit()
        self.connect('delete-event', lambda *x: on_delete_event())

    def load_file(self, location):
        self.player.set_location(location)
             
    def create_ui(self):

        hbox1 = gtk.HBox()
        self.menu = vbox = gtk.VBox()

        self.add(hbox1)

        self.scrolledwindow = gtk.ScrolledWindow()
        self.scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        # setup for channel list.
        self.create_treeview()
        self.scrolledwindow.add(self.treeview)

        vbox.pack_start(self.scrolledwindow);
        hbox1.pack_start(vbox, False, False, 10)

        self.videowidget = VideoWidget()
        hbox1.pack_start(self.videowidget)

        hbox = gtk.HBox()
        vbox.pack_start(hbox, fill=False, expand=False)
        
        self.pause_image = gtk.image_new_from_stock(gtk.STOCK_MEDIA_PAUSE,
                                                    gtk.ICON_SIZE_BUTTON)
        self.pause_image.show()

        self.play_image = gtk.image_new_from_stock(gtk.STOCK_MEDIA_PLAY,
                                                   gtk.ICON_SIZE_BUTTON)
        self.play_image.show()

        self.fullscreen_image = gtk.image_new_from_stock(gtk.STOCK_FULLSCREEN,
                                                   gtk.ICON_SIZE_BUTTON)
        self.fullscreen_image.show()

        self.leavefs_image =  gtk.image_new_from_stock(gtk.STOCK_LEAVE_FULLSCREEN,
                                                   gtk.ICON_SIZE_BUTTON)
        self.leavefs_image.show()

        self.button = button = gtk.Button()
        button.add(self.play_image)
        button.set_property('can-default', True)
        button.set_focus_on_click(False)
        button.show()
        hbox.pack_start(button, False, False, 5)
        button.set_property('has-default', True)
        button.connect('clicked', lambda *args: self.play_toggled())

        self.fsbutton = fsbutton = gtk.Button()
        fsbutton.add(self.fullscreen_image)
        fsbutton.show()
        hbox.pack_start(fsbutton, False, False, 5)
        fsbutton.set_property('can-default', True)
        fsbutton.set_property('has-default', True)
        fsbutton.set_focus_on_click(False)
        fsbutton.connect('clicked', lambda *args: self.fullscreen_toggled())
        self.fs = False

    def create_treeview(self):
        # create a liststore with one string column to use as the model
        self.liststore = gtk.ListStore(str, str)
        # create the TreeView using liststore
        self.treeview = gtk.TreeView(self.liststore)
        # create a CellRenderer to render the data
        self.cell = gtk.CellRendererText()
        self.cell2 = gtk.CellRendererText()
        # create the TreeViewColumns to display the data
        tvcolumn = gtk.TreeViewColumn('Channels', self.cell, text=0)
        tvcolumn2 = gtk.TreeViewColumn('URL', self.cell2, text=1)
        tvcolumn2.set_visible(False)

        # Allow sorting on the column
        tvcolumn.set_sort_column_id(0)

        # add columns to treeview
        self.treeview.append_column(tvcolumn)
        self.treeview.append_column(tvcolumn2)

        # make treeview searchable
        self.treeview.set_search_column(0)

        for c in range(1, 6):
            self.liststore.append( ["Channel %s" % c, self.CHANNELS[c]])

        self.treeview.connect('cursor-changed', lambda *args: self.changeChannel())

    def changeChannel(self):
        selection = self.treeview.get_selection()
        model, iter = selection.get_selected()
        if iter:
            uri = model.get_value(iter, 1)
            if(uri !=  self.player.get_location()):
                # print "Changing channel to %s" % uri
                self.player.stop()
                self.load_file(uri)
                self.play_toggled()


    def fullscreen_toggled(self):
        self.fsbutton.remove(self.fsbutton.child)
        if (self.fs == True):
            self.fs = False
            self.fsbutton.add(self.fullscreen_image)
            self.unfullscreen()
        else:
            self.fs = True
            self.fsbutton.add(self.leavefs_image)
            self.fullscreen()

    def play_toggled(self):
        self.button.remove(self.button.child)
        if self.player.is_playing():
            self.player.pause()
            self.button.add(self.play_image)
        else:
            self.player.play()
            self.button.add(self.pause_image)

def main(args):
    def usage():
        sys.stderr.write("usage: %s" % args[0])
        sys.exit(1)

    # Need to register our derived widget types for implicit event
    # handlers to get called.
    gobject.type_register(PlayerWindow)
    gobject.type_register(VideoWidget)

    w = PlayerWindow()
    w.show_all()

    gtk.main()

if __name__ == '__main__':
    sys.exit(main(sys.argv))
