How to play custom GUI sounds in GTK3 Python app? - python

Tinkering with a small GTK3 app in Python3, I can trigger XDG theme sounds like so:
#!/usr/bin/python3
import gi
gi.require_version("Gtk", "3.0")
gi.require_version('GSound', '1.0')
from gi.repository import Gtk, GSound
class PyApp:
def __init__(self):
super(PyApp, self).__init__()
self.builder = Gtk.Builder()
self.builder.add_from_file("test.glade")
handlers = {
"onButtonClick": self.onButtonClick
}
self.builder.connect_signals(handlers)
self.sound = GSound.Context()
self.sound.init()
self.window = self.builder.get_object("window1")
self.window.show_all()
def onButtonClick(self, button):
self.sound.play_simple({ GSound.ATTR_EVENT_ID : "phone-incoming-call" })
if __name__ == "__main__":
app = PyApp()
Gtk.main()
But how do I make GSound play my own sounds? Do I have to construct a custom XDG theme, and if so do I have to install this in the correct system folder (e.g. /usr/share/sounds/), or can I bundle it stand-alone with my app? Also, how do I tell the Gsound.context() which theme to use? Very little information available about this.
Edit: This looked promising:
self.sound = GSound.Context()
self.sound.set_attributes({GSound.ATTR_CANBERRA_XDG_THEME_NAME: "freedesktop"})
Alas:
gi.repository.GLib.Error: gsound - error - quark: Invalid argument (-2)

Related

How to enable hardware acceleration with python-vlc in Gtk3 application

Hello I am writing python application with gtk and vlc. Playback works, but without hardware acceleration.
import vlc
class Player:
def __init__(self):
self.instance = vlc.Instance("--no-xlib")
self.player = self.instance.media_player_new()
def visualize(self,widget):
self.player.set_xwindow(widget.get_window().get_xid())
def playurl(self,url):
media = self.instance.media_new(url)
self.player.set_media(media)
self.player.play()
When I run it I see:
[00007f4dfc014830] main filter error: Failed to create video converter
[00007f4df80af2a0] vdpau_avcodec generic error: Xlib is required for VDPAU
So I decided to remove "--no-xlib" parameter, but now I see this:
[00007f16b40078f0] egl_x11 gl error: Xlib not initialized for threads
Someone said this can help:
x11 = ctypes.cdll.LoadLibrary('libX11.so')
x11.XInitThreads()
I've added this on start of my main function. But it causes segmentation fault when calling Gtk.main()
def main():
x11 = ctypes.cdll.LoadLibrary('libX11.so')
x11.XInitThreads()
builder = Gtk.Builder()
builder.add_from_file(BUILDER_PATH)
mw = MainWin(builder) # class containing widgets loaded from GtkBuilder
mw.Show()
myvlc = Player()
myvlc.visualize(mw.player) # mw.player is GtkDrawingArea
myvlc.playurl("http://livesim.dashif.org/livesim/ato_10/testpic_2s/Manifest.mpd")
Gtk.main() # Crash
if __name__ == "__main__":
main()
PS: When I start vlc player /usr/bin/vlc HW acceleration works normally.

How to render MPV to GTK4 window on X11 with python?

How can mpv render to GTK4 window or widget?
In GTK3 it was quite easy to get XID (and put it as argument to MPV) but in GTK4 It seem have to be done with GtkX11 and X11Surface https://docs.gtk.org/gdk4-x11/method.X11Surface.get_xid.html
But I have not clue how to do that in python - can't get surface from window/widget.
#!/usr/bin/env python3
import gi
import mpv
gi.require_version('Gtk', '4.0')
gi.require_version('Gdk', '4.0')
gi.require_version('GdkX11', '4.0')
from gi.repository import Gtk, Gdk, GdkX11
class MainClass(Gtk.ApplicationWindow):
def __init__(self, app):
super(MainClass, self).__init__()
self.set_application(app)
self.set_default_size(600, 400)
self.connect("destroy", self.on_destroy)
widget = Gtk.Frame()
self.set_child(widget)
self.present()
# Can't get XID from widget there
self.mpv = mpv.MPV(wid=str(GdkX11.X11Surface.get_xid(widget)))
self.mpv.play("test.webm")
def on_destroy(self, widget, data=None):
self.mpv.terminate()
Gtk.main_quit()
def on_activate(app):
application = MainClass(app)
if __name__ == '__main__':
# This is necessary since like Qt, Gtk stomps over the locale settings needed by libmpv.
# Like with Qt, this needs to happen after importing Gtk but before creating the first mpv.MPV instance.
import locale
locale.setlocale(locale.LC_NUMERIC, 'C')
app = Gtk.Application()
app.connect('activate', on_activate)
app.run(None)
TypeError: argument self: Expected GdkX11.X11Surface, but got gi.repository.Gtk.Frame
I don't know if this is completely correct
GdkX11.X11Surface.get_xid() takes a X11Surface as a parameter
Try this:
self.mpv = mpv.MPV(wid=str(GdkX11.X11Surface.get_xid(self.get_surface())))
This worked for me

Why I receive this error about attribute in Python?

I have a problem in a simple Glade/Gtk project, I have some objects like Button, Text inputs etc. I have a basic error, gi.repository.Gtk has no attribute 'builder'. Any Ideas? Thanks in advance
Here's the error that I receive (https://imgur.com/a/14cEdn0)
import gi
gi.require_version('Gtk', '3.0')
import gi.repository
from gi.repository import Gtk
class Main:
def __init__(self):
gladeFile = Gtk.builder
self.builder = Gtk.Builder()
self.builder.add_from_file(gladeFile)
self.builder.connect_signals(self)
window = self.builder.get_object("button1")
window.show()
if __name__ == '__main__':
main = Main()
Gtk.main()
Looks like your gladeFile should be a string containing the path to your glade file, e.g. gladeFile = "example.glade".

python-vlc will not embed gtk widget into window, but open a new window instead

I'm working on a gtk3 front end for libvlc written in python using python-vlc. I'm following the gtk3 example from the python-vlc github page, but am experiencing strange behavior. I have a widget that looks like that:
import gi
import sys
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class PlayerWidget(Gtk.DrawingArea):
__gtype_name__ = 'VLCWidget'
def __init__(self, instance):
Gtk.DrawingArea.__init__(self)
self.player = instance.media_player_new()
def handle_embed(*args):
if sys.platform == 'win32':
self.player.set_hwnd(self.get_window().get_handle())
else:
self.player.set_xwindow(self.get_window().get_xid())
return True
self.connect("realize", handle_embed)
self.set_size_request(320, 200)
I embed it here:
import vlc
import sys
from widgets.player import PlayerWidget
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class VideoPlayer(Gtk.Window):
CONST_APP_NAME = "video player"
def __init__(self):
Gtk.Window.__init__(self)
if 'linux' in sys.platform:
self.instance = vlc.Instance("--no-xlib")
else:
self.instance = vlc.Instance()
self.set_default_size(800, 600)
header = Gtk.HeaderBar(title=self.CONST_APP_NAME)
header.set_subtitle("Filename.mp4")
header.set_show_close_button(True) # this one is the troublemaker
self.set_titlebar(header)
self.connect("destroy", Gtk.main_quit)
self.player_widget = PlayerWidget(self.instance)
self.add(self.player_widget)
def show_window(self):
self.show_all()
Gtk.main()
def set_media(self, fname):
self.player_widget.player.set_media(self.instance.media_new(fname))
def play(self):
self.player_widget.play()
if not len(sys.argv) > 0:
print('Please provide a filename')
sys.exit(1)
p = VideoPlayer()
p.set_media(sys.argv[1])
p.play()
p.show_window()
p.instance.release()
It works fine if I embed it into an empty Gtk.window. If, however, I add a HeaderBar to that window as well and then add a close button to that HeaderBar using set_show_close_button(True) it stops working as expected. The PlayerWidget will not be shown embedded anymore, but instead a new (second) window will be opened where the video is played. If I do not add the close button to the HeaderBar the widget gets embedded just fine.
A warning is thrown to the console: xcb_window window error: X server failure
I first thought it could be because I use gnome under wayland, but it occurs on X as well as on wayland.
Any help is appreciated.
Update 1: Added full code example. When I ran it today, the first time it actually worked as expected, but after that the same bug as described above occured again. Very weird.
As #mtz and #stovfl correctly pointed out, the problem was that I started the video playback (p.play()) before creating the window (p.show_window()).
As suggested I used GLib.idle_add(p.play) to let the window start the playback once it's ready. The GLib module can be imported using from gi.repository import GLib.

Python Gtk.MessageDialog Hides Parent Window

I am working on a Gtk3 app written in Python. The main window for my app is set up as follows:
#!/bin/python
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk as Gtk
## OTHER IMPORTS
class MainGui(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="APP TITLE")
# Defaults
self.set_default_size(600, 500)
## OTHER CODE
# Setup the Window
self.connect("destroy", self.on_close)
self.show_all()
## OTHER CODE
def on_close(self, widget):
if self.editor.get_document().get_has_changes():
save_dialog = Gtk.MessageDialog(self, 0,
Gtk.MessageType.QUESTION,
Gtk.ButtonsType.YES_NO,
"Save changes?")
response = save_dialog.run()
## REST OF DIALOG HANDELING
The problem I'm having is related to the save dialog. The app displays the dialog just fine, but it hides my main window, which is not the desired effect. I've tried searching around for a solution, but can't seem to figure out what I'm doing wrong. Any help would be greatly appreciated!
Shortly after posting this I realized that the reason things weren't working is because of a bone-headed mistake. I was hooking up my on_close method using this:
self.connect("destroy", self.on_close)
It turns out I should be doing it this way:
self.connect("delete-event", self.on_close)
Now things work great.

Categories

Resources