#!/usr/bin/env python

import gobject
gobject.threads_init()
import gtk
gtk.gdk.threads_init()
import hildon
import gst
import sys
import os

# VideoWidget taken from play.py in gst-python examples
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 MaemoGstView:

    def __init__(self):
        if os.path.exists("/dev/video1"):
            self.model = 'N900'
        else:
            self.model = 'N8x0'

        self.zoomtoggle = False
        self.camtoggle = False
        self.restoggle = False
        self.window_in_fullscreen = False   

        # hildon has one program instance per app, so get instance
        try:
            self.p = hildon.Program.get_instance()
            self.w = hildon.StackableWindow()
            self.l = gtk.Label("No option selected")
            menu = self.create_menu(self.l)
            self.w.set_app_menu(menu)
        except:
            self.p = hildon.hildon_program_get_instance()
            self.w = hildon.Window()
        # set name of application: this shows in titlebar
        gtk.set_application_name("Mirror")
        # stackable window in case we want more windows in future in app
        box = gtk.VBox()
        self.video_widget = VideoWidget()
        # video widget we want to expand to size
        box.pack_start(self.video_widget, True, True, 0)

        self.w.connect("window-state-event", self.on_window_state_change) 
        self.w.connect("focus-out-event", self.destroy)

        self.video_widget.connect_after("button-press-event", self.on_img_clicked)
#        g_signal_connect (G_OBJECT (self.video_widget), "expose_event",
#                    G_CALLBACK (self.on_button_clicked), NULL);
        self.video_widget.add_events(gtk.gdk.BUTTON_PRESS_MASK)
        # don't want button to expand or fill, just stay finger height
#        box.pack_start(self.button, False, False, 0)
        self.w.add(box)
        self.w.connect("destroy", self.destroy)
        self.w.connect("delete-event", gtk.main_quit)
        self.p.add_window(self.w)
        self.w.show_all()
        self.start_streaming()
        self.w.connect("focus-in-event", self.in_focus)

    def menu_button_clicked(self, button, label):
        buttontext = button.get_label()
        if buttontext == "Toggle camera":
            self.camtoggle = not self.camtoggle
        elif buttontext == "Toggle wide":
            self.restoggle = not self.restoggle
        elif buttontext == "Toggle zoom":
            self.zoomtoggle = not self.zoomtoggle

#        print >>sys.stderr, "Button clicked: %s" % buttontext
        self.destroy(None)
        self.start_streaming()


    def create_menu(self, label):
        menu = hildon.AppMenu()

        options = ["Toggle zoom", "Toggle wide"]
#        if self.model == 'N900':
#            options.append("Toggle camera")

        for i in options:
            # Create menu entries
            button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
            command_id = i
            button.set_label(command_id)

            # Attach callback to clicked signal
            button.connect("clicked", self.menu_button_clicked, label)

            # Add entry to the view menu
            menu.append(button)

        menu.show_all()

        return menu

    def start_streaming(self):
        if self.model == 'N900' and not self.camtoggle:
            devno = '1'
        else:
            devno = '0'

        if self.zoomtoggle and self.restoggle:
            zoom = "videocrop top=160 left=160 right=160 bottom=160 !"
        elif self.restoggle:
            zoom = "videocrop top=60 bottom=60 !"
        elif self.zoomtoggle:
            zoom = "videocrop top=120 left=160 right=160 bottom=120 !"
        else:
            zoom = ''

        # we use ximagesink solely for screenshotting ability
        # less cpu usage would happen with videotestsrc ! xvimagesink
        self.pipeline = \
            gst.parse_launch("v4l2src device=/dev/video%s ! ffmpegcolorspace ! %s gamma gamma=2.0 ! videoflip method=4 ! xvimagesink" % (devno, zoom))

        bus = self.pipeline.get_bus()
        # need to connect to sync message handler so we get the sink to be
        # embedded at the right time and not have a temporary new window
        bus.enable_sync_message_emission()
        bus.add_signal_watch()
        bus.connect("sync-message::element", self.on_sync_message)
        bus.connect("message", self.on_message)
        self.pipeline.set_state(gst.STATE_PLAYING)

    def in_focus(self, widget, data=None):
        success, state, pending = self.pipeline.get_state(1)
        if not pending and state != gst.STATE_PLAYING:
            self.start_streaming()

    def destroy(self, widget, data=None):
        # it is important to stop pipeline so there will be no
        # X-related errors when window is destroyed before the video sink
        self.pipeline.set_state(gst.STATE_NULL)

    def on_sync_message(self, bus, message):
        if message.structure is None:
            return
        if message.structure.get_name() == 'prepare-xwindow-id':
            # all this is needed to sync with the X server before giving the
            # x id to the sink
            gtk.gdk.threads_enter()
            gtk.gdk.display_get_default().sync()
            self.video_widget.set_sink(message.src)
            message.src.set_property("force-aspect-ratio", True)
            gtk.gdk.threads_leave()

    def on_message(self, bus, message):
        if message.type == gst.MESSAGE_ERROR:
            err, debug = message.parse_error()
            hildon.hildon_banner_show_information(self.w, '', 
                                                  "Error: %s" % err)


    def on_window_state_change(self, widget, event, *args): 
        if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN: 
            self.window_in_fullscreen = True 
        else: 
            self.window_in_fullscreen = False 

    def on_img_clicked(self, widget, button):
        success, state, pending = self.pipeline.get_state(1)
        # do not listen if in middle of state change

        if self.window_in_fullscreen: 
            self.w.unfullscreen () 
        else: 
            self.w.fullscreen () 

    def on_button_clicked(self, widget):
        success, state, pending = self.pipeline.get_state(1)
        # do not listen if in middle of state change
        if not pending:
            if state == gst.STATE_PLAYING:
                self.pipeline.set_state(gst.STATE_PAUSED)
                self.button.set_label("Play")
            else:
                self.pipeline.set_state(gst.STATE_PLAYING)
                self.button.set_label("Pause")

def main():
    view = MaemoGstView()
    gtk.main()

if __name__ == '__main__':
    main()

#!/bin/sh
#gst-launch-0.10 v4l2src device=/dev/video1 ! ffmpegcolorspace ! gamma gamma=2.0 ! videoflip method=4 ! autovideosink
