R. W. Prado
R. W. Prado

Reputation: 83

Closing a PyGTK window, if the focus is gain and, after, lost

I have a program in Python3 that can change the volume of my system. The behavior I want is it to be like a popup window which will destroy itself after the window, first, get focus and, after, lost focus.

My code has two problems. The first, It does not close itself when the focus is lost, giving me an error:

on_focus_out_event() takes 2 positional arguments, but 3 were given.

And yet, even solving this error, it wouldn't accomplish my desired behavior.

This is my first program written in Python, unfortunately, I need a close help with this. If someone could help me, I would really appreciate it.

#!/usr/bin/python3
    
import sys
import subprocess
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
    
class AppWindow(Gtk.ApplicationWindow):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.set_border_width(0)
        self.set_size_request(500, -1)

        scale_float = Gtk.Scale.new_with_range(Gtk.Orientation.HORIZONTAL, 0.0, 153, 1.0)
        scale_float.set_value_pos(Gtk.PositionType.LEFT)
        scale_float.connect('value-changed', self.on_value_changed)
        scale_float.show_all()

        label_box = Gtk.Box()
        label_box.pack_start(
        Gtk.Image.new_from_icon_name('audio-volume-high', 1), False, False,5)
        label_box.pack_start(Gtk.Label(label=''), True, True, 0)
        label_box.show_all()

        notebook = Gtk.Notebook()
        notebook.append_page(scale_float, label_box)
        notebook.set_tab_pos(Gtk.PositionType.RIGHT)
            
        self.connect('focus-out-event', self.on_focus_out_event)
        self.add(notebook)
        self.show_all()


    def on_value_changed(self, scale_float):
        val = int(scale_float.get_value())
        proc = subprocess.Popen('pactl set-sink-volume 0 ' + str(val) + '%', shell=True, stdout=subprocess.PIPE)
        proc.wait()

    def on_focus_out_event(self, event):
        self.destroy()

class Application(Gtk.Application):
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, application_id="org.example.volume_control",**kwargs)
        self.window = None
    
    def do_activate(self):
        if not self.window:
            self.window = AppWindow(application=self,title="")
            self.window.show_all()
            self.window.present()

if __name__ == "__main__":
    app = Application()
    app.run(sys.argv)

Upvotes: 2

Views: 372

Answers (2)

R. W. Prado
R. W. Prado

Reputation: 83

With the answer of Alperen, I was able to make an app that can mute and change my system's volume. My application will only close if the scale have been changed or if the button was toggled at least one time and, after, the window loses its focus. It's not my first wanted behavior, but I think it's even better implemented now.

P.S.: I am not sure if the code is indented correctly.

#!/usr/bin/python3

import sys
import subprocess
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

class AppWindow(Gtk.ApplicationWindow):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.set_border_width(0)
        self.set_size_request(500, -1)

        volume = subprocess.Popen("pacmd dump-volumes | awk 'NR==1{print $8}' | sed 's/\%//'", shell=True, stdout=subprocess.PIPE)
        volume_str = volume.stdout.read()

        scale_float = Gtk.Scale.new_with_range(Gtk.Orientation.HORIZONTAL, 0.0, 153, 1.0)
        scale_float.set_value(int(volume_str))
        scale_float.set_draw_value(False)
        scale_float.set_value_pos(Gtk.PositionType.LEFT)
        scale_float.connect('value-changed', self.on_value_changed)
        scale_float.show_all()

        ismuted = subprocess.Popen("pacmd list-sinks | grep muted | sed -e 's/.*: //g'", shell=True, stdout=subprocess.PIPE)

        if ismuted.stdout.read().decode() == b'yes\n'.decode():
            image=Gtk.Image.new_from_icon_name('audio-volume-muted', 1)
        else:
            image=Gtk.Image.new_from_icon_name('audio-volume-high', 1)
        button = Gtk.Button()
        button.set_image(image)
        button.connect("clicked", self.on_button_clicked )
        button.show_all()

        notebook = Gtk.Notebook()
        notebook.append_page(scale_float, button)
        notebook.set_tab_pos(Gtk.PositionType.RIGHT)

        self.add(notebook)
        self.show_all()

    def on_value_changed(self, scale):
        val = int(scale.get_value())
        proc = subprocess.Popen('pactl set-sink-volume 0 ' + str(val) + '%', shell=True, stdout=subprocess.PIPE)
        proc.wait()
        self.connect('focus-out-event', self.on_focus_out_event)

    def on_focus_out_event(self, widget, window):
        self.destroy()

    def on_button_clicked(self, button):
        subprocess.Popen("pactl set-sink-mute 0 toggle", shell=True, stdout=subprocess.PIPE)
        ismuted = subprocess.Popen("pacmd list-sinks | grep muted | sed -e 's/.*: //g'", shell=True, stdout=subprocess.PIPE)
        if ismuted.stdout.read().decode() == b'yes\n'.decode():
            image=Gtk.Image.new_from_icon_name('audio-volume-muted', 1)
        else:
            image=Gtk.Image.new_from_icon_name('audio-volume-high', 1)
        button.set_image(image)
        self.connect('focus-out-event', self.on_focus_out_event)

class Application(Gtk.Application):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, application_id="org.example.volume_control",**kwargs)
        self.window = None

    def do_activate(self):
        if not self.window:
            self.window = AppWindow(application=self,title="")
            self.window.show_all()
            self.window.present()

if __name__ == "__main__":
    app = Application()
    app.run(sys.argv)

Upvotes: 1

Alperen İsa
Alperen İsa

Reputation: 118

focus-out-event requires three arguments. Add the window argument to self, event on line 41.

    def on_focus_out_event(self, event, window):
        self.destroy()

enter image description here

Upvotes: 2

Related Questions