diff options
-rwxr-xr-x | logout-manager-tcl.py | 113 |
1 files changed, 23 insertions, 90 deletions
diff --git a/logout-manager-tcl.py b/logout-manager-tcl.py index 5b0d29d..74c914b 100755 --- a/logout-manager-tcl.py +++ b/logout-manager-tcl.py @@ -28,25 +28,16 @@ # package: RPM | DPKG # tkinter: python36-tkinter | python3-tk # PIL: python36-pillow-tk | python3-pil.imagetk -# cairo: python36-cairo | python3-cairo -# Rsvg: python36-gobject | python3-gobject -from gi import require_version -require_version('Rsvg', '2.0') -from gi.repository import Rsvg -import os, sys, configparser, glob, re, cairo +import glob, re import tkinter as tk -import tkinter.ttk as ttk from functools import partial from pathlib import Path +from sys import path +# loading PIL.ImageTk after tkinter makes ImageTk use the PIL version, which supports PNG. This is important on tcl < 8.6 (that is, el7) from PIL import Image, ImageTk -sys.path.append("/home/bgirton/dev/logout-manager") +path.append("/home/bgirton/dev/logout-manager") import lmlib -#if TkVersion < 8.6: -# USE_PRIVATE_TCL_IMAGES = 1 -# print("Loading private PIL translation layter") -# def PhotoImage_from_png(file): -# return ImageTk.PhotoImage(file=file) config = lmlib.Initialize_config() actions = lmlib.Actions @@ -54,48 +45,6 @@ actions = lmlib.Actions # graphical classes and functions print("Loading graphics...") -def _alpha_blending(rgba, back): - "Return a rgb tuple composed from a rgba and back(ground) tuple/list." - paired = zip(rgba[:-1], back) - alpha = rgba[-1] - tmp = list() - for upper, lower in paired: - blend = (((255 - alpha) * lower) + (alpha * upper)) / 255 - tmp.append(blend) - - return(tuple(tmp)) - -def convert(bgra_buffer, width, height): - "Convert bgra buffer to photoimage put" - idx = 0 - end = len(bgra_buffer) - arguments = list() - - while idx < end: - rgba = (ord(bgra_buffer[idx + 2]), - ord(bgra_buffer[idx + 1]), - ord(bgra_buffer[idx + 0]), - ord(bgra_buffer[idx + 3])) - back = (255, 255, 255) - rgb = _alpha_blending(rgba, back) - arguments += rgb - idx += 4 - - template = ' '.join(height *['{%s}' % (''.join(width*["#%02x%02x%02x"]))]) - return(template % tuple(arguments)) - -def photoimage_from_svg(file_path_name): - '''Return a Tkinter.PhotoImage with the content set to the rendered SVG.''' - svg = rsvg.Handle(file=file_path_name) - width, height = svg.get_dimension_data()[:2] - surface = cairo.ImageSurface(cairo.FORMAT_RGB24, int(width), int(height)) - context = cairo.Context(surface) - svg.render_cairo(context) - image = tk.PhotoImage(width=width, height=height) - data = convert(surface.get_data(), width, height) - image.put(data) - return(image) - class Tooltip: ''' @@ -255,10 +204,8 @@ def tryint(s): return s def sort_sizes(x): - # I don't even know how this works. I mashed it together from so#46228101 - # WORKS return [tryint(c) for c in re.split('([0-9]+)',x.split("/")[5])] + # Original reference so#46228101 value = x.split("/")[5] - #return int(re.split("[^0-9]+",value)[0]) * 100 + int( re.split("[^0-9]+",value)[1] if len(value.split("@")) >= 2 else 0 ) return mynum(value, "all") def mynum(x, type = "all"): @@ -297,11 +244,11 @@ def get_filename_of_icon(name, theme = "hicolor", size = 48, category = "actions theme = "hicolor" # first, find all files underneath /usr/share/icons/$THEME/$SIZE - # WORKHERE, allow a prioritization of category, but tolerate any category if the requested category has no matches but another category does print("Finding filename of icon, theme=",theme,"category=",category,"name=",name) - # WORKHERE: this glob affects if scalable/ dir is included. When support for svg is added (which is beyond PIL), need to add a conditional and use a second glob if USE_SVG=1. + # FUTUREIMPROVEMENT: this glob affects if scalable/ dir is included. When support for svg is added (which is beyond PIL), need to add a conditional and use a second glob if USE_SVG=1. + # to exclude the scalable/ contents, replace dir 5 asterisk with [0-9]* results = [] - results = glob.glob("/usr/share/icons/"+theme+"/*/"+category+"/"+name+".*") + results = glob.glob("/usr/share/icons/"+theme+"/*/"+category+"/"+name+".{png,PNG}") if len(results) == 0: # no results with that category, so try all categories results = glob.glob("/usr/share/icons/"+theme+"/*/*/"+name+".*") @@ -328,7 +275,7 @@ def get_scaled_icon(icon_name, size = 24, icon_theme = "default", fallback_icon_ #print("Using icon theme",icon_theme) iconfilename = get_filename_of_icon(name=icon_name, theme=icon_theme, size=size, category=config.get_icon_category()) - # So now that we think we have derived the correct filename... + # So now we think we have derived the correct filename try: print("Trying icon file",iconfilename) # try an svg @@ -340,7 +287,7 @@ def get_scaled_icon(icon_name, size = 24, icon_theme = "default", fallback_icon_ except: print("Error with icon file.") return None - # If I ever add HiDPI stuff, multiple size here by the factor. So, size * 1.25 + # If I ever add HiDPI support, multiple size here by the factor. So, size * 1.25 photo.thumbnail(size=[size, size]) try: photo2 = ImageTk.PhotoImage(photo) @@ -353,46 +300,40 @@ class App: frame = tk.Frame(master) frame.grid(row=0) - self.buttonLock = tk.Button(frame, text="Lock", underline=3, command=partial(actions.lock,config)) - self.buttonLock.grid(row=0,column=0) - # WORKS master.bind_all("<Alt-k>", something) - # PASSES 2 params when expecting 1 master.bind_all("<Alt-k>", self.buttonLock.invoke) + self.photoLock = get_scaled_icon(config.get_lock_icon(), config.get_icon_size(), config.get_icon_theme()) + self.buttonLock = tk.Button(frame, text="Lock", underline=3, command=partial(actions.lock,config), image=self.photoLock, compound=tk.LEFT) master.bind_all("<Alt-k>", partial(actions.lock,config)) + Tooltip(self.buttonLock, text="Hide session and require authentication to return to it") + self.buttonLock.grid(row=0,column=0) - # WORKS, for basic image loading. - #self.photoLogout = get_scaled_icon("/usr/share/icons/Adwaita/48x48/actions/system-log-out.png") - #self.buttonLogout = tk.Button(frame, text="Logout", underline=0, command=lambda: actions.logout(config), image=self.photoLogout, compound=TOP) - #self.photoLogout1 = Image.open("/usr/share/icons/Adwaita/48x48/actions/system-log-out.png") - #self.photoLogout1.thumbnail(size=[24,24]) - #self.photoLogout = ImageTk.PhotoImage(self.photoLogout1,size="24x24") - #self.photoLogout = get_scaled_icon("/usr/share/icons/Adwaita/48x48/actions/system-log-out.png", 24) - #self.photoLogout = get_scaled_icon("system-log-out", 24, icon_theme="default") - print("Using configed icon theme:",config.get_icon_theme()) self.photoLogout = get_scaled_icon(config.get_logout_icon(), config.get_icon_size(), config.get_icon_theme()) self.buttonLogout = tk.Button(frame, text="Logout", underline=0, command=lambda: actions.logout(config), image=self.photoLogout, compound=tk.LEFT) master.bind_all("<Alt-l>", partial(actions.logout,config)) - Tooltip(self.buttonLogout, text="HERE IS SOMETHING!") + Tooltip(self.buttonLogout, text="Close the current user session") self.buttonLogout.grid(row=0,column=1) self.photoHibernate = get_scaled_icon(config.get_hibernate_icon(), config.get_icon_size(), config.get_icon_theme()) self.buttonHibernate = tk.Button(frame, text="Hibernate", underline=0, command=lambda: actions.hibernate(config), image=self.photoHibernate, compound=tk.LEFT) - self.buttonHibernate.grid(row=0,column=2) master.bind_all("<Alt-h>", partial(actions.hibernate,config)) + Tooltip(self.buttonHibernate, text="Save state to disk and power off") + self.buttonHibernate.grid(row=0,column=2) self.photoShutdown = get_scaled_icon(config.get_shutdown_icon(), config.get_icon_size(), config.get_icon_theme()) self.buttonShutdown = tk.Button(frame, text="Shutdown", underline=0, command=lambda: actions.shutdown(config), image=self.photoShutdown, compound=tk.LEFT) - self.buttonShutdown.grid(row=0,column=3) master.bind_all("<Alt-s>", partial(actions.shutdown,config)) + Tooltip(self.buttonShutdown, text="Power off the computer") + self.buttonShutdown.grid(row=0,column=3) self.photoReboot = get_scaled_icon(config.get_reboot_icon(), config.get_icon_size(), config.get_icon_theme()) self.buttonReboot = tk.Button(frame, text="Reboot", underline=0, command=lambda: actions.reboot(config), image=self.photoReboot, compound=tk.LEFT) - self.buttonReboot.grid(row=0,column=4) master.bind_all("<Alt-r>", partial(actions.reboot,config)) + Tooltip(self.buttonReboot, text="Reboot the computer back to the login screen") + self.buttonReboot.grid(row=0,column=4) - #self.buttonCancel = tk.Button(frame, text="Cancel", underline=0, command=frame.quit) self.buttonCancel = tk.Button(frame, text="Cancel", underline=0, command=self.quitaction) - self.buttonCancel.grid(row=1,columnspan=8,sticky=tk.W+tk.E) master.bind_all("<Alt-c>", self.quitaction) + Tooltip(self.buttonCancel, text="Do nothing; just close this window") + self.buttonCancel.grid(row=1,columnspan=8,sticky=tk.W+tk.E) # Found this after trial and error. def quitaction(self,b=None): @@ -407,15 +348,7 @@ root = tk.Tk() # MAIN LOOP root.title("Log out options") -#root.iconbitmap(r'/usr/share/icons/Numix/48/actions/system-logout.svg') imgicon = get_scaled_icon(config.get_logout_icon(),24,config.get_icon_theme()) -#if USE_PRIVATE_TCL_IMAGES is None: -# #imgicon = PhotoImage(file=os.path.join("/usr/share/icons/Adwaita/24x24/actions","system-log-out.png")) -# imgicon = get_scaled_icon(config.get_logout_icon(),24) -#else: -# #imgicon = PhotoImage_from_png(file=os.path.join("/usr/share/icons/Adwaita/24x24/actions","system-log-out.png")) -# imgicon = get_scaled_icon(config.get_logout_icon(),24) -#print(imgicon) root.tk.call('wm','iconphoto', root._w, imgicon) app = App(root) root.mainloop() |