예제 #1
0
파일: overlay.py 프로젝트: trigg/Discover
 def set_monitor(self, idx=None, mon=None):
     """
     Set the monitor this overlay should display on.
     """
     self.monitor = idx
     if self.is_wayland:
         if mon:
             GtkLayerShell.set_monitor(self, mon)
     self.force_location()
     self.needsredraw = True
예제 #2
0
    def __init__(self,
                 parent,
                 position,
                 alignment,
                 settings,
                 width,
                 monitor=None,
                 icons_path=""):
        Gtk.Window.__init__(self, type_hint=Gdk.WindowTypeHint.NORMAL)
        GtkLayerShell.init_for_window(self)
        if monitor:
            GtkLayerShell.set_monitor(self, monitor)

        check_key(settings, "css-name", "controls-window")
        self.parent = parent

        self.set_property("name", settings["css-name"])
        self.icon_size = settings["icon-size"]
        self.icons_path = icons_path

        self.settings = settings
        self.position = position

        self.net_icon_name = ""

        self.menu_box = None
        self.sink_box = None

        self.bri_scale = None
        self.vol_scale = None

        self.src_tag = 0

        self.connect("show", self.on_window_show)

        check_key(settings, "output-switcher", False)
        self.sinks = []
        if commands["pamixer"] and settings["output-switcher"] and commands[
                "pamixer"]:
            self.sinks = list_sinks()

        eb = Gtk.EventBox()
        eb.set_above_child(False)
        if settings["leave-closes"]:
            self.connect("leave_notify_event", self.on_window_exit)
            self.connect("enter_notify_event", self.on_window_enter)

        outer_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
        eb.add(outer_vbox)
        self.add(eb)

        outer_hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
        Gtk.Widget.set_size_request(outer_hbox, width, 10)
        outer_vbox.pack_start(outer_hbox, True, True, 20)

        v_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
        outer_hbox.pack_start(v_box, True, True, 20)

        GtkLayerShell.set_layer(self, GtkLayerShell.Layer.TOP)
        # GtkLayerShell.set_keyboard_interactivity(self, True)
        GtkLayerShell.set_margin(self, GtkLayerShell.Edge.TOP,
                                 settings["window-margin"])
        GtkLayerShell.set_margin(self, GtkLayerShell.Edge.BOTTOM,
                                 settings["window-margin"])
        GtkLayerShell.set_margin(self, GtkLayerShell.Edge.RIGHT,
                                 settings["window-margin"])
        GtkLayerShell.set_margin(self, GtkLayerShell.Edge.LEFT,
                                 settings["window-margin"])

        if alignment == "left":
            GtkLayerShell.set_anchor(self, GtkLayerShell.Edge.LEFT, True)
        else:
            GtkLayerShell.set_anchor(self, GtkLayerShell.Edge.RIGHT, True)
        if position == "bottom":
            GtkLayerShell.set_anchor(self, GtkLayerShell.Edge.BOTTOM, True)
        else:
            GtkLayerShell.set_anchor(self, GtkLayerShell.Edge.TOP, True)

        check_key(settings, "commands", {"battery": "", "net": ""})

        add_sep = False
        if "brightness" in settings["components"]:
            inner_hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL,
                                 spacing=0)
            v_box.pack_start(inner_hbox, False, False, 0)

            self.bri_icon_name = "view-refresh-symbolic"
            self.bri_image = Gtk.Image.new_from_icon_name(
                self.bri_icon_name, Gtk.IconSize.MENU)

            inner_hbox.pack_start(self.bri_image, False, False, 6)

            self.bri_scale = Gtk.Scale.new_with_range(
                orientation=Gtk.Orientation.HORIZONTAL, min=0, max=100, step=1)
            self.bri_scale.connect("value-changed", self.set_bri)

            inner_hbox.pack_start(self.bri_scale, True, True, 5)
            add_sep = True

        if "volume" in settings["components"] and commands["pamixer"]:
            inner_hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL,
                                 spacing=0)
            v_box.pack_start(inner_hbox, False, False, 6)

            self.vol_icon_name = "view-refresh-symbolic"
            self.vol_image = Gtk.Image.new_from_icon_name(
                self.vol_icon_name, Gtk.IconSize.MENU)

            if self.parent.vol_icon_name != self.vol_icon_name:
                update_image(self.vol_image, self.parent.vol_icon_name,
                             self.icon_size, self.icons_path)
                self.vol_icon_name = self.parent.vol_icon_name

            eb = Gtk.EventBox()
            eb.connect("enter_notify_event", self.on_enter_notify_event)
            eb.connect("leave_notify_event", self.on_leave_notify_event)
            eb.connect("button-press-event", self.toggle_mute)
            eb.add(self.vol_image)
            inner_hbox.pack_start(eb, False, False, 6)

            self.vol_scale = Gtk.Scale.new_with_range(
                orientation=Gtk.Orientation.HORIZONTAL, min=0, max=100, step=1)
            self.vol_scale.set_value(self.parent.vol_value)
            self.vol_scale.connect("value-changed", self.set_vol)

            inner_hbox.pack_start(self.vol_scale, True, True, 5)
            if commands["pamixer"] and settings["output-switcher"]:
                pactl_eb = Gtk.EventBox()
                image = Gtk.Image()
                pactl_eb.add(image)
                pactl_eb.connect("enter_notify_event",
                                 self.on_enter_notify_event)
                pactl_eb.connect("leave_notify_event",
                                 self.on_leave_notify_event)
                update_image(image, "pan-down-symbolic", self.icon_size,
                             self.icons_path)
                inner_hbox.pack_end(pactl_eb, False, False, 5)

                self.sink_box = SinkBox()
                pactl_eb.connect('button-press-event',
                                 self.sink_box.switch_visibility)
                v_box.pack_start(self.sink_box, False, False, 0)

            add_sep = True

        if add_sep:
            sep = Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL)
            v_box.pack_start(sep, True, True, 10)

        if "net" in settings["components"] and commands[
                "netifaces"] and settings["net-interface"]:
            event_box = Gtk.EventBox()
            if "net" in settings["commands"] and settings["commands"]["net"]:
                event_box.connect("enter_notify_event",
                                  self.on_enter_notify_event)
                event_box.connect("leave_notify_event",
                                  self.on_leave_notify_event)

                event_box.connect('button-press-event', self.launch,
                                  settings["commands"]["net"])

            inner_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL,
                                 spacing=0)
            inner_hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL,
                                 spacing=0)
            inner_vbox.pack_start(inner_hbox, True, True, 6)
            v_box.pack_start(event_box, True, True, 0)

            self.net_icon_name = "view-refresh-symbolic"
            self.net_image = Gtk.Image.new_from_icon_name(
                self.net_icon_name, Gtk.IconSize.MENU)

            icon_name = "network-wired-symbolic" if self.parent.net_ip_addr else "network-wired-disconnected-symbolic"

            if icon_name != self.net_icon_name:
                update_image(self.net_image, icon_name, self.icon_size,
                             self.icons_path)
                self.net_icon_name = icon_name

            inner_hbox.pack_start(self.net_image, False, False, 6)

            self.net_label = Gtk.Label("{}: {}".format(
                settings["net-interface"], self.parent.net_ip_addr))
            inner_hbox.pack_start(self.net_label, False, True, 6)

            if "net" in settings["commands"] and settings["commands"]["net"]:
                img = Gtk.Image()
                update_image(img, "pan-end-symbolic", self.icon_size,
                             self.icons_path)
                inner_hbox.pack_end(img, False, True, 4)

            event_box.add(inner_vbox)

        if "bluetooth" in settings["components"] and commands["pybluez"]:
            event_box = Gtk.EventBox()
            if "bluetooth" in settings["commands"] and settings["commands"][
                    "bluetooth"]:
                event_box.connect("enter_notify_event",
                                  self.on_enter_notify_event)
                event_box.connect("leave_notify_event",
                                  self.on_leave_notify_event)

                event_box.connect('button-press-event', self.launch,
                                  settings["commands"]["bluetooth"])

            inner_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL,
                                 spacing=0)
            inner_hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL,
                                 spacing=0)
            inner_vbox.pack_start(inner_hbox, True, True, 6)
            v_box.pack_start(event_box, True, True, 0)

            self.bt_icon_name = "view-refresh-symbolic"
            self.bt_image = Gtk.Image.new_from_icon_name(
                self.bt_icon_name, Gtk.IconSize.MENU)

            inner_hbox.pack_start(self.bt_image, False, False, 6)

            self.bt_label = Gtk.Label()
            inner_hbox.pack_start(self.bt_label, False, True, 6)

            if "bluetooth" in settings["commands"] and settings["commands"][
                    "bluetooth"]:
                img = Gtk.Image()
                update_image(img, "pan-end-symbolic", self.icon_size,
                             self.icons_path)
                inner_hbox.pack_end(img, False, True, 4)

            event_box.add(inner_vbox)

        if "battery" in settings["components"]:
            event_box = Gtk.EventBox()
            if "battery" in settings["commands"] and settings["commands"][
                    "battery"]:
                event_box.connect("enter_notify_event",
                                  self.on_enter_notify_event)
                event_box.connect("leave_notify_event",
                                  self.on_leave_notify_event)

                event_box.connect('button-press-event', self.launch,
                                  settings["commands"]["battery"])

            inner_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL,
                                 spacing=0)
            inner_hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL,
                                 spacing=0)
            inner_vbox.pack_start(inner_hbox, True, True, 6)
            v_box.pack_start(event_box, True, True, 0)

            self.bat_icon_name = "view-refresh-symbolic"
            self.bat_image = Gtk.Image.new_from_icon_name(
                self.bat_icon_name, Gtk.IconSize.MENU)

            inner_hbox.pack_start(self.bat_image, False, False, 6)

            self.bat_label = Gtk.Label()
            inner_hbox.pack_start(self.bat_label, False, True, 6)

            if "battery" in settings["commands"] and settings["commands"][
                    "battery"]:
                img = Gtk.Image()
                update_image(img, "pan-end-symbolic", self.icon_size,
                             self.icons_path)
                inner_hbox.pack_end(img, False, True, 4)

            event_box.add(inner_vbox)

        check_key(settings, "custom-items", [])
        if settings["custom-items"]:
            for item in settings["custom-items"]:
                check_key(item, "name", "undefined")
                check_key(item, "icon", "")
                check_key(item, "cmd", "")
                c_item = self.custom_item(item["name"], item["icon"],
                                          item["cmd"])
                v_box.pack_start(c_item, True, True, 2)

        check_key(settings, "menu", {})
        if settings["menu"]:
            template = settings["menu"]

            sep = Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL)
            v_box.pack_start(sep, True, True, 10)

            e_box = Gtk.EventBox()
            box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
            e_box.add(box)
            inner_hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL,
                                 spacing=0)
            box.pack_start(inner_hbox, True, True, 6)
            v_box.pack_start(e_box, True, True, 6)

            img = Gtk.Image()
            update_image(img, template["icon"], self.icon_size,
                         self.icons_path)
            inner_hbox.pack_start(img, False, False, 6)

            check_key(template, "name", "Menu name")
            label = Gtk.Label(template["name"])
            inner_hbox.pack_start(label, False, False, 6)

            check_key(template, "items", [])
            if template["items"]:
                img = Gtk.Image()
                update_image(img, "pan-down-symbolic", self.icon_size,
                             self.icons_path)
                inner_hbox.pack_end(img, False, True, 5)

                e_box.connect("enter-notify-event", self.on_enter_notify_event)
                e_box.connect("leave-notify-event", self.on_leave_notify_event)

                self.menu_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL,
                                        spacing=6)
                v_box.pack_start(self.menu_box, False, False, 0)
                for item in template["items"]:
                    eb = Gtk.EventBox()
                    vb = Gtk.Box(orientation=Gtk.Orientation.VERTICAL,
                                 spacing=0)
                    hb = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL,
                                 spacing=0)
                    vb.pack_start(hb, False, False, 3)
                    i = Gtk.Label(item["name"])
                    hb.pack_start(i, False, False, self.icon_size + 18)
                    eb.add(vb)
                    eb.connect("enter_notify_event",
                               self.on_enter_notify_event)
                    eb.connect("leave_notify_event",
                               self.on_leave_notify_event)
                    eb.connect("button-press-event", self.launch, item["cmd"])
                    self.menu_box.pack_start(eb, False, False, 0)

                e_box.connect('button-press-event', self.switch_menu_box)

        Gdk.threads_add_timeout(GLib.PRIORITY_LOW, 500, self.refresh)
예제 #3
0
파일: main.py 프로젝트: KPWhiver/nwg-panel
def main():
    common.config_dir = get_config_dir()
    common.defaults = get_defaults()

    parser = argparse.ArgumentParser()
    parser.add_argument("-c",
                        "--config",
                        type=str,
                        default="config",
                        help="config filename (in {}/)".format(common.config_dir))

    parser.add_argument("-s",
                        "--style",
                        type=str,
                        default="style.css",
                        help="css filename (in {}/)".format(common.config_dir))

    parser.add_argument("-r",
                        "--restore",
                        action="store_true",
                        help="restore default config files")

    parser.add_argument("-v",
                        "--version",
                        action="version",
                        version="%(prog)s {}".format(__version__),
                        help="display version information")

    args = parser.parse_args()

    try:
        from pyalsa import alsamixer
        common.dependencies["pyalsa"] = True
    except:
        print("pylsa module not found, will try amixer")

    global restart_cmd
    restart_cmd = "nwg-panel -c {} -s {}".format(args.config, args.style)

    # Try and kill already running instance if any
    pid_file = os.path.join(temp_dir(), "nwg-panel.pid")
    if os.path.isfile(pid_file):
        try:
            pid = int(load_text_file(pid_file))
            os.kill(pid, signal.SIGINT)
            print("Running instance killed, PID {}".format(pid))
        except:
            pass
    save_string(str(os.getpid()), pid_file)

    save_string("-c {} -s {}".format(args.config, args.style), os.path.join(local_dir(), "args"))

    common.app_dirs = get_app_dirs()

    common.dependencies["amixer"] = is_command("amixer")

    config_file = os.path.join(common.config_dir, args.config)

    copy_files(os.path.join(dir_name, "icons_light"), os.path.join(common.config_dir, "icons_light"))
    copy_files(os.path.join(dir_name, "icons_dark"), os.path.join(common.config_dir, "icons_dark"))
    copy_executors(os.path.join(dir_name, "executors"), os.path.join(common.config_dir, "executors"))
    copy_files(os.path.join(dir_name, "config"), common.config_dir, args.restore)

    common.outputs = list_outputs(sway=sway)

    panels = load_json(config_file)

    screen = Gdk.Screen.get_default()
    provider = Gtk.CssProvider()
    style_context = Gtk.StyleContext()
    style_context.add_provider_for_screen(screen, provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
    try:
        provider.load_from_path(os.path.join(common.config_dir, args.style))
    except Exception as e:
        print(e)

    for panel in panels:
        check_key(panel, "icons", "")
        icons_path = ""
        if panel["icons"] == "light":
            icons_path = os.path.join(common.config_dir, "icons_light")
        elif panel["icons"] == "dark":
            icons_path = os.path.join(common.config_dir, "icons_dark")

        check_key(panel, "output", "")

        # This is to allow width "auto" value. Actually all non-numeric values will be removed.
        if "width" in panel and not isinstance(panel["width"], int):
            panel.pop("width")

        if panel["output"] in common.outputs or not panel["output"]:
            check_key(panel, "spacing", 6)
            check_key(panel, "css-name", "")
            check_key(panel, "padding-horizontal", 0)
            check_key(panel, "padding-vertical", 0)
            window = Gtk.Window()
            if panel["css-name"]:
                window.set_property("name", panel["css-name"])

            if "output" not in panel or not panel["output"]:
                display = Gdk.Display.get_default()
                monitor = display.get_monitor(0)
                for key in common.outputs:
                    if common.outputs[key]["monitor"] == monitor:
                        panel["output"] = key

            # Width undefined or "auto"
            if "output" in panel and panel["output"] and "width" not in panel:
                panel["width"] = common.outputs[panel["output"]]["width"]

            check_key(panel, "width", 0)
            w = panel["width"]

            check_key(panel["controls-settings"], "window-width", 0)
            controls_width = panel["controls-settings"]["window-width"] if panel["controls-settings"][
                                                                               "window-width"] > 0 else int(w / 5)
            check_key(panel, "height", 0)
            h = panel["height"]

            check_key(panel, "controls", "off")
            if panel["controls"]:
                check_key(panel, "controls-settings", {})

            if "controls-settings" in panel:
                controls_settings = panel["controls-settings"]
                check_key(controls_settings, "show-values", False)

            Gtk.Widget.set_size_request(window, w, h)

            vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
            hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
            vbox.pack_start(hbox, True, True, panel["padding-vertical"])

            check_key(panel, "modules-left", [])
            check_key(panel, "modules-center", [])
            check_key(panel, "modules-right", [])

            # This is to allow the "auto" value. Actually all non-numeric values will be removed.
            if "homogeneous" in panel and not isinstance(panel["homogeneous"], bool):
                panel.pop("homogeneous")

            # set equal columns width by default if "modules-center" not empty; this may be overridden in config
            if panel["modules-center"]:
                check_key(panel, "homogeneous", True)
            else:
                check_key(panel, "homogeneous", False)

            inner_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
            inner_box.set_homogeneous(panel["homogeneous"])

            hbox.pack_start(inner_box, True, True, panel["padding-horizontal"])

            left_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=panel["spacing"])
            inner_box.pack_start(left_box, False, True, 0)
            if panel["controls"] and panel["controls"] == "left":
                monitor = None
                try:
                    monitor = common.outputs[panel["output"]]["monitor"]
                except KeyError:
                    pass

                cc = Controls(panel["controls-settings"], panel["position"], panel["controls"],
                              controls_width, monitor=monitor, icons_path=icons_path)
                common.controls_list.append(cc)
                left_box.pack_start(cc, False, False, 0)

            instantiate_content(panel, left_box, panel["modules-left"], icons_path=icons_path)

            center_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=panel["spacing"])
            inner_box.pack_start(center_box, True, False, 0)
            check_key(panel, "modules-center", [])
            instantiate_content(panel, center_box, panel["modules-center"], icons_path=icons_path)

            right_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=panel["spacing"])
            # Damn on the guy who invented `pack_start(child, expand, fill, padding)`!
            helper_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
            helper_box.pack_end(right_box, False, False, 0)
            inner_box.pack_start(helper_box, False, True, 0)
            check_key(panel, "modules-right", [])
            instantiate_content(panel, right_box, panel["modules-right"], icons_path=icons_path)

            if panel["controls"] and panel["controls"] == "right":
                monitor = None
                try:
                    monitor = common.outputs[panel["output"]]["monitor"]
                except KeyError:
                    pass

                cc = Controls(panel["controls-settings"], panel["position"], panel["controls"],
                              controls_width, monitor=monitor, icons_path=icons_path)
                common.controls_list.append(cc)
                right_box.pack_end(cc, False, False, 0)

            window.add(vbox)

            GtkLayerShell.init_for_window(window)

            monitor = None
            try:
                monitor = common.outputs[panel["output"]]["monitor"]
            except KeyError:
                pass

            check_key(panel, "layer", "top")
            o = panel["output"] if "output" in panel else "undefined"
            print("Display: {}, position: {}, layer: {}, width: {}, height: {}".format(o, panel["position"],
                                                                                       panel["layer"], panel["width"],
                                                                                       panel["height"]))

            if monitor:
                GtkLayerShell.set_monitor(window, monitor)

            GtkLayerShell.auto_exclusive_zone_enable(window)

            if panel["layer"] == "top":
                GtkLayerShell.set_layer(window, GtkLayerShell.Layer.TOP)
            else:
                GtkLayerShell.set_layer(window, GtkLayerShell.Layer.BOTTOM)

            check_key(panel, "margin-top", 0)
            GtkLayerShell.set_margin(window, GtkLayerShell.Edge.TOP, panel["margin-top"])

            check_key(panel, "margin-bottom", 0)
            GtkLayerShell.set_margin(window, GtkLayerShell.Edge.BOTTOM, panel["margin-bottom"])

            if panel["position"] == "top":
                GtkLayerShell.set_anchor(window, GtkLayerShell.Edge.TOP, 1)
            else:
                GtkLayerShell.set_anchor(window, GtkLayerShell.Edge.BOTTOM, 1)

            window.show_all()

    Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 150, check_tree)

    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)

    Gtk.main()
예제 #4
0
    def __init__(self, position, settings, width, monitor=None):
        Gtk.Window.__init__(self, type_hint=Gdk.WindowTypeHint.NORMAL)
        GtkLayerShell.init_for_window(self)
        if monitor:
            GtkLayerShell.set_monitor(self, monitor)

        check_key(settings, "css-name", "controls-window")
        self.set_property("name", settings["css-name"])
        self.icon_size = settings["icon-size"]

        self.settings = settings
        self.position = position

        self.bt_icon_name = ""
        self.bt_image = Gtk.Image()

        eb = Gtk.EventBox()
        eb.set_above_child(False)
        self.connect("leave_notify_event", self.on_window_exit)

        outer_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
        eb.add(outer_vbox)
        self.add(eb)

        outer_hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
        Gtk.Widget.set_size_request(outer_hbox, width, 10)
        outer_vbox.pack_start(outer_hbox, True, True, 20)

        v_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
        outer_hbox.pack_start(v_box, True, True, 20)

        GtkLayerShell.set_layer(self, GtkLayerShell.Layer.TOP)
        # GtkLayerShell.set_keyboard_interactivity(self, True)
        GtkLayerShell.set_margin(self, GtkLayerShell.Edge.TOP, 6)
        GtkLayerShell.set_margin(self, GtkLayerShell.Edge.BOTTOM, 6)
        GtkLayerShell.set_margin(self, GtkLayerShell.Edge.RIGHT, 6)
        GtkLayerShell.set_margin(self, GtkLayerShell.Edge.LEFT, 6)

        if settings["alignment"] == "left":
            GtkLayerShell.set_anchor(self, GtkLayerShell.Edge.LEFT, True)
        else:
            GtkLayerShell.set_anchor(self, GtkLayerShell.Edge.RIGHT, True)
        if position == "bottom":
            GtkLayerShell.set_anchor(self, GtkLayerShell.Edge.BOTTOM, True)
        else:
            GtkLayerShell.set_anchor(self, GtkLayerShell.Edge.TOP, True)

        check_key(settings, "commands", {"battery": "", "net": ""})

        add_sep = False
        if "brightness" in settings["components"]:
            inner_hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
            v_box.pack_start(inner_hbox, False, False, 0)

            self.bri_icon_name = "view-refresh-symbolic"
            self.bri_image = Gtk.Image.new_from_icon_name(self.bri_icon_name, Gtk.IconSize.MENU)

            icon_name = bri_icon_name(int(get_brightness()))
            if icon_name != self.bri_icon_name:
                update_image(self.bri_image, icon_name, self.icon_size)
                self.bri_icon_name = icon_name

            inner_hbox.pack_start(self.bri_image, False, False, 6)

            scale = Gtk.Scale.new_with_range(orientation=Gtk.Orientation.HORIZONTAL, min=0, max=100, step=1)
            value = get_brightness()
            scale.set_value(value)
            scale.connect("value-changed", self.set_bri)

            inner_hbox.pack_start(scale, True, True, 5)
            add_sep = True

        if "volume" in settings["components"]:
            inner_hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
            v_box.pack_start(inner_hbox, False, False, 6)

            self.vol_icon_name = "view-refresh-symbolic"
            self.vol_image = Gtk.Image.new_from_icon_name(self.vol_icon_name, Gtk.IconSize.MENU)

            vol, switch = get_volume()
            icon_name = vol_icon_name(vol, switch)

            if icon_name != self.vol_icon_name:
                update_image(self.vol_image, icon_name, self.icon_size)
                self.vol_icon_name = icon_name

            inner_hbox.pack_start(self.vol_image, False, False, 6)

            scale = Gtk.Scale.new_with_range(orientation=Gtk.Orientation.HORIZONTAL, min=0, max=100, step=1)
            value, switch = get_volume()
            scale.set_value(value)
            scale.connect("value-changed", self.set_vol)

            inner_hbox.pack_start(scale, True, True, 5)
            add_sep = True

        if add_sep:
            sep = Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL)
            v_box.pack_start(sep, True, True, 10)

        if "net" in settings["components"] and dependencies["netifaces"]:
            event_box = Gtk.EventBox()
            if "net" in settings["commands"] and settings["commands"]["net"]:
                event_box.connect("enter_notify_event", self.on_enter_notify_event)
                event_box.connect("leave_notify_event", self.on_leave_notify_event)

                event_box.connect('button-press-event', self.launch, settings["commands"]["net"])

            inner_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
            inner_hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
            inner_vbox.pack_start(inner_hbox, True, True, 6)
            v_box.pack_start(event_box, True, True, 10)

            self.net_icon_name = "view-refresh-symbolic"
            self.net_image = Gtk.Image.new_from_icon_name(self.net_icon_name, Gtk.IconSize.MENU)

            ip_addr = get_interface(settings["net-interface"])
            icon_name = "network-wired-symbolic" if ip_addr else "network-wired-disconnected-symbolic"

            if icon_name != self.net_icon_name:
                update_image(self.net_image, icon_name, self.icon_size)
                self.net_icon_name = icon_name

            inner_hbox.pack_start(self.net_image, False, False, 6)

            self.net_label = Gtk.Label("{}: {}".format(settings["net-interface"], ip_addr))
            inner_hbox.pack_start(self.net_label, False, True, 6)

            if "net" in settings["commands"] and settings["commands"]["net"]:
                img = Gtk.Image()
                update_image(img, "pan-end-symbolic", self.icon_size)
                inner_hbox.pack_end(img, False, True, 4)

            event_box.add(inner_vbox)

        if bt_service_enabled() and "bluetooth" in settings["components"]:
            event_box = Gtk.EventBox()
            if "bluetooth" in settings["commands"] and settings["commands"]["bluetooth"]:
                event_box.connect("enter_notify_event", self.on_enter_notify_event)
                event_box.connect("leave_notify_event", self.on_leave_notify_event)

                event_box.connect('button-press-event', self.launch, settings["commands"]["bluetooth"])

            inner_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
            inner_hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
            inner_vbox.pack_start(inner_hbox, True, True, 6)
            v_box.pack_start(event_box, True, True, 6)

            self.bt_icon_name = "view-refresh-symbolic"
            self.bt_image = Gtk.Image.new_from_icon_name(self.bt_icon_name, Gtk.IconSize.MENU)

            icon_name = bt_icon_name(bt_on())

            if icon_name != self.bt_icon_name:
                update_image(self.bt_image, icon_name, self.icon_size)
                self.bt_icon_name = icon_name

            inner_hbox.pack_start(self.bt_image, False, False, 6)

            self.bt_label = Gtk.Label(bt_name())
            inner_hbox.pack_start(self.bt_label, False, True, 6)

            if "bluetooth" in settings["commands"] and settings["commands"]["bluetooth"]:
                img = Gtk.Image()
                update_image(img, "pan-end-symbolic", self.icon_size)
                inner_hbox.pack_end(img, False, True, 4)

            event_box.add(inner_vbox)

        if "battery" in settings["components"]:
            event_box = Gtk.EventBox()
            if "battery" in settings["commands"] and settings["commands"]["battery"]:
                event_box.connect("enter_notify_event", self.on_enter_notify_event)
                event_box.connect("leave_notify_event", self.on_leave_notify_event)

                event_box.connect('button-press-event', self.launch, settings["commands"]["battery"])

            inner_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
            inner_hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
            inner_vbox.pack_start(inner_hbox, True, True, 6)
            v_box.pack_start(event_box, True, True, 6)

            self.bat_icon_name = "view-refresh-symbolic"
            self.bat_image = Gtk.Image.new_from_icon_name(self.bat_icon_name, Gtk.IconSize.MENU)

            msg, level = get_battery()
            icon_name = bat_icon_name(level)

            if icon_name != self.bat_icon_name:
                update_image(self.bat_image, icon_name, self.icon_size)
                self.bat_icon_name = icon_name

            inner_hbox.pack_start(self.bat_image, False, False, 6)

            self.bat_label = Gtk.Label(msg)
            inner_hbox.pack_start(self.bat_label, False, True, 6)

            if "battery" in settings["commands"] and settings["commands"]["battery"]:
                img = Gtk.Image()
                update_image(img, "pan-end-symbolic", self.icon_size)
                inner_hbox.pack_end(img, False, True, 4)

            event_box.add(inner_vbox)

        check_key(settings, "custom-items", [])
        if settings["custom-items"]:
            for item in settings["custom-items"]:
                c_item = self.custom_item(item["name"], item["icon"], item["cmd"])
                v_box.pack_start(c_item, True, True, 6)

        check_key(settings, "menu", {})
        if settings["menu"]:
            template = settings["menu"]

            sep = Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL)
            v_box.pack_start(sep, True, True, 10)

            e_box = Gtk.EventBox()
            box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
            e_box.add(box)
            inner_hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
            box.pack_start(inner_hbox, True, True, 6)
            v_box.pack_start(e_box, True, True, 6)

            img = Gtk.Image()
            update_image(img, template["icon"], self.icon_size)
            inner_hbox.pack_start(img, False, False, 6)

            check_key(template, "name", "Menu name")
            label = Gtk.Label(template["name"])
            inner_hbox.pack_start(label, False, False, 6)

            check_key(template, "items", [])
            if template["items"]:
                img = Gtk.Image()
                update_image(img, "pan-end-symbolic", self.icon_size)
                inner_hbox.pack_end(img, False, True, 0)

                e_box.connect("enter-notify-event", self.on_enter_notify_event)
                e_box.connect("leave-notify-event", self.on_leave_notify_event)

                self.menu_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
                v_box.pack_start(self.menu_box, False, False, 0)
                for item in template["items"]:
                    eb = Gtk.EventBox()
                    vb = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
                    hb = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
                    vb.pack_start(hb, False, False, 6)
                    i = Gtk.Label(item["name"])
                    hb.pack_start(i, False, False, self.icon_size + 18)
                    eb.add(vb)
                    eb.connect("enter_notify_event", self.on_enter_notify_event)
                    eb.connect("leave_notify_event", self.on_leave_notify_event)
                    eb.connect("button-press-event", self.launch, item["cmd"])
                    self.menu_box.pack_start(eb, False, False, 0)

                e_box.connect('button-press-event', self.switch_menu_box)

        Gdk.threads_add_timeout_seconds(GLib.PRIORITY_LOW, settings["interval"], self.refresh)