How to create a Budgie applet, showing a menu?
Below is the code of a budgie applet in python, I have created.The applet is running smoothly.
#!/usr/bin/env python3
import gi.repository
gi.require_version('Budgie', '1.0')
from gi.repository import Budgie, GObject, Gtk, Gdk
class myapplet(GObject.GObject, Budgie.Plugin): __gtype_name__ = "myapplet"
def __int__(self): GObject.Object.__init__(self)
def do_get_panel_widget(self, uuid): return myappletApplet(uuid)
class myappletApplet(Budgie.Applet): button = None manager = None
def __init__(self, uuid): Budgie.Applet.__init__(self) #create a toggle button in panel self.button = Gtk.ToggleButton.new() self.button.set_relief(Gtk.ReliefStyle.NONE) self.button.set_active(False) self.button.set_tooltip_text("Apple Menu") box1 = Gtk.EventBox() box1.add(self.button) self.add(box1) img = Gtk.Image.new_from_icon_name("apple", Gtk.IconSize.BUTTON) self.button.add(img) box1.show_all() self.show_all() #create a popover self.popover = Budgie.Popover.new(self.button) #create a box box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.popover.add(box) #create separators separator1 = Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL) box.pack_start(separator1, True, True, 0) separator2 = Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL) box.pack_start(separator2, True, True, 0) separator3 = Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL) box.pack_start(separator3, True, True, 0) separator4 = Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL) box.pack_start(separator4, True, True, 0) separator5 = Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL) box.pack_start(separator5, True, True, 0) #events def event_press(box2, event_press): self.popover.hide() self.button.set_active(False) import subprocess subprocess.call(["hardinfo"]) def event_press1(box3, event_press1): self.popover.hide() self.button.set_active(False) import subprocess subprocess.call(["gnome-control-center"]) def event_press2(box4, event_press2): self.popover.hide() self.button.set_active(False) import subprocess subprocess.call(["gnome-software"]) def event_press3(box5, event_press3): if self.pop.get_visible(): self.pop.hide() else: self.pop.show_all() def event_press4(box6, event_press4): self.popover.hide() self.button.set_active(False) import subprocess subprocess.run("xkill") def event_press5(box7, event_press5): self.popover.hide() self.button.set_active(False) import subprocess subprocess.call(["systemctl", "suspend"]) def event_press6(box8, event_press6): self.popover.hide() self.button.set_active(False) import subprocess subprocess.call(["gnome-session-quit", "--reboot"]) def event_press7(box9, event_press7): self.popover.hide() self.button.set_active(False) import subprocess subprocess.call(["gnome-session-quit", "--power-off"]) def event_press8(box10, event_press8): self.popover.hide() self.button.set_active(False) import subprocess subprocess.call(["gnome-session-quit"]) #create popover items box2 = Gtk.EventBox() label1 = Gtk.Label("About This Pc") label1.set_size_request(250, 30) label1.set_xalign(0.1) #label1.set_use_markup(True) box2.connect("button-press-event", event_press) box2.add(label1) box.pack_start(box2, True, True, 0) box.reorder_child(box2, 0) box3 = Gtk.EventBox() label2 = Gtk.Label("System Settings...") label2.set_size_request(250, 25) label2.set_xalign(0.12) #label2.set_use_markup(True) box3.connect("button-press-event", event_press1) box3.add(label2) box.pack_start(box3, True, True, 0) box.reorder_child(box3, 2) box4 = Gtk.EventBox() label3 = Gtk.Label("Software...") label3.set_size_request(250, 25) label3.set_xalign(0.09) label3.set_justify(Gtk.Justification.LEFT) box4.connect("button-press-event", event_press2) box4.add(label3) box.pack_start(box4, True, True, 0) box.reorder_child(box4, 3) box5 = Gtk.EventBox() label4 = Gtk.Label("Recent Items") label4.set_size_request(250, 30) label4.set_xalign(0.1) box5.connect("button-press-event", event_press3) box5.add(label4) box.pack_start(box5, True, True, 0) box.reorder_child(box5, 5) self.pop = Budgie.Popover.new(box5) self.pop.set_position(Gtk.PositionType.RIGHT) boxy = Gtk.Box() boxy = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) boxy.set_size_request(250, 400) self.pop.add(boxy) recentchooserwidget = Gtk.RecentChooserWidget() boxy.add(recentchooserwidget) box6 = Gtk.EventBox() label5 = Gtk.Label("Force Quit") label5.set_size_request(250, 30) label5.set_xalign(0.09) box6.connect("button-press-event", event_press4) box6.add(label5) box.pack_start(box6, True, True, 0) box.reorder_child(box6, 7) box7 = Gtk.EventBox() label6 = Gtk.Label("Sleep") label6.set_size_request(250, 20) label6.set_xalign(0.08) box7.connect("button-press-event", event_press5) box7.add(label6) box.pack_start(box7, True, True, 0) box.reorder_child(box7, 9) box8 = Gtk.EventBox() label7 = Gtk.Label("Restart") label7.set_size_request(250, 20) label7.set_xalign(0.08) box8.connect("button-press-event", event_press6) box8.add(label7) box.pack_start(box8, True, True, 0) box.reorder_child(box8, 10) box9 = Gtk.EventBox() label8 = Gtk.Label("ShutDown") label8.set_size_request(250, 20) label8.set_xalign(0.09) box9.connect("button-press-event", event_press7) box9.add(label8) box.pack_start(box9, True, True, 0) box.reorder_child(box9, 11) box10 = Gtk.EventBox() label9 = Gtk.Label("LogOut\t\t\tCtrAltDel") label9.set_size_request(250, 30) label9.set_xalign(0.23) box10.connect("button-press-event", event_press8) box10.add(label9) box.pack_start(box10, True, True, 0) #button signal self.button.connect("toggled", self.on_button_toggled, self.popover)
def on_button_toggled(self, button, popover): if self.button.get_active(): self.popover.show_all() else: self.popover.hide() self.pop.hide()This applet opens a popover menu with items which can be selected and run each one a separate command.The popover menu opens and closes through pushing a toggle button. I used the Budgie.popover.new() constructor for this.There are some issues that I want to refine.
First issue. I want the popover to close automatically when I click somewhere outside the popover .How can I achieve this.Now I have to push again the toggle button.
Second issue. When I select, lets say the first item in popover ("About This Pc" item), the button freezes in pushed position and I can not activate it (the toogle button) again.I have to close first the application that opened and then push again the toggle button.This happens for "About this Pc", "System Settings", "Restart" and "Shutdown" items. Oddly this does not happen for "Software", "Recent Items" and "LogOut" items.
Third issue. When I select the " Recent Items" item, opens a new popover with recent items inside, just below the eventbox (box5).What I want is to open this new popover (self.pop) on the right of the eventbox.
Any help will be appreciated.
Thanks in advance.
11 Answer
A basic example
Your code seems overcomplex in many ways. A few obvious things:
- You can simply use a
Gtk.Menu, you don't create a menu by a series of buttons. - Don't use a toggle button to call an applet, a normal button is what you need. If you use an
EventBox, you don't need a button at all. - It is sufficient to import
subprocessonly once, at the head of the applet
In short, an example
It might be better to just show an example on how it can be done.
#!/usr/bin/env python3
import subprocess
import gi.repository
gi.require_version('Budgie', '1.0')
from gi.repository import Budgie, GObject, Gtk
class SomeApp(GObject.GObject, Budgie.Plugin): __gtype_name__ = "SomeApp" def __int__(self): GObject.Object.__init__(self) def do_get_panel_widget(self, uuid): return SomeAppApplet(uuid)
class SomeAppApplet(Budgie.Applet): manager = None def __init__(self, uuid): Budgie.Applet.__init__(self) self.box = Gtk.EventBox() self.add(self.box) img = Gtk.Image.new_from_icon_name("firefox", Gtk.IconSize.MENU) self.box.add(img) self.menu = Gtk.Menu() self.create_menu() self.box.show_all() self.show_all() def run_command(self, menuitem): print(menuitem) subprocess.Popen(["gedit"]) def create_menu(self): item1 = Gtk.MenuItem('Some item') item1.connect("activate", self.run_command) item2 = Gtk.MenuItem('Another item') item3 = Gtk.MenuItem('I am on a roll, yet another item') for item in [item1, item2, item3]: self.menu.append(item) self.menu.show_all() self.box.connect("button-press-event", self.popup_menu) def popup_menu(self, *args): self.menu.popup( None, None, None, None, 0, Gtk.get_current_event_time() )And the .plugin file (SomeApp.plugin:
[Plugin]
Loader=python3
Module=someapp
Name=Some App
Description=Obviously an App
Authors=James Bond
Copyright=Copyright © 2018 007
Website=some_website
Icon=firefoxOther tips
On creation of the menu, you can add the menuitems to a list, combined with the commands you want them to run. That way, you don't need to use separate functions for each and every command, but just run the command as argument to run run_command().