aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lmlib.py4
-rwxr-xr-xlogout-manager-tcl.py89
2 files changed, 80 insertions, 13 deletions
diff --git a/lmlib.py b/lmlib.py
index 67b207f..2b0d6f9 100644
--- a/lmlib.py
+++ b/lmlib.py
@@ -11,12 +11,11 @@
# Reference:
# platform info https://stackoverflow.com/questions/110362/how-can-i-find-the-current-os-in-python/10091465#10091465
# Improve:
-# detect if el7, use icon_category = "apps". This should be an internal variable (not listed in .conf)
# Documentation:
import configparser, platform
-logout_manager_version="2019-06-14a"
+logout_manager_version="2019-06-14b"
class Actions:
@@ -225,6 +224,7 @@ def Initialize_config():
# written primarily for el7 which uses "app" for the system-reboot icons, etc.
a = platform.dist()
try:
+ # WORKHERE: after moving in the gtk3 default icon theme check to lmlib, do a check here, for of the theme=default and gtk3_default=hicolor, to make category=apps
if a[0] == "redhat" and int(a[1].split(".")[0]) <= 7:
config.set_icon_category("apps")
except:
diff --git a/logout-manager-tcl.py b/logout-manager-tcl.py
index 694a648..afe6632 100755
--- a/logout-manager-tcl.py
+++ b/logout-manager-tcl.py
@@ -20,13 +20,20 @@
# 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
# tooltips https://stackoverflow.com/questions/3221956/how-do-i-display-tooltips-in-tkinter/41381685#41381685
+# rsvg https://stackoverflow.com/questions/10393675/rsvg-with-python-3-2-on-ubuntu/19744099#19744099
# Improve:
# add svg support
# Dependencies:
-# python36-tkinter | python3-tk
-# python36-pillow-tk | python3-pil.imagetk
-
-import os, sys, configparser, glob, re
+# 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 tkinter as tk
import tkinter.ttk as ttk
from functools import partial
@@ -46,6 +53,48 @@ 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:
'''
@@ -199,6 +248,7 @@ class Tooltip:
self.tw = None
def get_gtk3_default_theme():
+ # WORKHERE: move this to lmlib
# abstracted so it does not clutter get_scaled_icon
name = "hicolor"
gtk3_config_path = os.path.join(os.path.expanduser("~"),".config","gtk-3.0","settings.ini")
@@ -212,6 +262,7 @@ def get_gtk3_default_theme():
except:
# supposed failsafe
name = "hicolor"
+ print("Found gtk3 default theme:",name)
return name
def tryint(s):
@@ -230,10 +281,18 @@ def sort_sizes(x):
def mynum(x, type = "all"):
# return the complicated numerical value for the weird size options
f = re.split("[^0-9]+",x)
+ try:
+ f0 = int(f[0])
+ except:
+ f0 = 0
+ try:
+ f1 = int(f[1])
+ except:
+ f1 = 0
if type == "all":
- return int(f[0]) * 100 + int( f[1] if len(f) >= 2 else 0 )
+ return f0 * 100 + f1 if len(f) >= 2 else 0
else:
- return int(f[0])
+ return f0
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
@@ -252,9 +311,10 @@ 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.
- results = glob.glob("/usr/share/icons/"+theme+"/*[0-9]*/"+category+"/"+name+".*")
+ 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)
@@ -262,7 +322,7 @@ def get_filename_of_icon(name, theme = "hicolor", size = 48, category = "actions
filename = find_best_size_match(size,results)
return filename
-def get_scaled_icon(icon_name, size = 24, fallback_icon_name = "", icon_theme = "default"):
+def get_scaled_icon(icon_name, size = 24, icon_theme = "default", fallback_icon_name = ""):
iconfilename = None
# if name is a specific filename, just use it.
@@ -273,16 +333,21 @@ def get_scaled_icon(icon_name, size = 24, fallback_icon_name = "", icon_theme =
if icon_theme == "default":
# retrieve default theme from config file
- #print("Discovering default icon theme...")
+ 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, category=config.get_icon_category())
-
+
# So now that we think we have derived the correct filename...
try:
print("Trying icon file",iconfilename)
- photo = Image.open(iconfilename)
+ # try an svg
+ if re.compile(".*\.svg").match(iconfilename):
+ print("Trying svg...")
+ photo = photoimage_from_svg(iconfilename)
+ else:
+ photo = Image.open(iconfilename)
except:
print("Error with icon file.")
return None
@@ -313,6 +378,7 @@ class App:
#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))
@@ -360,6 +426,7 @@ 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()
bgstack15