Package flumotion :: Package admin :: Package gtk :: Module spyglass
[hide private]

Source Code for Module flumotion.admin.gtk.spyglass

  1  # -*- Mode: Python -*- 
  2  # vi:si:et:sw=4:sts=4:ts=4 
  3  # 
  4  # Flumotion - a streaming media server 
  5  # Copyright (C) 2004,2005,2006,2007 Fluendo, S.L. (www.fluendo.com). 
  6  # All rights reserved. 
  7   
  8  # This file may be distributed and/or modified under the terms of 
  9  # the GNU General Public License version 2 as published by 
 10  # the Free Software Foundation. 
 11  # This file is distributed without any warranty; without even the implied 
 12  # warranty of merchantability or fitness for a particular purpose. 
 13  # See "LICENSE.GPL" in the source distribution for more information. 
 14   
 15  # Licensees having purchased or holding a valid Flumotion Advanced 
 16  # Streaming Server license may use this file in accordance with the 
 17  # Flumotion Advanced Streaming Server Commercial License Agreement. 
 18  # See "LICENSE.Flumotion" in the source distribution for more information. 
 19   
 20  # Headers in this file shall remain intact. 
 21   
 22  # FIXME: moving this down causes errors 
 23  from flumotion.common import log, pygobject 
 24   
 25  import os 
 26   
 27  import gobject 
 28  import gst 
 29  import gst.interfaces 
 30  import gtk 
 31  import gtk.glade 
 32   
 33  from flumotion.configure import configure 
 34  from flumotion.common.pygobject import gsignal 
 35   
 36  if gtk.pygtk_version < (2,3,91): 
 37      raise SystemExit, "PyGTK 2.3.91 or higher required" 
 38   
39 -def _debug(*args):
40 log.debug('spyglass', ' '.join(args))
41 42 # only Controller is to be shown in epydoc 43 __all__ = ('Controller', ) 44
45 -class Controller(gobject.GObject):
46 """ 47 Controller for a spyglass, used for viewing a video feed. 48 The controller's model takes a raw video feed as accepted by ximagesink. 49 """ 50 # FIXME: decide on a good name for prepared that says "you can do stuff with me 51 # now" 52 gsignal('prepared') 53 gsignal('focus-changed', object) 54
55 - def __init__(self):
56 """ 57 Create a new spyglass controller. 58 The spyglass controller needs to be prepared. 59 """ 60 self.__gobject_init__() 61 self.view = View() 62 self.model = Model()
63 64 ### public methods 65
66 - def prepare(self):
67 """ 68 Prepares the controller. 69 Returns immediately. 70 Emits 'prepared' signal when it is done preparing. 71 """ 72 self.view.connect('have-xid', self._view_have_xid_cb) 73 self.view.connect('focus-changed', self._view_focus_changed_cb) 74 # the view's prepare is synchronous for now 75 self.view.prepare()
76 # the model doesn't currently have a prepare 77
78 - def add_focus(self, key, description):
79 """ 80 Adds a focus point for the spyglass. 81 @type key: C{object} 82 @param key: the key for this focus point. 83 @type description: C{string} 84 @param description: the description for the focus point in the view. 85 """ 86 self.view.add_focus(key, description)
87
88 - def set_focus(self, key):
89 """ 90 Sets the focus point in the view given by the key. 91 @type key: C{object} 92 @param key: the key for the focus point. 93 """ 94 self.view.set_focus(key)
95 96 ### callbacks 97
98 - def _view_have_xid_cb(self, view, xid):
99 _debug("_view_have_xid_cb: have xid %d" % xid) 100 self.model.set_xid(xid) 101 self.emit('prepared')
102
103 - def _view_focus_changed_cb(self, view, key):
104 self.emit('focus-changed', key)
105
106 -class View(gobject.GObject):
107 gsignal('have-xid', long) 108 gsignal('focus-changed' , object) 109
110 - def __init__(self):
111 """ 112 Construct a new Spyglass View. 113 """ 114 self.__gobject_init__() 115 self._gladefile = os.path.join(configure.gladedir, 'spyglass.glade') 116 self._glade = gtk.glade.XML(self._gladefile, "spyglass-widget") 117 self._widget = self._glade.get_widget("spyglass-widget") 118 self._combo = self._glade.get_widget("spyglass-combo")
119
120 - def prepare(self):
121 # create an empty tree model for the combobox and set it there 122 self._focus_model = gtk.ListStore(str, object) 123 # hash for key -> model row mapping for quick set_focus lookup 124 self._focus_key = {} 125 self._combo.set_model(self._focus_model) 126 self._combo.connect("changed", self.view_combo_changed_cb) 127 128 # connect realize callback to drawing area so we know when to get 129 # the xid 130 area = self._glade.get_widget("spyglass-area") 131 assert(area) 132 self._expose_id = area.connect("expose-event", self.view_exposed_cb)
133
134 - def get_widget(self):
135 return self._widget
136
137 - def add_focus(self, key, description):
138 self._focus_key[key] = len(self._focus_model) 139 self._focus_model.append((description, key))
140
141 - def set_focus(self, key):
142 self._combo.set_active(self._focus_key[key])
143 144 ### callbacks 145
146 - def view_combo_changed_cb(self, combo):
147 row = self._focus_model[combo.get_active()] 148 key = row[1] 149 self.emit('focus-changed', key)
150
151 - def view_exposed_cb(self, widget, event):
152 'store our xid now that we are exposed' 153 widget.disconnect(self._expose_id) 154 self._xid = widget.window.xid 155 _debug("view_exposed_cb, got xid %d" % self._xid) 156 self.emit('have-xid', self._xid)
157
158 -class Model:
159 - def __init__(self):
160 self._sink = gst.Element('ximagesink')
161
162 - def get_element(self):
163 'Gets the element we should link and put in our main bin' 164 return self._sink
165
166 - def set_xid(self, xid):
167 # use of long is due to a pygtk bug 168 self._sink.set_xwindow_id(long(xid))
169 170 # register our types globally 171 pygobject.type_register(View) 172 pygobject.type_register(Controller) 173 174 if __name__ == '__main__':
175 - def controller_prepared_cb(controller, thread):
176 # we can set stuff to playing now 177 _debug("setting thread to PLAYING") 178 thread.set_state(gst.STATE_PLAYING)
179
180 - def controller_focus_changed_cb(controller, key, src):
181 _debug("focus changed to key %s" % key) 182 src.set_property('pattern', key)
183 184 _debug("testing") 185 186 # create fake toplevel model 187 thread = gst.Thread() 188 src = gst.Element('videotestsrc') 189 csp = gst.Element('ffmpegcolorspace') 190 191 # create our controller 192 controller = Controller() 193 controller.connect("prepared", controller_prepared_cb, thread) 194 controller.connect("focus-changed", controller_focus_changed_cb, src) 195 controller.prepare() 196 197 # add possible spyglass focuses 198 # we "fake" spyglass focuses by just changing the pattern on the 199 # same videotestsrc, using the enum value as the key 200 controller.add_focus(1, 'Snow source') 201 controller.add_focus(0, 'Snow embedded in test signal') 202 controller.add_focus(2, 'Snow in the dark') 203 # set to smpte by default 204 controller.set_focus(2) 205 206 # embed the view in our fake toplevel view 207 window = gtk.Window() 208 window.connect('destroy', gtk.main_quit) 209 window.add(controller.view.get_widget()) 210 window.show_all() 211 212 # embed the model in our fake toplevel model 213 sink = controller.model.get_element() 214 prev = None 215 for e in (src, csp, sink): 216 thread.add(e) 217 if prev: prev.link(e) 218 prev = e 219 220 _debug("going into gtk.main") 221 gtk.main() 222