-1

I want to use MPD's idle feature to wait for any changes and then display them in the GTK GUI using Python. The problem is that the GUI seems to block and become unresponsive when I use MPD's idle feature (when changing songs the GTK window becomes unresponsive). When I remove self.mpd.idle() it works, but then the function keeps getting run all the time which I find unnecessary.

What is the best way to solve this?

Not working My initial approach:

import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib
from mpd import MPDClient

class GUI:
    def __init__(self):
        self.mpd = MPDClient()
        self.mpd.timeout = 10
        self.mpd.connect("localhost", 6600)

        self.window = Gtk.Window()
        self.window.connect("delete-event", Gtk.main_quit)
        self.window.show_all()

        GLib.idle_add(self.get_current_song)
        Gtk.main()

    def get_current_song(self):
        self.mpd.idle()
        print(self.mpd.currentsong())
        return True

app = GUI()

Not working My second approach using this. Still getting the same results.

import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib
from mpd import MPDClient
import threading

class GUI:
    def __init__(self):
        self.mpd = MPDClient()
        self.mpd.timeout = 1
        self.mpd.connect("localhost", 6600)

        self.window = Gtk.Window()
        self.window.connect("delete-event", Gtk.main_quit)

        self.window.show_all()
        self.thread = threading.Thread(target=self.idle_loop)
        self.thread.daemon = True
        self.thread.start()
        Gtk.main()

    def get_songs(self):
        print(self.mpd.currentsong())
        self.mpd.idle()
        return True

    def idle_loop(self):
        GLib.idle_add(self.get_songs)

app = GUI()

WORKING Leaving out the GLib.idle_add() function seems to be a solution. But I don't know if this is the "proper" way. It feels wrong not knowing why GLib.idle_add() was messing it up and not using it since it's mentioned in the documentation.

import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib
from mpd import MPDClient
import threading

class GUI:
    def __init__(self):
        self.mpd = MPDClient()
        self.mpd.timeout = 1
        self.mpd.connect("localhost", 6600)

        self.window = Gtk.Window()
        self.window.connect("delete-event", Gtk.main_quit)

        self.window.show_all()
        self.thread = threading.Thread(target=self.get_songs)
        self.thread.daemon = True
        self.thread.start()
        Gtk.main()

    def get_songs(self):
        self.mpd.idle()
        print(self.mpd.currentsong())

app = GUI()
Likdoyaya
  • 21
  • 5
  • You can use `threading.Thread` and make the song getting task run simultaneously? – J Arun Mani Jan 29 '20 at 15:40
  • 1
    Threading is the wrong solution to the wrong problem. It won't prevent `the function keeps getting run all the time which I find unnecessary` problem. – liberforce Jan 30 '20 at 09:19
  • I tried using the threading module as mentioned in the OP (I found [this](https://wiki.gnome.org/Projects/PyGObject/Threading). Still had the same problem. Then I left out the GLib.idle_add() function and it's somewhat working now. I don't know if this is the "proper way", not utilizing the GLib.idle_add() function. – Likdoyaya Jan 30 '20 at 13:04
  • You should add the function to `GLib.idle_add` every time, that is whenever you want some changes to GUI. – J Arun Mani Jan 30 '20 at 15:31
  • But adding it to `GLib.idle_add` causes the lockdowns. That's what makes it not work. – Likdoyaya Jan 31 '20 at 07:38
  • Please give a link to the mpd implementation you're using, as it seems there are several out there, and we need to know how `mdp.idle()` is supposed to work. – liberforce Jan 31 '20 at 14:30
  • `GLib.idle_add` is used to execute a callback when the main program is idle. It must call a non-blocking function, otherwise the whole UI freezes. So we need to know what `mpd.idle` exactly does. – liberforce Jan 31 '20 at 17:26
  • I am using [python-mpd2](https://github.com/Mic92/python-mpd2). Perhaps it's then wrong to use GLib.idle_add() in this case and it's okay to use threads? – Likdoyaya Feb 04 '20 at 00:41

1 Answers1

0

Let us use the threading module here. As described in this article : https://pygobject.readthedocs.io/en/latest/guide/threading.html, we can make the following code:

import gi
from threading import Thread
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib
from mpd import MPDClient

class GUI:
    def __init__(self):
        self.mpd = MPDClient()
        self.mpd.timeout = 10
        self.mpd.connect("localhost", 6600)

        self.window = Gtk.Window()
        self.window.connect("delete-event", Gtk.main_quit)
        self.window.show_all()

        thread = Thread(target=self.get_current_song, args=())
        thread.start()
        Gtk.main()

    def get_current_song(self):
        self.mpd.idle()
        print(self.mpd.currentsong())
        return True

app = GUI()
J Arun Mani
  • 620
  • 3
  • 20
  • 1
    Thanks. I got rid of the GLib.idle_add() function and it stopped being unresponsive on song changes. I updated the OP. – Likdoyaya Jan 30 '20 at 13:06