---
libreport.spec.in | 2 +
src/gui-wizard-gtk/wizard.c | 38 +++++++
src/gui-wizard-gtk/wizard.glade | 47 ++++++++-
src/plugins/Makefile.am | 5 +
src/plugins/abrt-screencast | 219 ++++++++++++++++++++++++++++++++++++++++
5 files changed, 310 insertions(+), 1 deletion(-)
create mode 100644 src/plugins/abrt-screencast
diff --git a/libreport.spec.in b/libreport.spec.in
index ff1bba5..67e6660 100644
--- a/libreport.spec.in
+++ b/libreport.spec.in
@@ -111,6 +111,7 @@ bugs
Summary: GTK front-end for libreport
Group: User Interface/Desktops
Requires: libreport = %{version}-%{release}
+Requires: recordmydesktop
Provides: report-gtk = 0:0.23-1
Obsoletes: report-gtk < 0:0.23-1
@@ -346,6 +347,7 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null ||
:
%files gtk
%defattr(-,root,root,-)
%{_bindir}/report-gtk
+%{_libexecdir}/abrt-screencast
%{_libdir}/libreport-gtk.so.*
%files gtk-devel
diff --git a/src/gui-wizard-gtk/wizard.c b/src/gui-wizard-gtk/wizard.c
index 781fd57..9d9642e 100644
--- a/src/gui-wizard-gtk/wizard.c
+++ b/src/gui-wizard-gtk/wizard.c
@@ -103,6 +103,8 @@ static GtkSpinner *g_spinner_event_log;
static GtkImage *g_img_process_fail;
static GtkImage *g_img_process_ok;
+static GtkButton *g_btn_startcast;
+
static GtkWidget *g_top_most_window;
static void add_workflow_buttons(GtkBox *box, GHashTable *workflows, GCallback func);
@@ -2931,6 +2933,7 @@ static void add_pages(void)
g_spinner_event_log = GTK_SPINNER( gtk_builder_get_object(g_builder,
"spinner_event_log"));
g_img_process_ok = GTK_IMAGE( gtk_builder_get_object(g_builder,
"img_process_ok"));
g_img_process_fail = GTK_IMAGE( gtk_builder_get_object(g_builder,
"img_process_fail"));
+ g_btn_startcast = GTK_BUTTON( gtk_builder_get_object(g_builder,
"btn_startcast"));
gtk_widget_set_no_show_all(GTK_WIDGET(g_spinner_event_log), true);
@@ -3042,6 +3045,34 @@ static void assistant_quit_cb(void *obj, void *data)
gtk_main_quit();
}
+static void on_btn_startcast(GtkWidget *btn, gpointer user_data)
+{
+ const char *args[15];
+ args[0] = "/usr/libexec/abrt-screencast";
+ args[1] = concat_path_file(g_dump_dir_name, "screencast.ogv");
+ args[2] = NULL;
+
+ pid_t castapp = 0;
+ castapp = fork_execv_on_steroids(
+ EXECFLG_QUIET,
+ (char **)args,
+ NULL,
+ /*env_vec:*/ NULL,
+ /*dir:*/ NULL,
+ /*uid (ignored):*/ 0
+ );
+ gtk_widget_hide(GTK_WIDGET(g_wnd_assistant));
+ /*flush all gui events before we start waitpid
+ * otherwise the main window wouldn't hide
+ */
+ while (gtk_events_pending())
+ gtk_main_iteration_do(false);
+
+ int status;
+ safe_waitpid(castapp, &status, 0);
+ gtk_widget_show(GTK_WIDGET(g_wnd_assistant));
+}
+
void create_assistant(bool expert_mode)
{
g_loaded_texts = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
@@ -3131,6 +3162,13 @@ void create_assistant(bool expert_mode)
g_signal_connect(g_btn_add_file, "clicked", G_CALLBACK(on_btn_add_file),
NULL);
+ /* we need to override the activate-link handler, because we use
+ * the link button instead of normal button and if wouldn't override it
+ * gtk would try to run it's defualt action and open the associated URI
+ * but since the URI is empty it would complain about it...
+ */
+ g_signal_connect(g_btn_startcast, "activate-link",
G_CALLBACK(on_btn_startcast), NULL);
+
g_signal_connect(g_search_entry_bt, "changed", G_CALLBACK(search_timeout),
NULL);
g_signal_connect (g_tv_event_log, "key-press-event", G_CALLBACK
(key_press_event), NULL);
diff --git a/src/gui-wizard-gtk/wizard.glade b/src/gui-wizard-gtk/wizard.glade
index 9a0a523..5e01887 100644
--- a/src/gui-wizard-gtk/wizard.glade
+++ b/src/gui-wizard-gtk/wizard.glade
@@ -1,6 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="stock">gtk-media-record</property>
+ </object>
<object class="GtkWindow" id="window0">
<property name="can_focus">False</property>
<child>
@@ -157,6 +162,46 @@
</packing>
</child>
<child>
+ <object class="GtkBox" id="box3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkLabel" id="label9">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">If
you don't know how to describe it, you can</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLinkButton"
id="btn_startcast">
+ <property name="label" translatable="yes">add
screencast</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="has_tooltip">True</property>
+ <property name="relief">none</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkCheckButton" id="cb_no_comment">
<property name="label" translatable="yes">I
don't know what caused this problem</property>
<property name="visible">True</property>
@@ -168,7 +213,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
- <property name="position">4</property>
+ <property name="position">5</property>
</packing>
</child>
</object>
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index f121205..0af4577 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -73,7 +73,10 @@ if BUILD_UREPORT
reporters_extra_dist += report_uReport.xml.in
endif
+PYTHON_FILES = abrt-screencast
+
EXTRA_DIST = $(reporters_extra_dist) \
+ $(PYTHON_FILES) \
report_Logger.conf \
report_Logger.xml.in \
report_Mailx.xml.in \
@@ -81,6 +84,8 @@ EXTRA_DIST = $(reporters_extra_dist) \
report_Kerneloops.xml.in \
report_Uploader.xml.in
+libexec_SCRIPTS = abrt-screencast
+
$(DESTDIR)/$(DEBUG_INFO_DIR):
$(mkdir_p) '$@'
diff --git a/src/plugins/abrt-screencast b/src/plugins/abrt-screencast
new file mode 100644
index 0000000..fe126e1
--- /dev/null
+++ b/src/plugins/abrt-screencast
@@ -0,0 +1,219 @@
+#! /usr/bin/python -u
+# -*- coding: utf-8 -*-
+# a lot of code taken from gtk-recordMyDesktop written by johnvarouhakis(a)gmail.com
+
+import os
+import locale, gettext
+import popen2
+import signal
+import sys
+import fcntl
+from reportclient import _
+import re
+from gi.repository import GLib
+from gi.repository import GObject
+from gi.repository import Gtk, Gio
+from gi.repository.Gtk import SizeGroupMode
+from gi.repository import Gdk
+
+class AbrtScreecastWindow(Gtk.Window):
+ wroot = None
+ wwidth = None
+ wheight = None
+ without_frame = False
+ save_to = None
+ recPid = None
+
+ width = None
+ height = None
+ x = None
+ y = None
+
+ progress = None
+ enc_completed = None
+
+ recorapp = None
+ # read queue
+ q = None
+
+ r = re.compile(r'.(?P<num>\d+).')
+
+ def update_counter(self, source, condition):
+ if self.recorapp.poll() != -1: # process died
+ Gtk.main_quit() #encoding finished, so just close the window
+
+ strstdout = ""
+ try:
+ c = ""
+ strstdout = ""
+ # read only until ']' - the string we're trying to read is:
+ # "[X%]" or "[XX%]"
+ while self.recorapp.poll() == -1 and c != "]":
+ c = self.recorapp.fromchild.read(1)
+ strstdout += c
+
+ except IOError, ex:
+ pass #fd is non-blocking so we ignore "Resource unavailable"
+
+ except Exception, ex:
+ print ex
+
+
+ # child process prints some escape sequences to control the output on
+ # terminal, so we need to filter it only tor ord(c) < 32, otherwise the
+ # regexp matching is not reliable
+ mpa = dict.fromkeys(range(32))
+ cleaned_str = ''.join(c for c in strstdout.strip() if ord(c) >= 32)
+ num_regexp = self.r.match(cleaned_str)
+ num = ""
+ if num_regexp:
+ num = num_regexp.group("num")
+
+ if not num:
+ return True
+
+ self.enc_completed=float(num)
+ percentage=self.enc_completed/100.0
+ if percentage>1.0 or (self.recorapp.poll() != -1):
+ percentage=1.0
+
+ self.progress.set_fraction(percentage)
+ self.progress.set_text(_("Encoding: {0!s}%
complete").format(self.enc_completed))
+ return True
+
+ def __init__(self, save_to):
+ self.save_to = save_to
+ Gtk.Window.__init__(self)
+ buttons_size_group = Gtk.SizeGroup(SizeGroupMode.BOTH)
+ main_vbox = Gtk.VBox()
+ main_hbox = Gtk.HBox()
+ self.add(main_vbox)
+ self.set_decorated(False)
+ self.wroot = Gdk.get_default_root_window()
+ self.wwidth = self.wroot.get_width()
+ self.wheight = self.wroot.get_height()
+
+ #progress bar
+ self.progress = Gtk.ProgressBar()
+ self.progress.set_no_show_all(True)
+
+ #stop button
+ stop_button = Gtk.Button(stock=Gtk.STOCK_MEDIA_STOP)
+ stop_button.connect("clicked", self.__stop_recording__)
+ stop_button.set_sensitive(False)
+ buttons_size_group.add_widget(stop_button)
+ main_hbox.pack_start(stop_button, False, False, 0)
+
+ #start button
+ rec_button = Gtk.Button(stock=Gtk.STOCK_MEDIA_RECORD)
+ rec_button.connect("clicked", self.__start_recording__, stop_button)
+ # have to select window first
+ rec_button.set_sensitive(False)
+ buttons_size_group.add_widget(rec_button)
+ main_hbox.pack_start(rec_button, False, False, 0)
+
+ # select button
+ select_button = Gtk.Button(_("Select window"))
+ select_button.connect("clicked", self.__select_window__, rec_button)
+ buttons_size_group.add_widget(select_button)
+ main_hbox.pack_start(select_button, False, False, 0)
+
+ # close button
+ close_button = Gtk.Button(stock=Gtk.STOCK_CLOSE)
+ close_button.connect("clicked", Gtk.main_quit)
+ buttons_size_group.add_widget(close_button)
+ main_hbox.pack_start(close_button, False, False, 0)
+
+ main_vbox.pack_start(main_hbox, True, True, 0)
+ main_vbox.pack_start(self.progress, True, True, 0)
+
+ self.connect("destroy", Gtk.main_quit)
+
+ def __start_recording__(self, button, stop_button):
+ args = [
+ "recordmydesktop",
+ "-o",
+ self.save_to,
+ "--fps",
+ "5",
+ "--no-sound",
+ "--width",
+ str(self.width),
+ "--height",
+ str(self.height),
+ "--v_quality",
+ "50",
+ "--workdir",
+ "/tmp",
+ "-x", str(self.x),
+ "-y", str(self.y)
+ ]
+
+ self.recorapp = popen2.Popen3(args, True, 0)
+ flags = fcntl.fcntl(self.recorapp.fromchild, fcntl.F_GETFL)
+ fcntl.fcntl(self.recorapp.fromchild, fcntl.F_SETFL, flags | os.O_NONBLOCK)
+
+ self.recPid = self.recorapp.pid
+ if self.recPid != None:
+ stop_button.set_sensitive(True)
+ button.set_sensitive(False)
+
+ def __stop_recording__(self, button):
+ os.kill(self.recPid,signal.SIGINT)
+ button.set_sensitive(False)
+ self.progress.set_visible(True)
+
+ giochannel = GLib.IOChannel(filedes=self.recorapp.fromchild.fileno())
+ giochannel.add_watch(GLib.IO_IN|GLib.IO_HUP, self.update_counter)
+
+ def __select_window__(self, button, start_button):
+ xwininfo_com=['xwininfo','-frame']
+ if self.without_frame == True:
+ xwininfo_com=['xwininfo']
+
+ (stdin,stdout,stderr)=os.popen3(xwininfo_com, 't')
+ wid=stdout.readlines()
+ stdin.close()
+ stdout.close()
+ stderr.close()
+ x = y = width = height = None
+ for i in wid:
+ if i.lstrip().startswith('Absolute upper-left X:'):
+ x=int(i.split(' ')[len(i.split(' '))-1])
+ elif i.lstrip().startswith('Absolute upper-left Y'):
+ y=int(i.split(' ')[len(i.split(' '))-1])
+ elif i.lstrip().startswith('Width:'):
+ width=int(i.split(' ')[len(i.split(' '))-1])
+ elif i.lstrip().startswith('Height:'):
+ height=int(i.split(' ')[len(i.split(' '))-1])
+
+ if x <= 0:
+ width += x
+ x = 1 #recordmydesktop accepts only values > 0
+ if y <= 0:
+ height += y
+ y = 1
+ if width + x > self.wwidth:
+ width = self.wwidth - x
+ if height + y > self.wheight:
+ height = self.wheight - y
+ self.x = x
+ self.y = y
+ self.width = width
+ self.height = height
+
+ #print self.x, self.y, self.width, self.height
+
+ start_button.set_sensitive(True)
+
+ def _show_all(self):
+ self.show_all()
+ width, height = self.get_size()
+ self.move(self.wwidth - (width + 50), self.wheight - (height + 50))
+
+
+if __name__ == "__main__":
+ output_file = sys.argv[1]
+ w = AbrtScreecastWindow(save_to=output_file)
+ w._show_all()
+ Gtk.main()
--
1.8.0.1