So, I'm depeloping a Python/GTK app which, after showing an assistant, it hides the assistant's window and runs an external app. The problem is that window.hide()
doesn't works if, after the command, there's an app call using os.system()
or call()
. When the call is done, the window seems to hang and it doesn't disappears until all the calls are done. So... what can be done?
-
We are making a client/server app, and we have some troubles with gtk, it seams to lock our thread in the Gtk.main(). So we might be interested about using your solution, but where did you put those lines ?– Audrey-ShowMyFavesJun 24, 2012 at 21:32
-
Yep, I had the same problem with an app which I've done. Let me check...– XerzJun 24, 2012 at 21:43
-
OK, it seems to fix the hanged thread error. Just insert it before the code which causes the problem, and done! :)– XerzJun 24, 2012 at 21:49
-
Wait... I'm not sure, try it anyway.– XerzJun 24, 2012 at 21:52
3 Answers
After some time googling possible solutions, I've found this simple answer, which waits to GTK until it finished all its working tasks. You may think that makes the app slower, but the difference is almost unexistent.
This workaround can be used with any version of Python. It works with PyGTK and with GTK+3 (with GTK+3, change gtk
per Gtk
... :P )
while gtk.events_pending():
gtk.main_iteration()
Just add this before the code which causes the problem... and done! :)
In my applications I tend to replace os.system()
and subprocess.call()
with subprocess.Popen
(see https://stackoverflow.com/a/636570/2372604).
-
I've been using
subprocess.Popen
recently and it's really delightful. If only I knew back then!– XerzJan 27, 2016 at 9:25
Using openSUSE Leap 15.5, Python 3.6.15 and GTK 4.6.9 here.
In short, the idea is: hide the window by calling Gtk.Window.hide()
, then start a thread using threading.Timer()
(non-blocking). In that thread, run the external app with subprocess.run()
(blocking) then show the window again with Gtk.Window.show()
.
Here is a complete working example:
#!/usr/bin/python3
import subprocess
import sys
import threading
import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk, Gdk
class MainWindow(Gtk.ApplicationWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.set_default_size(600, 250)
self.set_title('MyApp')
self.box1 = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
self.set_child(self.box1)
self.button = Gtk.Button(label='Launch')
self.button.connect('clicked', self.on_button_clicked)
self.box1.append(self.button)
def on_button_clicked(self, button):
self.hide()
t = threading.Timer(1, self.launch)
t.start()
def launch(self):
subprocess.run(['gnome-calculator'])
self.show()
class MyApp(Gtk.Application):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.connect('activate', self.on_activate)
def on_activate(self, app):
self.main_window = MainWindow(application=app)
self.main_window.present()
app = MyApp(application_id='com.example.MyApp')
app.run(sys.argv)
These may be useful: