aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB Stack <bgstack15@gmail.com>2019-06-13 23:11:28 -0400
committerB Stack <bgstack15@gmail.com>2019-06-13 23:11:28 -0400
commit8ef7f6d4d0b27f7a8b74fd7a63438342d1efe33d (patch)
tree2bf809bb7f1629c18300d38f847d4ce9057381e6
parentadd main components for tcl frontend (diff)
downloadlogout-manager-8ef7f6d4d0b27f7a8b74fd7a63438342d1efe33d.tar.gz
logout-manager-8ef7f6d4d0b27f7a8b74fd7a63438342d1efe33d.tar.bz2
logout-manager-8ef7f6d4d0b27f7a8b74fd7a63438342d1efe33d.zip
add rudimentary freedesktop.org icon theme support
After much ripping off of StackOverflow, the python/tcl frontend now has the functions in place to use /usr/share/icons themes, as long as they are using png files (tcl8.6). More work is needed on tcl8.5 (no png support). SVGs are not supported, but are planned for future commits. Many functions are added here that search for the valid filenames, and sort them by size-dirname, then find the first one that meets or exceeds the requested size.
-rwxr-xr-xlogout-manager-tcl.py116
1 files changed, 104 insertions, 12 deletions
diff --git a/logout-manager-tcl.py b/logout-manager-tcl.py
index c605dc0..b9d9997 100755
--- a/logout-manager-tcl.py
+++ b/logout-manager-tcl.py
@@ -1,5 +1,8 @@
#!/usr/bin/env python3
# Startdate: 2019-06-12 20:05
+# Dependencies:
+# python36-tkinter | python3-tk
+# python36-pillow-tk | python3-pil.imagetk
# WORKHERE:
# add icons
# add full headers
@@ -12,12 +15,18 @@
# alternate for passing params https://stackoverflow.com/questions/6920302/how-to-pass-arguments-to-a-button-command-in-tkinter
# https://stackoverflow.com/questions/18537918/set-window-icon#18538416
# the exact syntax <Alt-k> for master.bind https://stackoverflow.com/questions/16082243/how-to-bind-ctrl-in-python-tkinter
+# https://pillow.readthedocs.io/en/stable/reference/ImageTk.html
+# gtk-3.0 default icon theme https://coderwall.com/p/no3qfa/setting-gtk2-and-gtk3-theme-via-config-file
+# homedir https://stackoverflow.com/questions/4028904/how-to-get-the-home-directory-in-python
+# natural sort https://stackoverflow.com/questions/46228101/sort-list-of-strings-by-two-substrings-using-lambda-function/46228199#46228199
-import os, sys
-sys.path.append("/home/bgirton/dev/logout-manager")
-import lmlib
+import os, sys, configparser, glob, re
from tkinter import *
from functools import partial
+from pathlib import Path
+from PIL import Image, ImageTk
+sys.path.append("/home/bgirton/dev/logout-manager")
+import lmlib
config = lmlib.Initialize_config()
actions = lmlib.Actions
@@ -25,13 +34,89 @@ actions = lmlib.Actions
# graphical classes and functions
print("Loading graphics...")
-def icon_bitmap(name = "", theme = "default", size = "48"):
- # WORKHERE: can build some tool that loops through the icon theme dirs
+def get_gtk3_default_theme():
+ # abstracted so it does not clutter get_scaled_icon
+ name = None
+ gtk3_config_path = os.path.join(os.path.expanduser("~"),".config","gtk-3.0","settings.ini")
+ gtk3_config = configparser.ConfigParser()
+ gtk3_config.read(gtk3_config_path)
+ try:
+ if 'Settings' in gtk3_config:
+ name = gtk3_config['Settings']['gtk-icon-theme-name']
+ elif 'settings' in gtk3_config:
+ name = gtk3_config['settings']['gtk-icon-theme-name']
+ except:
+ # supposed failsafe
+ name = "hicolor"
+ return name
+
+def tryint(s):
+ try:
+ return int(s)
+ except:
+ 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])]
+ 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"):
+ # return the complicated numerical value for the weird size options
+ if type == "all":
+ return int(re.split("[^0-9]+",x)[0]) * 100 + int( re.split("[^0-9]+",x)[1] if len(re.split("[^0-9]+",x)) >= 2 else 0 )
+ else:
+ return int(re.split("[^0-9]+",x)[0])
+
+def find_best_size_match(size, thelist):
+ # return item from sorted thelist whose split("/")[5] is the first to meet or exceed the requested size
+ return next(( i for i in thelist if mynum(i.split("/")[5],"real") >= size ), thelist[-1])
+
+def get_filename_of_icon(name, theme = "hicolor", size = 48, category = "actions"):
+ # poor man's attempt at walking through fd.o icon theme
+ filename = None
+ # example: Adwaita system-log-out
+
+ # first, find all files underneath /usr/share/icons/$THEME/$SIZE
+ print("Finding filename of icon.")
+ results = glob.glob("/usr/share/icons/"+theme+"/*/"+category+"/"+name+".*")
+ # the sort arranges it so a Numix/24 dir comes before a Numix/24@2x dir
+ results = sorted(results, key=sort_sizes)
+ #print(results)
+ # now find the first one that matches
+ filename = find_best_size_match(size,results)
+ return filename
+
+def get_scaled_icon(icon_name, size = 24, fallback_icon_name = "", icon_theme = "default"):
+ iconfilename = None
+
# if name is a specific filename, just use it.
- # if the only thing that is found during the looping is a svg, return None
- # if the valid file provided is svg, then try a few derivations to get a png, else return None
- imgicon = PhotoImage(file=os.path.join("/usr/share/icons/Adwaita/24x24/actions","system-log-out.png"))
- return imgicon
+ if Path(icon_name).is_file():
+ #print("This is a file:",icon_name)
+ iconfilename = icon_name
+ else:
+
+ if icon_theme == "default":
+ # retrieve default theme from config file
+ #print("Discovering default icon theme...")
+ icon_theme = get_gtk3_default_theme()
+ # so now that icon_theme is defined, let us go find the icon that matches the requested name and size, in the actions category
+ #print("Using icon theme",icon_theme)
+ iconfilename = get_filename_of_icon(name=icon_name, theme=icon_theme, size=size)
+
+ # So now that we think we have derived the correct filename...
+ try:
+ print("Trying icon file",iconfilename)
+ photo = Image.open(iconfilename)
+ except:
+ print("Error with icon file.")
+ return None
+ # If I ever add HiDPI stuff, multiple size here by the factor. So, size * 1.25
+ photo.thumbnail(size=[size, size])
+ photo2 = ImageTk.PhotoImage(photo)
+ return photo2
class App:
def __init__(self, master):
@@ -39,15 +124,22 @@ class App:
frame.grid(row=0)
self.buttonLock = Button(frame, text="Lock", underline=3, command=partial(actions.lock,config))
- #self.buttonLock.pack(side=LEFT)
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)
master.bind_all("<Alt-k>", partial(actions.lock,config))
- self.buttonLogout = Button(frame, text="Logout", underline=0, command=lambda: actions.logout(config))
- self.buttonLogout.grid(row=0,column=1)
+ # WORKS, for basic image loading.
+ #self.photoLogout = get_scaled_icon("/usr/share/icons/Adwaita/48x48/actions/system-log-out.png")
+ #self.buttonLogout = 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")
+ self.buttonLogout = Button(frame, text="Logout", underline=0, command=lambda: actions.logout(config), image=self.photoLogout, compound=LEFT)
master.bind_all("<Alt-l>", partial(actions.logout,config))
+ self.buttonLogout.grid(row=0,column=1)
self.buttonHibernate = Button(frame, text="Hibernate", underline=0, command=lambda: actions.hibernate(config))
self.buttonHibernate.grid(row=0,column=2)
bgstack15