1

So I am trying to use threads to implement a blocking operation in a Python3 based application.

#!/usr/bin/env python3

import gi, os, threading, Skype4Py
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GLib, GObject

skype = Skype4Py.Skype()

def ConnectSkype():
    skype.Attach()

class Contacts_Listbox_Row(Gtk.ListBoxRow):

    def __init__(self, name):
        # super is not a good idea, needs replacement.
        super(Gtk.ListBoxRow, self).__init__()
        self.names = name
        self.add(Gtk.Label(label=name))

class MainInterfaceWindow(Gtk.Window):
    """The Main User UI"""

    def __init__(self):
        Gtk.Window.__init__(self, title="Python-GTK-Frontend")

        # Set up Grid object
        main_grid = Gtk.Grid()
        self.add(main_grid)

        # Create a listbox which will contain selectable contacts
        contacts_listbox = Gtk.ListBox()
        for handle, name in self.GetContactTuples():
            GLib.idle_add(contacts_listbox.add, Contacts_Listbox_Row(name))
        GLib.idle_add(main_grid.add, contacts_listbox)


        # Test label for debug
        label = Gtk.Label()
        label.set_text("Test")
        GLib.idle_add(main_grid.attach_next_to, label, contacts_listbox, Gtk.PositionType.TOP, 2, 1)

    def GetContactTuples(self):
        """
        Returns a list of tuples in the form: (username, display name).
        Return -1 if failure.
        """
        print([(user.Handle, user.FullName) for user in skype.Friends]) # debug
        return [(user.Handle, user.FullName) for user in skype.Friends]

if __name__ == '__main__':

        threads = []

        thread = threading.Thread(target=ConnectSkype) # potentially blocking operation
        thread.start()
        threads.append(thread)

        main_window = MainInterfaceWindow()
        main_window.connect("delete-event", Gtk.main_quit)
        main_window.show_all()
        print('Calling Gtk.main')
        Gtk.main()

The basic idea is this simple program should fetch a list of contacts from the Skype API, and build a list of tuples. The GetContactTuples function succeeds in its design, the print call I placed verifies that. However, the program hangs indefinitely, and never renders an interface. Sometimes, it will yield random errors involving threads and/or resource availability. Once such error is

(example.py:31248): Gdk-WARNING **: example.py: Fatal IO error 11 (Resource temporarily unavailable) on X server :1.

I know it is related to the use of threads, but based on the documentation here, it seems like just adding GLib.idle_add calls before interface updates should be sufficient. So the questions are, why does this not work, and how could I correct the above sample?

UPDATE: If GLib.idle_add is prepended to every line that interacts with GTK that it can be, I get a different error. [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. python: xcb_io.c:179: dequeue_pending_request: Assertion '!xcb_xlib_unknown_req_in_deq' failed. Aborted (core dumped)

1
  • A quick update, if ConnectSkype() is not run in a thread, it has the exact same result, so the thread is completely useless. However, Skype4Py must use a thread internally, as it yields the same errors. Commented Mar 17, 2016 at 19:38

1 Answer 1

1

Depending on your library version (this was no longer necessary in Gobject 3.10.2) you might need to actually need to explicitly initialize your threads using GObject.threads_init() as below:

if __name__ == '__main__':

    threads = []

    thread = threading.Thread(target=ConnectSkype) # potentially blocking operation
    thread.start()
    threads.append(thread)

    main_window = MainInterfaceWindow()
    main_window.connect("delete-event", Gtk.main_quit)

    GObject.threads_init()

    main_window.show_all()
    print('Calling Gtk.main')
    Gtk.main()
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.