Fluxlaunch §

Fluxlaunch est un lanceur d'applications qui apparaît dans la zone de notification (systray).

#!/usr/bin/env python3
# -*- coding:Utf-8 -*- 


"""
Auteur :      prx <prx@si3t.ch>  
licence :     GPLv2

Description : Met dans le systray des lanceurs d'application

Code inspiré de unapplet : 
http://download.tuxfamily.org/unapplet/
Merci à Michael Lange <klappnase@tuxfamily.org>

Dépendances : python3-pil python3-tk python3-pil.imagetk tk-tktray
"""


import os
from subprocess import Popen
import tkinter
from PIL import Image, ImageTk


default_config="""#/path/to/icon command
/usr/local/share/icons/Adwaita/16x16/categories/applications-internet.png,firefox
/usr/local/share/icons/Adwaita/16x16/categories/applications-other.png,thunar
"""

configfile = os.path.expanduser("~/.fluxlaunch.conf")


def which(program):
    #https://stackoverflow.com/questions/377017/test-if-executable-exists-in-python/377028#377028
    def is_exe(fpath):
        return os.path.isfile(fpath) and os.access(fpath, os.X_OK)

    fpath, fname = os.path.split(program)
    if fpath:
        if is_exe(program):
            return program
    else:
        for path in os.environ["PATH"].split(os.pathsep):
            path = path.strip('"')
            exe_file = os.path.join(path, program)
            if is_exe(exe_file):
                return exe_file

    return False


def edit_config(cf):
    for editor in ["geany","gedit","scite","kate", "mousepad", "leafpad"]:
        EDITOR = which(editor)
        if EDITOR:
            Popen([EDITOR, cf])
            break





def save_default():
    with open(configfile, "w") as default:
        default.write(default_config)

def load_config():
    if not os.path.isfile(configfile):
        save_default()
    with open(configfile, "r") as config:
        c = config.readlines()

    conf = []
    for l in c:
        l = l.strip()
        if not l.startswith('#') and len(l) > 0:
            a,b = l.split(',')
            conf.append([a.strip(), b.strip()])

    return(conf)


class Icon(tkinter.BaseWidget, tkinter.Wm):
    def __init__(self, master=None, cmd = None, cnf={}, **kw):

        if not master:
            if tkinter._support_default_root:
                if not tkinter._default_root:
                    tkinter._default_root = tkinter.Tk()
                master = tkinter._default_root
        self.TktrayVersion = master.tk.call('package', 'require', 'tktray')

        # stolen from tkinter.Toplevel
        if kw:
            cnf = tkinter._cnfmerge((cnf, kw))
        extra = ()
        for wmkey in ['screen', 'class_', 'class', 'visible', 'colormap']:
            if wmkey in cnf.keys():
                val = cnf[wmkey]
                # TBD: a hack needed because some keys
                # are not valid as keyword arguments
                if wmkey[-1] == '_': opt = '-'+wmkey[:-1]
                else: opt = '-'+wmkey
                extra = extra + (opt, val)
                del cnf[wmkey]
        tkinter.BaseWidget.__init__(self, master, 'tktray::icon', cnf, {}, extra)
        self.protocol("WM_DELETE_WINDOW", self.destroy)

        if cmd:
            self.bind("<ButtonPress-1>", lambda x: Popen(cmd))



class TrayApp():
    def __init__(self, conf):
        """
        conf : list of i
        i = [path/to/image cmd]
        """

        self.conf = conf

        self.root = tkinter.Tk()
        self.root.withdraw()

        self.menu = tkinter.Menu(self.root, tearoff=0)
        self.menu.add_command(label="Configurer", command=self.configure)
        self.menu.add_command(label="Quitter", command=self.root.destroy)

        for i in self.conf:
            if not os.path.isfile(i[0]):
                print("Can't find {}".format(i[0]))
            else:
                b = tkinter.Label(self.root)
                img = Image.open(i[0])
                b.img = ImageTk.PhotoImage(img)
                icon = Icon(image=b.img, cmd=i[1])
                icon.bind("<Button-3>", self.popup)

        self.root.mainloop()

    def popup(self,event):
        self.menu.post(event.x_root, event.y_root)

    def configure(self):
        edit_config(configfile)


if __name__ == '__main__':
    print("Running fluxlaunch")
    print("edit {} to change configuration".format(configfile))
    conf = load_config()

    TrayApp(conf)

Pour utiliser le script, enregistrez-le puis exécutez-le avec python3 :

python3 fluxlaunch.py
Running fluxlaunch
edit /home/xavier/.fluxlaunch.conf to change configuration

Il est nécessaire d'avoir les dépendances :

python3-pil python3-tk python3-pil.imagetk tk-tktray

Vous verrez apparaître quelques icônes dans le systray. Si ce n'est pas le cas, vous pouvez éditez le fichier ''~/.fluxlaunch.conf'' qui ressemble à ça :

# /path/to/icon command
/usr/share/icons/Adwaita/16x16/categories/applications-internet.png, firefox
/usr/share/icons/Adwaita/16x16/categories/applications-other.png, thunar

Très facile à comprendre, une icône par ligne suivie par la commande à lancer, les deux séparées d'une virgule.

Au final, vous n'avez plus qu'à cliquer sur une des petites icônes du tray pour lancer la commande voulue.