[Reportbug-commits] [reportbug] 19/31: gtk2_ui: Add assertions that we are in the intended thread
Sandro Tosi
morph at moszumanska.debian.org
Mon Jan 16 01:36:57 UTC 2017
This is an automated email from the git hooks/post-receive script.
morph pushed a commit to branch master
in repository reportbug.
commit ba22b46b01e593f4d8842e264d95df27cc736915
Author: Simon McVittie <smcv at debian.org>
Date: Sat Jan 14 19:32:50 2017 +0000
gtk2_ui: Add assertions that we are in the intended thread
---
reportbug/ui/gtk2_ui.py | 171 ++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 166 insertions(+), 5 deletions(-)
diff --git a/reportbug/ui/gtk2_ui.py b/reportbug/ui/gtk2_ui.py
index fbc4133..5a5e92c 100644
--- a/reportbug/ui/gtk2_ui.py
+++ b/reportbug/ui/gtk2_ui.py
@@ -76,6 +76,27 @@ global application, assistant, report_message, reportbug_context, ui_context
# Utilities
+def _describe_context(context):
+ if context == ui_context:
+ return '<MainContext of UI thread>'
+ elif context == reportbug_context:
+ return '<MainContext of reportbug thread>'
+ else:
+ return repr(context)
+
+
+def _assert_context(expected):
+ really = GLib.MainContext.ref_thread_default()
+
+ # This compares by pointer value of the underlying GMainContext
+ if really != expected:
+ raise AssertionError('Function should be called in %s but was called in %s' %
+ (_describe_context(really), _describe_context(expected)))
+
+ if not really.is_owner():
+ raise AssertionError('Function should be called with %s acquired')
+
+
def highlight(s):
return '<b>%s</b>' % s
@@ -94,6 +115,7 @@ def ask_free(s):
def create_scrollable(widget, with_viewport=False):
+ _assert_context(ui_context)
scrolled = Gtk.ScrolledWindow()
scrolled.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
scrolled.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
@@ -105,6 +127,7 @@ def create_scrollable(widget, with_viewport=False):
def info_dialog(message):
+ _assert_context(ui_context)
dialog = Gtk.MessageDialog(assistant, Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
Gtk.MessageType.INFO, Gtk.ButtonsType.CLOSE, message)
dialog.connect('response', lambda d, *args: d.destroy())
@@ -113,6 +136,7 @@ def info_dialog(message):
def error_dialog(message):
+ _assert_context(ui_context)
dialog = Gtk.MessageDialog(assistant, Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, message)
dialog.connect('response', lambda d, *args: d.destroy())
@@ -122,6 +146,7 @@ def error_dialog(message):
class CustomDialog(Gtk.Dialog):
def __init__(self, stock_image, message, buttons, *args, **kwargs):
+ _assert_context(ui_context)
Gtk.Dialog.__init__(self, "Reportbug", assistant,
Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
buttons)
@@ -155,15 +180,18 @@ class CustomDialog(Gtk.Dialog):
class InputStringDialog(CustomDialog):
def __init__(self, message):
+ _assert_context(ui_context)
CustomDialog.__init__(self, Gtk.STOCK_DIALOG_INFO, message,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT))
def setup_dialog(self, vbox):
+ _assert_context(ui_context)
self.entry = Gtk.Entry()
vbox.pack_start(self.entry, False, True, 0)
def get_value(self):
+ _assert_context(ui_context)
return self.entry.get_text()
@@ -171,7 +199,9 @@ class ExceptionDialog(CustomDialog):
# Register an exception hook to display an error when the GUI breaks
@classmethod
def create_excepthook(cls, oldhook):
+ _assert_context(reportbug_context)
def excepthook(exctype, value, tb):
+ # OK to call from any thread
if oldhook:
oldhook(exctype, value, tb)
application.run_once_in_main_thread(cls.start_dialog,
@@ -180,6 +210,7 @@ class ExceptionDialog(CustomDialog):
@classmethod
def start_dialog(cls, tb):
+ _assert_context(ui_context)
try:
dialog = cls(tb)
dialog.show_all()
@@ -187,6 +218,7 @@ class ExceptionDialog(CustomDialog):
sys.exit(1)
def __init__(self, tb):
+ _assert_context(ui_context)
CustomDialog.__init__(self, Gtk.STOCK_DIALOG_ERROR, "An error has occurred while doing an operation in Reportbug.\nPlease report the bug.", (Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE), tb)
def setup_dialog(self, vbox, tb):
@@ -203,11 +235,13 @@ class ExceptionDialog(CustomDialog):
self.connect('response', self.on_response)
def on_response(self, dialog, res):
+ _assert_context(ui_context)
sys.exit(1)
class ReportViewerDialog(Gtk.Dialog):
def __init__(self, message):
+ _assert_context(ui_context)
Gtk.Dialog.__init__(self, "Reportbug", assistant,
Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
(Gtk.STOCK_COPY, Gtk.ResponseType.APPLY,
@@ -226,6 +260,7 @@ class ReportViewerDialog(Gtk.Dialog):
self.show_all()
def on_response(self, dialog, res):
+ _assert_context(ui_context)
# ok Gtk.ResponseType.APPLY is ugly for Gtk.STOCK_COPY, but who cares?
# maybe adding it as a secondary button or such is better
if res == Gtk.ResponseType.APPLY:
@@ -344,6 +379,7 @@ class BugReport(object):
# BTS GUI
class BugPage(Gtk.EventBox, threading.Thread):
def __init__(self, assistant, dialog, number, queryonly, bts, mirrors, http_proxy, timeout, archived):
+ _assert_context(ui_context)
threading.Thread.__init__(self)
Gtk.EventBox.__init__(self)
self.setDaemon(True)
@@ -390,21 +426,25 @@ class BugPage(Gtk.EventBox, threading.Thread):
self.application.run_once_in_main_thread(self.found, info)
def drop_progressbar(self):
+ _assert_context(ui_context)
child = self.get_child()
if child:
self.remove(child)
child.unparent()
def pulse(self):
+ _assert_context(ui_context)
self.progress.pulse()
return self.isAlive()
def not_found(self):
+ _assert_context(ui_context)
self.drop_progressbar()
self.add(Gtk.Label("The bug can't be fetched or it doesn't exist."))
self.show_all()
def found(self, info):
+ _assert_context(ui_context)
self.drop_progressbar()
desc = info[0].subject
bodies = info[1]
@@ -443,9 +483,11 @@ class BugPage(Gtk.EventBox, threading.Thread):
self.show_all()
def on_open_browser(self, button):
+ _assert_context(ui_context)
launch_browser(debbugs.get_report_url(self.bts, int(self.number), self.archived))
def on_reply(self, button):
+ _assert_context(ui_context)
# Return the bug number to reportbug
self.application.set_next_value(self.bug_status)
# Forward the assistant to the progress bar
@@ -457,6 +499,7 @@ class BugPage(Gtk.EventBox, threading.Thread):
class BugsDialog(Gtk.Dialog):
def __init__(self, assistant, queryonly):
+ _assert_context(ui_context)
Gtk.Dialog.__init__(self, "Reportbug: bug information", assistant,
Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
(Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE))
@@ -498,24 +541,33 @@ class ReportbugApplication(threading.Thread):
Gdk.threads_leave()
def get_last_value(self):
+ _assert_context(reportbug_context)
return self.queue.get()
def put_next_value(self):
+ _assert_context(ui_context)
self.queue.put(self.next_value)
self.next_value = None
def set_next_value(self, value):
+ _assert_context(ui_context)
self.next_value = value
def run_once_in_main_thread(self, func, *args, **kwargs):
+ # OK to call from any thread
+
def callback():
+ _assert_context(ui_context)
func(*args, **kwargs)
return False
GLib.idle_add(callback)
def call_in_main_thread(self, func, *args, **kwargs):
+ # OK to call from any thread
+
def callback():
+ _assert_context(ui_context)
try:
ret = func(*args, **kwargs)
except BaseException as e:
@@ -539,18 +591,20 @@ class ReportbugApplication(threading.Thread):
# Syncronize "pipe" with reportbug
class SyncReturn(RuntimeError):
def __init__(self, result):
+ _assert_context(reportbug_context)
RuntimeError.__init__(self, result)
self.result = result
class ReportbugConnector(object):
- # Executed in the glib thread
def execute_operation(self, *args, **kwargs):
+ _assert_context(ui_context)
pass
# Executed in sync with reportbug. raise SyncResult(value) to directly return to reportbug
# Returns args and kwargs to pass to execute_operation
def sync_pre_operation(cls, *args, **kwargs):
+ _assert_context(reportbug_context)
return args, kwargs
@@ -563,6 +617,7 @@ class Page(ReportbugConnector):
WARNING_COLOR = Gdk.color_parse("#fff8ae")
def __init__(self, assistant):
+ _assert_context(ui_context)
self.assistant = assistant
self.application = assistant.application
self.widget = self.create_widget()
@@ -572,6 +627,7 @@ class Page(ReportbugConnector):
self.page_num = Page.next_page_num
def execute_operation(self, *args, **kwargs):
+ _assert_context(ui_context)
self.switch_in()
self.connect_signals()
self.empty_ok = kwargs.pop('empty_ok', False)
@@ -581,20 +637,24 @@ class Page(ReportbugConnector):
self.setup_focus()
def connect_signals(self):
- pass
+ _assert_context(ui_context)
def set_page_complete(self, complete):
+ _assert_context(ui_context)
self.assistant.set_page_complete(self.widget, complete)
def set_page_type(self, type):
+ _assert_context(ui_context)
self.assistant.set_page_type(self.widget, type)
def set_page_title(self, title):
+ _assert_context(ui_context)
if title:
self.assistant.set_page_title(self.widget, title)
# The user will see this as next page
def switch_in(self):
+ _assert_context(ui_context)
Page.next_page_num += 1
self.assistant.insert_page(self.widget, self.page_num)
self.set_page_complete(self.default_complete)
@@ -605,24 +665,30 @@ class Page(ReportbugConnector):
# Setup keyboard focus in the page
def setup_focus(self):
+ _assert_context(ui_context)
self.widget.grab_focus()
# Forward page when a widget is activated(e.g. GtkEntry) only if page is complete
def activate_forward(self, *args):
+ _assert_context(ui_context)
if self.assistant.get_page_complete(self.widget):
self.assistant.forward_page()
# The user forwarded the assistant to see the next page
def switch_out(self):
- pass
+ _assert_context(ui_context)
def is_valid(self, value):
+ _assert_context(ui_context)
+
if self.empty_ok:
return True
else:
return bool(value)
def validate(self, *args, **kwargs):
+ _assert_context(ui_context)
+
value = self.get_value()
if self.is_valid(value):
self.application.set_next_value(value)
@@ -636,6 +702,8 @@ class IntroPage(Page):
default_complete = True
def create_widget(self):
+ _assert_context(ui_context)
+
vbox = Gtk.VBox(spacing=24)
label = Gtk.Label("""
@@ -657,9 +725,11 @@ This wizard will guide you through the bug reporting process step by step.
class GetStringPage(Page):
def setup_focus(self):
+ _assert_context(ui_context)
self.entry.grab_focus()
def create_widget(self):
+ _assert_context(ui_context)
vbox = Gtk.VBox(spacing=12)
self.label = Gtk.Label()
self.label.set_line_wrap(True)
@@ -672,13 +742,16 @@ class GetStringPage(Page):
return vbox
def connect_signals(self):
+ _assert_context(ui_context)
self.entry.connect('changed', self.validate)
self.entry.connect('activate', self.activate_forward)
def get_value(self):
+ _assert_context(ui_context)
return self.entry.get_text()
def execute(self, prompt, options=None, force_prompt=False, default=''):
+ _assert_context(ui_context)
# Hackish: remove the text needed for textual UIs...
GLib.idle_add(self.label.set_text, prompt.replace('(enter Ctrl+c to exit reportbug without reporting a bug)', ''))
self.entry.set_text(default)
@@ -701,6 +774,7 @@ class GetStringPage(Page):
class GetPasswordPage(GetStringPage):
def create_widget(self):
+ _assert_context(ui_context)
widget = GetStringPage.create_widget(self)
self.entry.set_visibility(False)
return widget
@@ -708,9 +782,11 @@ class GetPasswordPage(GetStringPage):
class GetMultilinePage(Page):
def setup_focus(self):
+ _assert_context(ui_context)
self.view.grab_focus()
def create_widget(self):
+ _assert_context(ui_context)
vbox = Gtk.VBox(spacing=12)
self.label = Gtk.Label()
self.label.set_line_wrap(True)
@@ -726,9 +802,11 @@ class GetMultilinePage(Page):
return vbox
def connect_signals(self):
+ _assert_context(ui_context)
self.buffer.connect('changed', self.validate)
def get_value(self):
+ _assert_context(ui_context)
text = self.buffer.get_text(self.buffer.get_start_iter(), self.buffer.get_end_iter())
lines = text.split('\n')
# Remove the trailing empty line at the end
@@ -737,6 +815,7 @@ class GetMultilinePage(Page):
return text.split('\n')
def execute(self, prompt):
+ _assert_context(ui_context)
self.empty_ok = True
# The result must be iterable for reportbug even if it's empty and not modified
GLib.idle_add(self.label.set_text, prompt)
@@ -748,16 +827,20 @@ class TreePage(Page):
value_column = None
def __init__(self, *args, **kwargs):
+ _assert_context(ui_context)
Page.__init__(self, *args, **kwargs)
self.selection = self.view.get_selection()
def setup_focus(self):
+ _assert_context(ui_context)
self.view.grab_focus()
def connect_signals(self):
+ _assert_context(ui_context)
self.selection.connect('changed', self.validate)
def get_value(self):
+ _assert_context(ui_context)
model, paths = self.selection.get_selected_rows()
multiple = self.selection.get_mode() == Gtk.SelectionMode.MULTIPLE
result = []
@@ -774,6 +857,7 @@ class GetListPage(TreePage):
value_column = 0
def create_widget(self):
+ _assert_context(ui_context)
vbox = Gtk.VBox(spacing=12)
self.label = Gtk.Label()
self.label.set_line_wrap(True)
@@ -803,22 +887,26 @@ class GetListPage(TreePage):
return vbox
def get_value(self):
+ _assert_context(ui_context)
values = []
for row in self.model:
values.append(row[self.value_column])
return values
def on_add(self, button):
+ _assert_context(ui_context)
dialog = InputStringDialog("Add a new item to the list")
dialog.show_all()
dialog.connect('response', self.on_add_dialog_response)
def on_add_dialog_response(self, dialog, res):
+ _assert_context(ui_context)
if res == Gtk.ResponseType.ACCEPT:
self.model.append([dialog.get_value()])
dialog.destroy()
def on_remove(self, button):
+ _assert_context(ui_context)
model, paths = self.selection.get_selected_rows()
# We need to transform them to iters, since paths change when removing rows
iters = []
@@ -828,6 +916,7 @@ class GetListPage(TreePage):
self.model.remove(iter)
def execute(self, prompt):
+ _assert_context(ui_context)
self.empty_ok = True
GLib.idle_add(self.label.set_text, prompt)
@@ -843,6 +932,7 @@ class GetListPage(TreePage):
class WrapRendererText(Gtk.CellRendererText):
def do_render(self, cr, widget, background_area, cell_area, flags):
+ _assert_context(ui_context)
self.set_property('wrap-width', cell_area.width)
Gtk.CellRendererText.do_render(self, cr, widget, background_area, cell_area, flags)
@@ -854,6 +944,7 @@ class MenuPage(TreePage):
value_column = 0
def create_widget(self):
+ _assert_context(ui_context)
vbox = Gtk.VBox(spacing=12)
self.label = Gtk.Label()
self.label.set_line_wrap(True)
@@ -869,11 +960,13 @@ class MenuPage(TreePage):
return vbox
def connect_signals(self):
+ _assert_context(ui_context)
TreePage.connect_signals(self)
self.view.connect('row-activated', self.activate_forward)
def execute(self, par, options, prompt, default=None, any_ok=False,
order=None, extras=None, multiple=False):
+ _assert_context(ui_context)
GLib.idle_add(self.label.set_text, par)
self.model = Gtk.ListStore(str, str)
@@ -923,6 +1016,7 @@ class HandleBTSQueryPage(TreePage):
def sync_pre_operation(self, package, bts, timeout, mirrors=None, http_proxy="", queryonly=False, screen=None,
archived='no', source=False, title=None,
version=None, buglist=None, mbox_reader_cmd=None, latest_first=False):
+ _assert_context(reportbug_context)
self.bts = bts
self.mirrors = mirrors
self.http_proxy = http_proxy
@@ -989,9 +1083,11 @@ class HandleBTSQueryPage(TreePage):
raise SyncReturn(None)
def setup_focus(self):
+ _assert_context(ui_context)
self.entry.grab_focus()
def create_widget(self):
+ _assert_context(ui_context)
vbox = Gtk.VBox(spacing=6)
self.label = Gtk.Label("List of bugs. Select a bug to retrieve and submit more information.")
vbox.pack_start(self.label, False, True, 6)
@@ -1026,18 +1122,22 @@ class HandleBTSQueryPage(TreePage):
return vbox
def connect_signals(self):
+ _assert_context(ui_context)
TreePage.connect_signals(self)
self.view.connect('row-activated', self.on_retrieve_info)
self.entry.connect('changed', self.on_filter_changed)
def on_filter_clear(self, button):
+ _assert_context(ui_context)
self.entry.set_text("")
def on_filter_changed(self, entry):
+ _assert_context(ui_context)
self.model.filter_text = entry.get_text().lower()
self.filter.refilter()
def on_retrieve_info(self, *args):
+ _assert_context(ui_context)
bug_ids = TreePage.get_value(self)
if not bug_ids:
info_dialog("Please select one ore more bugs")
@@ -1049,13 +1149,16 @@ class HandleBTSQueryPage(TreePage):
dialog.show_all()
def is_valid(self, value):
+ _assert_context(ui_context)
return True
def get_value(self):
+ _assert_context(ui_context)
# The value returned to reportbug doesn't depend by a selection, but by the dialog of a bug
return None
def match_filter(self, iter):
+ _assert_context(ui_context)
# Flatten the columns into a single string
text = ""
for col in range(len(self.columns)):
@@ -1071,6 +1174,7 @@ class HandleBTSQueryPage(TreePage):
return False
def filter_visible_func(self, model, iter, user_data=None):
+ _assert_context(ui_context)
matches = self.match_filter(iter)
if not self.model.iter_parent(iter) and not matches:
# If no children are visible, hide it
@@ -1084,6 +1188,7 @@ class HandleBTSQueryPage(TreePage):
return matches
def execute(self, buglist, sectitle):
+ _assert_context(ui_context)
GLib.idle_add(self.label.set_text, "%s. Double-click a bug to retrieve and submit more information." % sectitle)
self.model = Gtk.TreeStore(*([str] * len(self.columns)))
@@ -1106,21 +1211,26 @@ class ShowReportPage(Page):
default_complete = True
def create_widget(self):
+ _assert_context(ui_context)
self.page = BugPage(self.assistant, None, None, None, None, None, None, None, None)
return self.page
def get_value(self):
+ _assert_context(ui_context)
return None
def is_valid(self, value):
+ _assert_context(ui_context)
return True
def sync_pre_operation(self, *args, **kwargs):
+ _assert_context(reportbug_context)
if kwargs.get('queryonly'):
self.page_type = Gtk.AssistantPageType.CONFIRM
return args, kwargs
def execute(self, number, system, mirrors, http_proxy, timeout, queryonly=False, title='', archived='no', mbox_reader_cmd=None):
+ _assert_context(ui_context)
self.page.number = number
self.page.bts = system
self.page.mirrors = mirrors
@@ -1136,12 +1246,14 @@ class DisplayReportPage(Page):
default_complete = True
def create_widget(self):
+ _assert_context(ui_context)
self.view = Gtk.TextView()
self.view.set_editable(False)
scrolled = create_scrollable(self.view)
return scrolled
def execute(self, message, *args):
+ _assert_context(ui_context)
# 'use' args only if it's passed
if args:
message = message % args
@@ -1152,6 +1264,7 @@ class LongMessagePage(Page):
default_complete = True
def create_widget(self):
+ _assert_context(ui_context)
self.label = Gtk.Label()
self.label.set_line_wrap(True)
self.label.set_justify(Gtk.Justification.FILL)
@@ -1162,6 +1275,7 @@ class LongMessagePage(Page):
return eb
def execute(self, message, *args):
+ _assert_context(ui_context)
message = message % args
# make it all on one line, it will be wrapped at display-time
message = ' '.join(message.split())
@@ -1177,12 +1291,14 @@ class FinalMessagePage(LongMessagePage):
default_complete = True
def execute(self, *args, **kwargs):
+ _assert_context(ui_context)
LongMessagePage.execute(self, *args, **kwargs)
self.set_page_title("Thanks for your report")
class EditorPage(Page):
def create_widget(self):
+ _assert_context(ui_context)
vbox = Gtk.VBox(spacing=6)
hbox = Gtk.HBox(spacing=12)
hbox.pack_start(Gtk.Label("Subject: "), False, True, 0)
@@ -1222,16 +1338,19 @@ class EditorPage(Page):
def switch_out(self):
global report_message
+ _assert_context(ui_context)
report_message = self.get_value()[0]
f = open(self.filename, "w")
f.write(report_message)
f.close()
def connect_signals(self):
+ _assert_context(ui_context)
self.info_buffer.connect('changed', self.validate)
self.subject.connect('changed', self.validate)
def get_value(self):
+ _assert_context(ui_context)
info = self.info_buffer.get_text(self.info_buffer.get_start_iter(),
self.info_buffer.get_end_iter())
if not info.strip():
@@ -1245,14 +1364,17 @@ class EditorPage(Page):
return(message, message != self.message)
def handle_first_info(self):
+ _assert_context(ui_context)
self.focus_in_id = self.view.connect('focus-in-event', self.on_view_focus_in_event)
def on_view_focus_in_event(self, view, *args):
+ _assert_context(ui_context)
# Empty the buffer only the first time
self.info_buffer.set_text("")
view.disconnect(self.focus_in_id)
def execute(self, message, filename, editor, charset='utf-8'):
+ _assert_context(ui_context)
self.message = message
self.report = BugReport(message)
self.filename = filename
@@ -1271,6 +1393,7 @@ class SelectOptionsPage(Page):
default_complete = False
def create_widget(self):
+ _assert_context(ui_context)
self.label = Gtk.Label()
self.label.set_line_wrap(True)
self.label.set_justify(Gtk.Justification.FILL)
@@ -1280,14 +1403,17 @@ class SelectOptionsPage(Page):
return self.vbox
def on_clicked(self, button, menuopt):
+ _assert_context(ui_context)
self.application.set_next_value(menuopt)
self.assistant.forward_page()
def on_display_clicked(self, button):
global report_message
+ _assert_context(ui_context)
ReportViewerDialog(report_message)
def setup_focus(self):
+ _assert_context(ui_context)
if self.default:
self.default.props.can_default = True
self.default.props.has_default = True
@@ -1295,6 +1421,7 @@ class SelectOptionsPage(Page):
self.default.grab_focus()
def execute(self, prompt, menuopts, options):
+ _assert_context(ui_context)
# remove text UI indication
prompt = prompt.replace('(e to edit)', '')
GLib.idle_add(self.label.set_text, prompt)
@@ -1336,6 +1463,7 @@ class SystemPage(Page):
default_complete = False
def create_widget(self):
+ _assert_context(ui_context)
hbox = Gtk.HBox()
self.terminal = Vte.Terminal()
@@ -1351,10 +1479,12 @@ class SystemPage(Page):
return hbox
def on_child_exited(self, terminal):
+ _assert_context(ui_context)
self.application.set_next_value(None)
self.assistant.forward_page()
def execute(self, cmdline):
+ _assert_context(ui_context)
self.terminal.fork_command('/bin/bash', ['/bin/bash', '-c', cmdline])
@@ -1362,10 +1492,12 @@ class ProgressPage(Page):
page_type = Gtk.AssistantPageType.PROGRESS
def pulse(self):
+ _assert_context(ui_context)
self.progress.pulse()
return True
def create_widget(self):
+ _assert_context(ui_context)
vbox = Gtk.VBox(spacing=6)
self.label = Gtk.Label()
self.label.set_line_wrap(True)
@@ -1378,14 +1510,17 @@ class ProgressPage(Page):
return vbox
def set_label(self, text):
+ _assert_context(ui_context)
GLib.idle_add(self.label.set_text, text)
def reset_label(self):
+ _assert_context(ui_context)
self.set_label("This operation may take a while")
class ReportbugAssistant(Gtk.Assistant):
def __init__(self, application):
+ _assert_context(ui_context)
Gtk.Assistant.__init__(self)
self.application = application
@@ -1400,6 +1535,7 @@ class ReportbugAssistant(Gtk.Assistant):
self.setup_pages()
def _hack_buttons(self, widget):
+ _assert_context(ui_context)
# This is a real hack for two reasons:
# 1. There's no other way to access action area but inspecting the assistant and searching for the back button
# 2. Hide back button on show, because it can be shown-hidden by the assistant depending on the page
@@ -1426,18 +1562,22 @@ class ReportbugAssistant(Gtk.Assistant):
widget.forall(self._hack_buttons)
def hack_buttons(self):
+ _assert_context(ui_context)
self._hack_buttons(self)
def connect_signals(self):
+ _assert_context(ui_context)
self.connect('cancel', self.confirm_exit)
self.connect('prepare', self.on_prepare)
self.connect('delete-event', self.close)
self.connect('apply', self.close)
def on_back_show(self, widget):
+ _assert_context(ui_context)
widget.hide()
def on_prepare(self, assistant, widget):
+ _assert_context(ui_context)
# If the user goes back then forward, we must ensure the feedback value to reportbug must be sent
# when the user clicks on "Forward" to the requested page by reportbug
if self.showing_page and self.showing_page == self.requested_page and self.get_current_page() > self.showing_page.page_num:
@@ -1454,9 +1594,11 @@ class ReportbugAssistant(Gtk.Assistant):
GLib.idle_add(self.showing_page.setup_focus)
def close(self, *args):
+ _assert_context(ui_context)
sys.exit(0)
def confirm_exit(self, *args):
+ _assert_context(ui_context)
dialog = Gtk.MessageDialog(None, Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
Gtk.MessageType.WARNING, Gtk.ButtonsType.YES_NO,
"Are you sure you want to quit Reportbug?")
@@ -1466,22 +1608,26 @@ class ReportbugAssistant(Gtk.Assistant):
sys.exit(0)
def forward(self, page_num):
+ _assert_context(ui_context)
return page_num + 1
def forward_page(self):
+ _assert_context(ui_context)
self.set_current_page(self.forward(self.showing_page.page_num))
def set_next_page(self, page):
+ _assert_context(ui_context)
self.requested_page = page
# If we're in progress immediately show this guy
if self.showing_page == self.progress_page:
self.set_current_page(page.page_num)
- # Called in UI thread
def set_progress_label(self, text, *args, **kwargs):
+ _assert_context(ui_context)
self.progress_page.set_label(text % args)
def setup_pages(self):
+ _assert_context(ui_context)
# We insert pages between the intro and the progress, so that we give the user the feedback
# that the applications is still running when he presses the "Forward" button
self.showing_page = IntroPage(self)
@@ -1494,17 +1640,20 @@ class ReportbugAssistant(Gtk.Assistant):
# Dialogs
class YesNoDialog(ReportbugConnector, Gtk.MessageDialog):
def __init__(self, application):
+ _assert_context(ui_context)
Gtk.MessageDialog.__init__(self, assistant, Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO)
self.application = application
self.connect('response', self.on_response)
def on_response(self, dialog, res):
+ _assert_context(ui_context)
self.application.set_next_value(res == Gtk.ResponseType.YES)
self.application.put_next_value()
self.destroy()
def execute_operation(self, msg, yeshelp=None, nohelp=None, default=True, nowrap=False):
+ _assert_context(ui_context)
self.set_markup(msg)
if default:
self.set_default_response(Gtk.ResponseType.YES)
@@ -1515,28 +1664,33 @@ class YesNoDialog(ReportbugConnector, Gtk.MessageDialog):
class DisplayFailureDialog(ReportbugConnector, Gtk.MessageDialog):
def __init__(self, application):
+ _assert_context(ui_context)
Gtk.MessageDialog.__init__(self, assistant, Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
Gtk.MessageType.WARNING, Gtk.ButtonsType.CLOSE)
self.application = application
self.connect('response', self.on_response)
def on_response(self, dialog, res):
+ _assert_context(ui_context)
self.application.put_next_value()
self.destroy()
def execute_operation(self, msg, *args):
+ _assert_context(ui_context)
self.set_markup(msg % args)
self.show_all()
class GetFilenameDialog(ReportbugConnector, Gtk.FileChooserDialog):
def __init__(self, application):
+ _assert_context(ui_context)
Gtk.FileChooserDialog.__init__(self, '', assistant, buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
self.application = application
self.connect('response', self.on_response)
def on_response(self, dialog, res):
+ _assert_context(ui_context)
value = None
if res == Gtk.ResponseType.OK:
value = self.get_filename()
@@ -1546,22 +1700,25 @@ class GetFilenameDialog(ReportbugConnector, Gtk.FileChooserDialog):
self.destroy()
def execute_operation(self, title, force_prompt=False):
+ _assert_context(ui_context)
self.set_title(ask_free(title))
self.show_all()
-# Called in reportbug thread
def log_message(*args, **kwargs):
+ _assert_context(reportbug_context)
application.run_once_in_main_thread(assistant.set_progress_label, *args, **kwargs)
def select_multiple(*args, **kwargs):
+ _assert_context(reportbug_context)
kwargs['multiple'] = True
kwargs['empty_ok'] = True
return menu(*args, **kwargs)
def get_multiline(prompt, *args, **kwargs):
+ _assert_context(reportbug_context)
if 'ENTER' in prompt:
# This is a list, let's handle it the best way
return get_list(prompt, *args, **kwargs)
@@ -1588,7 +1745,9 @@ dialogs = {'yes_no': YesNoDialog,
def create_forwarder(parent, klass):
+ _assert_context(reportbug_context)
def func(*args, **kwargs):
+ _assert_context(reportbug_context)
op = application.call_in_main_thread(klass, parent)
try:
args, kwargs = op.sync_pre_operation(*args, **kwargs)
@@ -1600,6 +1759,7 @@ def create_forwarder(parent, klass):
def forward_operations(parent, operations):
+ _assert_context(reportbug_context)
for operation, klass in operations.items():
globals()[operation] = create_forwarder(parent, klass)
@@ -1654,4 +1814,5 @@ Falling back to 'text' interface."""
def can_input():
+ _assert_context(reportbug_context)
return True
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/reportbug/reportbug.git
More information about the Reportbug-commits
mailing list