Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/screencast_activity.py
diff options
context:
space:
mode:
Diffstat (limited to 'screencast_activity.py')
-rw-r--r--screencast_activity.py244
1 files changed, 244 insertions, 0 deletions
diff --git a/screencast_activity.py b/screencast_activity.py
new file mode 100644
index 0000000..86cd662
--- /dev/null
+++ b/screencast_activity.py
@@ -0,0 +1,244 @@
+# Copyright 2008 Chris Ball.
+#
+# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+"""Screencast Activity: An activity for producing XO tutorials."""
+from gettext import gettext as _
+from dbus.service import method, signal as dbus_signal
+import fcntl
+import gobject
+import gtk
+import logging
+import os
+import popen2
+import re
+import shutil
+import signal
+import sys
+
+from sugar.activity import activity
+from sugar.activity.activity import ActivityToolbox, \
+ get_bundle_path, get_bundle_name
+from sugar.graphics.alert import NotifyAlert
+from sugar.graphics.combobox import ComboBox
+
+SERVICE = "org.laptop.Screencast"
+IFACE = SERVICE
+PATH = "/org/laptop/Screencast"
+
+OUTFILE = "/tmp/recordmydesktop.ogv"
+
+class ScreencastActivity(activity.Activity):
+ """Screencast Activity as specified in activity.info"""
+ def __init__(self, handle):
+ """Set up the Screencast activity."""
+ super(ScreencastActivity, self).__init__(handle)
+ self._logger = logging.getLogger('screencast-activity')
+ self.timed_id2 = None
+
+ from sugar.graphics.menuitem import MenuItem
+ from sugar.graphics.icon import Icon
+
+ # Main layout. Record button, stop button, label.
+ hbox = gtk.HBox()
+ vbox = gtk.VBox()
+
+ # Toolbar.
+ toolbox = ActivityToolbox(self)
+ activity_toolbar = toolbox.get_activity_toolbar()
+ activity_toolbar.remove(activity_toolbar.share)
+ activity_toolbar.share = None
+ activity_toolbar.remove(activity_toolbar.keep)
+ activity_toolbar.keep = None
+ self.set_toolbox(toolbox)
+ toolbox.show()
+
+ # Recording buttons.
+ self.record = gtk.Button("Record")
+ self.record.connect("clicked", self.record_cb)
+ self.record.set_size_request(150, 150)
+ recimage = gtk.Image()
+ recimage.set_from_icon_name("media-record", -1)
+ self.record.set_image(recimage)
+ self.stop = gtk.Button("Stop")
+ self.stop.connect("clicked", self.stop_cb)
+ self.stop.set_size_request(150, 150)
+ self.stop.set_sensitive(False)
+ stopimage = gtk.Image()
+ stopimage.set_from_icon_name("media-playback-stop", -1)
+ self.stop.set_image(stopimage)
+
+ # Record sound checkbox and quality selector
+ hbox2 = gtk.HBox(spacing=50)
+ self.audiocheckbox = gtk.CheckButton(label="record sound")
+ self.audiocheckbox.set_active(True)
+ hbox2.add(self.audiocheckbox)
+ self.qualitycombo = ComboBox()
+ self.qualitycombo.append_item("0", "high quality video")
+ self.qualitycombo.append_item("1", "medium quality video")
+ self.qualitycombo.append_item("2", "low quality video")
+ self.qualitycombo.set_active(2)
+
+ hbox2.add(self.qualitycombo)
+ options = gtk.Alignment(0.5, 0, 0, 0)
+ options.add(hbox2)
+
+ # Status label.
+ self.status = gtk.Label(_("Status: Stopped"))
+
+ hbox.pack_start(self.record, expand=False, padding=40)
+ hbox.pack_start(self.stop, expand=False, padding=40)
+
+ # Encoding progress bar
+ self.progressbar=gtk.ProgressBar(adjustment=None)
+ self.progressbar.set_fraction(0)
+ self.progressbar.set_text("0% complete")
+
+ valign = gtk.Alignment(0.5, 0.4, 0, 0)
+ valign.add(vbox)
+ vbox.pack_end(self.progressbar, expand=True, padding=20)
+ vbox.pack_end(self.status, expand=True, padding=40)
+ vbox.pack_end(hbox, expand=True, fill=False)
+ vbox.pack_end(options, expand=True, padding=40)
+
+ self.set_canvas(valign)
+ self.show_all()
+ self.progressbar.hide()
+
+ def write_file (self, file_path):
+ print "Saving file to %s" % file_path
+ self.metadata['mime_type'] = 'video/ogg'
+ #try:
+ # shutil.copy(OUTFILE, file_path)
+
+ #except IOError, e:
+ # print "unable to save to outfile: %s" % e
+
+
+ # FIXME: This fails in /tmp.
+ # that comment by probably cjb
+ # I have no idea why it was saving to filepath
+ #added copy-to-journal in check_status_cb
+ #error msgs are OK probably just no video processed
+ #Tony Forster
+
+ #try:
+
+ # os.remove(OUTFILE)
+ #except OSError, e:
+ # print "unable to remove outfile: %s" % e
+
+ def can_close(self):
+ if self.status.get_text().startswith("Status: Stopped"):
+ return True
+ else:
+ self.alert("You need to finish operation before quitting.", self.status.get_text())
+
+ def alert(self, title, text=None):
+ alert = NotifyAlert(timeout=10)
+ alert.props.title = title
+ alert.props.msg = text
+ self.add_alert(alert)
+ alert.connect('response', self.alert_cancel_cb)
+ alert.show()
+
+ def alert_cancel_cb(self, alert, response_id):
+ self.remove_alert(alert)
+
+ def record_cb(self, record):
+ self.stop.set_sensitive(True)
+ self.record.set_sensitive(False)
+ self.audiocheckbox.set_sensitive(False)
+ self.qualitycombo.set_sensitive(False)
+ execargs = ["./recordmydesktop", "--no-frame", "--overwrite"]
+ if not self.audiocheckbox.get_active():
+ execargs.append("--no-sound")
+ if self.qualitycombo.get_active()==0:
+ execargs.append("-v_quality") # in later versions seems to be --v_quality instead
+ execargs.append("0")
+ elif self.qualitycombo.get_active()==1:
+ execargs.append("-v_quality") # in later versions seems to be --v_quality instead
+ execargs.append("31")
+ execargs.append("-o")
+ execargs.append(OUTFILE)
+ self.childp = popen2.Popen3(execargs, "t", 0)
+ flags = fcntl.fcntl(self.childp.childerr, fcntl.F_GETFL)
+ fcntl.fcntl(self.childp.childerr, fcntl.F_SETFL, flags|os.O_NONBLOCK)
+ flags = fcntl.fcntl(self.childp.fromchild, fcntl.F_GETFL)
+ fcntl.fcntl(self.childp.fromchild, fcntl.F_SETFL, flags|os.O_NONBLOCK)
+ self.timed_id = gobject.timeout_add(1000, self.check_status_cb)
+ self.status.set_text("Status: Recording")
+
+ def stop_cb(self, stop):
+ exitret = os.waitpid(self.childp.pid, os.WNOHANG)
+ if exitret[0] == 0:
+ os.kill(self.childp.pid, signal.SIGTERM)
+ self.stop.set_sensitive(False)
+
+ def update_counter(self):
+ self.progressbar.show()
+ while True:
+ try:
+ strstdout=self.childp.fromchild.read()
+ self.counter_fraction=float(re.search("[0-9][0-9]?[0-9]?", strstdout).group())
+ percentage=self.counter_fraction/100.0
+ if percentage>1.0:
+ percentage=1.0
+ #print "PORCENTAJE %s " % str(percentage)
+ self.progressbar.set_fraction(percentage)
+ self.progressbar.set_text("%d%%"%int(percentage*100)+' complete')
+ except IOError:
+ gtk.main_iteration(block=False)
+ except AttributeError:
+ break
+ except:
+ print "Unexpected error:", sys.exc_info()[0]
+ print "Unexpected error:", sys.exc_info()[1]
+ break
+
+ def check_status_cb(self):
+ if self.childp.pid:
+ exitret = os.waitpid(self.childp.pid, os.WNOHANG)
+ if exitret[0] != 0:
+ # The recording process exited
+ self.status.set_text("Status: Stopped")
+ if self.timed_id2:
+ gobject.source_remove(self.timed_id2)
+ self.timed_id2 = None
+ self.progressbar.hide()
+ self.alert("Success:", "Saved recording to journal")
+ self.progressbar.set_fraction(0)
+ self.progressbar.set_text('0% complete')
+ self.record.set_sensitive(True)
+ self.audiocheckbox.set_sensitive(True)
+ self.qualitycombo.set_sensitive(True)
+ if self._jobject.metadata['title_set_by_user'] == '1':
+ title = self.metadata['title']
+ else:
+ title = "My Screencast"
+ os.system("copy-to-journal /tmp/recordmydesktop.ogv -m video/ogg -t \"%s\""% title)
+ return False
+ else:
+ # Maybe we have new stderr.
+ while True:
+ try:
+ err_line = self.childp.childerr.readline()
+ if err_line.startswith("STATE:ENCODING"):
+ if not self.timed_id2:
+ self.timed_id2=gobject.timeout_add(300,self.update_counter)
+ self.status.set_text("Status: Encoding, please wait")
+ except:
+ break
+ return True