I understand that one is not supposed to update the UI from other threads in gtk, or face consequences, but I am not sure how I can avoid that while using gstreamer.
My application crashes from time to time during video stream initialization with a following complaint:
[xcb] Unknown sequence number while processing queue
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
python: ../../src/xcb_io.c:274: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed.
In my code I have added gtk.thread_init() call right in the beginning of the GUI class:
import pygtk, gtk, gobject
gtk.gdk.threads_init()
(I have also tried gobject.threads_init(), but this doesnt seem any different). In a separate class, which is run in a separate thread, I start a gstreamer stream to a tcpserversink (this gstreamer thread is already a third thread, if someone is keeping count). And then another thread receives this data before pushing the data to xvimagesink in the end.
The xvimagesink needs a viewport, and I believe this gstreamer callback function is where sometimes gtk goes crazy, when I assign it:
def on_sync_message(self, bus, message):
...
if message_name == "prepare-xwindow-id":
# Assign the viewport
imagesink = message.src
imagesink.set_property("force-aspect-ratio", True)
imagesink.set_xwindow_id(self.window_handle.window.xid)
The self.window_handle is a pointer to self.movie_window = gtk.DrawingArea(), assigned during GUI initialization.
TL;DR Is there a safe way of using gtk with gstreamer, since I cannot avoid threading when calling gst.Pipeline("name").set_state(gst.STATE_PLAYING) and view will be a GTK drawing area ?
I think your issue is the fact that you are accessing unprotected Xlib/xcb from 2 threads - once impicitly from your Gtk+ UI and once in the thread where your gstreamer backend callback is executed - which by default is the mainloop you told gstreamer to use (or the thread default mainloop).
gtk.gdk.threads_init() is already called once the type system is initialized (if I recall correctly, correct me if I am wrong).
Use g_idle_add (or use GSource with a higher priority) (which are threadsafe) with a callback which schedules UI changes in the Gtk mainloop (run by gtk_main()).
Related
I'm building a GTK GUI in Python and I need to get some data from the database which takes quite long, so the GUI freezes.
So I'm now using Threads to run the refreshing "in the background":
Thread(target=self.updateOrderList).start()
I have GUI class with alle relevant methods to manipulate the GUI. My solution work 80% of the time, but when it doesn't GTK crashed and it outputs this:
[xcb] Unknown request in queue while dequeuing
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
python3.6: ../../src/xcb_io.c:165: dequeue_pending_request:
The other times it works good, the data get loaded and its refreshing the gui.
edit: Sometimes I get this error:
Gdk-Message: 11:13:42.848: main.py: Fatal IO error 11 (Die Ressource ist zur Zeit nicht verfügbar) on X server :0
Sometimes I click the refresh button several times and it works, but then it doesn't at some point.
My main.py looks like this:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GObject
import gui
GObject.threads_init()
# start gui
gui.Gui()
Gtk.main()
Any ideas whats happening here?
Markus
Okay, GTK3 is not threadsafe. So I changed the program logic - doing requests in a new thread, and handling the GUI manipulation in the GUI thread ONLY. So that means I have to emit a "requests done" signal to the event loop:
Creating a new signal and registering it:
GObject.signal_new("my-custom-signal", self.window, GObject.SIGNAL_RUN_LAST, GObject.TYPE_PYOBJECT,
(GObject.TYPE_PYOBJECT,))
self.window.connect("my-custom-signal", self.updateOrderListCallback)
So when I click a button, start a thread:
Thread(target=self.updateOrderListThread).start()
In that thread, do the calculations, and then emit the signal:
self.window.emit("my-custom-signal", None)
so than the callback will be called after the calculations/requests/whatever are done and it works!
I'm new for python but willing to learn. I have a set of hardware to receive touch coordinators and draw line accordingly to coordinators.
My problem is that the wxpython won't draw line if coordinator changes.
Here is my code : https://github.com/eleghostliu/homework/blob/master/DrawXY_byWxPython/PythonApplication1/PythonApplication1.py
can someone give advise, thanks.
You registered for EVT_PAINT, yet you are not triggering the event as the data changes. The frame has no idea whether data changed or not, unless you specifically inform it.
You can trigger the event simply by calling
frame.Refresh()
You can hook it in several ways. For instance, you could pass frame.Refresh bound method as a parameter to MainProcess so that it can make the function call to refresh the frame. Something like the following:
WARNING: Erroneous code piece
# Start a socket server
def MainProcess(refresh_callback):
while True:
refresh_callback()
***********************************************
frame = DrawPanel()
frame.Show()
start_new_thread(MainProcess, (frame.Refresh,))
Edit:
The above code piece calling UI methods directly is wrong!
Worker thread should not directly manipulate GUI, instead it should inform the GUI thread about a change, and the GUI thread which is the main thread will handle it in its context. There are again several approaches here, the quickest to implement is through wx.CallAfter.
Which you can incorporate as below, instead of directly calling the function:
wx.CallAfter(refresh_callback)
Another way to handle the communication between worker thread and GUI thread is via wx.PostEvent.
class DrawPanel(wx.Frame):
"""Draw a line to a panel."""
def notify(self):
wx.PostEvent(self, wx.PaintEvent())
Then from the secondary thread, you can safely call frame.notify() whenever new data arrives.
For a more elegant solution involving wx.CallAfter, refer to https://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/ where pubsub is used.
This is the standard example of DBus service.
import dbus
import gobject
from dbus import service
# from gi._gobject import MainLoop
from dbus.mainloop.glib import DBusGMainLoop
class DBusServer(service.Object):
def __init__(self, name, object_path):
# super(service.Object, self).__init__(name, object_path)
dbus.service.Object.__init__(self, name, object_path)
#dbus.service.method("com.test", in_signature='s', out_signature="s")
def test(self, args):
return args + " Sent by dbus client"
#dbus.service.method("com.test", in_signature='s', out_signature="s")
def foo(self, args):
return "foo"
bus_loop = DBusGMainLoop(set_as_default=True)
session_bus = dbus.SessionBus()
session_name = service.BusName("com.test", session_bus)
dbus_server = DBusServer(session_name, "/test")
loop = gobject.MainLoop()
try:
loop.run()
except KeyboardInterrupt:
loop.quit()
I have questions regarding two mainloops used here
1. What is the role of each mainloop or event loop in this code (if I am using the correct terminology. They both are event loops I guess)
2. If my app is not a GUI app why should I need gobject mainloop or qt mainloop since that is required to catch user generated events from X11 library (in case of Linux)
3. Why can't I use an infinite loop which does nothing instead of gobject main loop (as follows)
while True:
pass
Below are summarized short answers, see the details at the end for more explanations.
Question 1:
There is only one mainloop being used in the code you posted, the loop = gobject.MainLoop(). Its role is to process events, e.g. D-Bus messages sent to your service.
Question 2:
You need a mainloop in order for your code to not block D-Bus messages coming from outside your service. The dbus-python binding does not have a mainloop implementation so you need to use a mainloop from some other library (which also needs to be one supported by dbus-python, in this case GLib).
Question 3:
An infinite loop like that will never allow for any code other than that particular loop to execute, and there would be no way of receiving D-Bus messages (or any other events).
Details:
Simply put, a mainloop typically processes other events when there is no code currently running in your program. In this case, the nature of D-Bus requires there to be a way for your code to handle events from an external source, i.e. D-Bus messages. This is the reason that you need to have a mainloop. You could base the event processing on a loop you write yourself, as long as you have code in the loop that can process external events. The reason people often use libraries for mainloops is because things tend to grow complex in 'real' applications or systems and it's often more robust to use something which has been tested, used, and improved by others for years (e.g. GLib).
The D-Bus binding dbus-python is implemented in a way that requires an external mainloop to be used, as it does not have its own mainloop implementation. A typical reason for designing a library to use an external mainloop is to let the user of a library decide what mainloop to use, since the mainloop could potentially be used for other things as well (e.g. process other events than D-Bus events). This increases the potential use of the library and reduces the dependencies introduced as a side-effect of using the library.
The library must however support the mainloop of choice which means that there must be some integration provided specifically for each mainloop intended to be used with the library. Typically, the internals of a library like this would be designed to use a class/type that is an abstraction of a mainloop so the code internals doesn't need to know about what mainloop has been integrated. This reduces the amount of code which needs to be mainloop implementation specific within the library.
If you examine the bus_loop object received when doing:
bus_loop = DBusGMainLoop(set_as_default=True)
... you will see that it is an object of type dbus.mainloop.NativeMainLoop which is the mainloop wrapper object in dbus-python.
Now, dbus-python currently only provides an integration for the GLib mainloop so the discussion above becomes a bit theoretical in this case. The way dbus-python integrates a GLib mainloop is to require the user to import and instantiate the GLib mainloop wrapper, like this:
from dbus.mainloop.glib import DBusGMainLoop
DBusGMainLoop(set_as_default=True)
This creates a GLib main context which is later used by a GLib mainloop to process events that dbus-python associates with that context. The last part of the mainloop integration is to require the user to start a GLib mainloop. When you import and run the gobject mainloop, like this:
loop = gobject.MainLoop()
loop.run()
The mainloop will process events from the context created previously. This is the 'link' between the D-Bus binding dbus-python and the GObject binding gobject (which gives access to the GLib mainloop).
Simplified to the extreme, one could say that the context created and set when doing:
from dbus.mainloop.glib import DBusGMainLoop
DBusGMainLoop(set_as_default=True)
is a list of events to process if they appear, and the mainloop created and started when doing:
loop = gobject.MainLoop()
loop.run()
is what makes something check that list. The fact that GLib is used for both things makes it work, again simply put.
If you want to dig further into this, read up on GLib and the GMainLoop and GMainContext and the concepts related to these. Hope this helps.
I have a pygtk application which runs as soon as my python script is opened. Along with gtk.main() I have a thread which is started at the beginning of the script, which refreshes a gtk.TextView() instance:
def listen(self):
while True:
print "refreshing"
data = self.socket.recv(buffer_size)
if data:
self.txtBuffer.insert(self.txtBuffer.get_end_iter(), data + "\n")
print data
thread.start_new_thread(self.listen, ())
self.set_up_gui() # gtk.main()
However, when I run the program, the gui opens, but no "refreshing" text is printed, nor is any data printed when sent to the socket. I have attempted to use glib.add_idle() to thread this program, however that only runs the separate thread when the gui is idle (which is infrequent). Thank you!
You are accessing the text buffer from a different thread without any synchronization, which is unsupported. To fix that, replace self.txtBuffer.insert(...) with gobject.idle_add(lambda: self.txtBuffer.insert(...)). That tells the GUI thread to update the text buffer at the next main loop iteration, which is guaranteed to work without explicit synchronization.
You should make sure that the GUI thread is not blocked, i.e. that it's running gtk.main() and only processing GUI updates such as the above textBuffer.insert. Long-running/blocking tasks should be delegated to other threads or processes, as your code already tries to do. When this is implemented, GUI updates will appear to happen instantaneously.
See this answer for additional details on PyGTK and threading.
I am using PyGTK to build a GUI application. I want to update the textview widget from another thread but the widget is not getting updated everytime i try an update. What should i do to get a reliable GUI updating?
GTK+ is not thread-safe, so you should not simply call GUI update methods from other threads. glib.idle_add (or gobject.idle_add in older PyGTK versions) can be used for this purpose.
Instead of writing:
label.set_text("foo")
you would write:
glib.idle_add(label.set_text, "foo")
which causes the function call to be queued in GTK+.
If you need to run multiple statements, it's often easier to wrap them in a function:
def idle():
label1.set_text("foo")
label2.set_text("bar")
glib.idle_add(idle)
Make sure that the function passed to idle_add does not return True; otherwise it will be queued again.
Edit: As Daniel pointed out, you need to call gtk.gdk.threads_init() anywhere in your program first.
As stated in the previous answers, GTK is not "thread safe," but it is "thread-aware" - see this page on Threads: https://developer.gnome.org/gdk2/stable/gdk2-Threads.html
In order to modify GTK widgets from another thread you have to use GTK's locking. Call gtk.threads_init() immediately after importing the gtk module, and then you can update like so:
gtk.threads_enter()
# make changes...
gtk.threads_leave()
Note that the above will not work on Windows (see the link above). On Windows you must use gobject.idle_add() as explained above, though don't forget to put gobject.threads_init() directly after importing gobject in your code! The idle_add() function will execute the update itself in the main thread (the thread running gtk.main()).
the same may be achieved using gobject.idle_add method whose syntax is same as above,you have to import the module gobject
What Johannes said is correct, however since GTK is a wrapper for the glib and gobject things, you would actually want to use gtk.idle_add(). No need for the unnecessary imports.