Tried improved threading logic
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 858 B After Width: | Height: | Size: 858 B |
Before Width: | Height: | Size: 850 B After Width: | Height: | Size: 850 B |
Before Width: | Height: | Size: 702 B After Width: | Height: | Size: 702 B |
Before Width: | Height: | Size: 925 B After Width: | Height: | Size: 925 B |
Before Width: | Height: | Size: 882 B After Width: | Height: | Size: 882 B |
Before Width: | Height: | Size: 707 B After Width: | Height: | Size: 707 B |
Before Width: | Height: | Size: 798 B After Width: | Height: | Size: 798 B |
Before Width: | Height: | Size: 989 B After Width: | Height: | Size: 989 B |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
@ -31,7 +31,7 @@ class Settings:
|
||||
self.usrHome = os.path.expanduser('~')
|
||||
self.desktopPath = self.usrHome + "/Desktop"
|
||||
self.iconContainerWxH = [128, 128]
|
||||
self.systemIconImageWxH = [72, 72]
|
||||
self.systemIconImageWxH = [56, 56]
|
||||
self.viIconWxH = [256, 128]
|
||||
|
||||
self.DEFAULTCOLOR = gdk.RGBA(0.0, 0.0, 0.0, 0.0) # ~#00000000
|
@ -21,27 +21,28 @@ from utils.FileHandler import FileHandler
|
||||
def threaded(fn):
|
||||
def wrapper(*args, **kwargs):
|
||||
threading.Thread(target=fn, args=args, kwargs=kwargs).start()
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
class Grid:
|
||||
def __init__(self, grid, settings):
|
||||
self.grid = grid
|
||||
self.settings = settings
|
||||
self.fileHandler = FileHandler(self.settings)
|
||||
self.grid = grid
|
||||
self.settings = settings
|
||||
self.fileHandler = FileHandler(self.settings)
|
||||
|
||||
self.store = gtk.ListStore(GdkPixbuf.Pixbuf, str)
|
||||
self.usrHome = settings.returnUserHome()
|
||||
self.builder = settings.returnBuilder()
|
||||
self.ColumnSize = settings.returnColumnSize()
|
||||
self.vidsFilter = settings.returnVidsFilter()
|
||||
self.imagesFilter = settings.returnImagesFilter()
|
||||
self.iconFactory = Icon(settings)
|
||||
self.gtkLock = False # Thread checks for gtkLock
|
||||
self.threadLock = False # Gtk checks for thread lock
|
||||
self.helperThread = None # Helper thread object
|
||||
self.toWorkPool = [] # Thread fills pool and gtk empties it
|
||||
self.selectedFiles = []
|
||||
self.currentPath = ""
|
||||
self.store = gtk.ListStore(GdkPixbuf.Pixbuf, str)
|
||||
self.usrHome = settings.returnUserHome()
|
||||
self.hideHiddenFiles = settings.isHideHiddenFiles()
|
||||
self.builder = settings.returnBuilder()
|
||||
self.ColumnSize = settings.returnColumnSize()
|
||||
self.vidsFilter = settings.returnVidsFilter()
|
||||
self.imagesFilter = settings.returnImagesFilter()
|
||||
self.iconFactory = Icon(settings)
|
||||
self.helperThread = None # Helper thread object
|
||||
self.toWorkPool = [] # Thread fills pool and gtk empties it
|
||||
self.selectedFiles = []
|
||||
self.currentPath = ""
|
||||
|
||||
self.grid.set_model(self.store)
|
||||
self.grid.set_pixbuf_column(0)
|
||||
@ -51,8 +52,6 @@ class Grid:
|
||||
|
||||
|
||||
def setNewDirectory(self, path):
|
||||
self.store.clear()
|
||||
|
||||
self.currentPath = path
|
||||
dirPaths = ['.', '..']
|
||||
vids = []
|
||||
@ -62,15 +61,18 @@ class Grid:
|
||||
|
||||
for f in listdir(path):
|
||||
file = join(path, f)
|
||||
if self.settings.isHideHiddenFiles():
|
||||
if self.hideHiddenFiles:
|
||||
if f.startswith('.'):
|
||||
continue
|
||||
|
||||
if isfile(file):
|
||||
if file.lower().endswith(self.vidsFilter):
|
||||
lowerName = file.lower()
|
||||
|
||||
if lowerName.endswith(self.vidsFilter):
|
||||
vids.append(f)
|
||||
elif file.lower().endswith(self.imagesFilter):
|
||||
elif lowerName.endswith(self.imagesFilter):
|
||||
images.append(f)
|
||||
elif file.lower().endswith((".desktop",)):
|
||||
elif lowerName.endswith((".desktop",)):
|
||||
desktop.append(f)
|
||||
else:
|
||||
files.append(f)
|
||||
@ -82,53 +84,38 @@ class Grid:
|
||||
images.sort()
|
||||
desktop.sort()
|
||||
files.sort()
|
||||
files = dirPaths + vids + images + desktop + files
|
||||
|
||||
if self.helperThread:
|
||||
self.helperThread.terminate()
|
||||
self.helperThread = None
|
||||
files = dirPaths + vids + images + desktop + files
|
||||
self.store.clear()
|
||||
|
||||
# Run helper thread...
|
||||
self.threadLock = True
|
||||
self.helperThread = threading.Thread(target=self.generateGridIcon, args=(path, files)).start()
|
||||
glib.idle_add(self.addToGrid, (file,)) # NOTE: This must stay in the main thread b/c
|
||||
# gtk isn't thread safe/aware So, we
|
||||
# make a sad lil thread hot potato 'game'
|
||||
# out of this process.
|
||||
|
||||
self.helperThread = threading.Thread(target=self.generateGridIcons, args=(path, files))
|
||||
self.helperThread.daemon = True # Set this thread as a Daemon Thread
|
||||
self.helperThread.start()
|
||||
# self.generateGridIcons(path, files)
|
||||
glib.idle_add(self.addToGrid, (files,)) # NOTE: This must stay in the main thread b/c
|
||||
# gtk isn't thread safe/aware.
|
||||
|
||||
# @threaded
|
||||
def generateGridIcon(self, dirPath, files):
|
||||
# NOTE: We'll be passing pixbuf after retreval to keep Icon.py file more
|
||||
# universaly usable. We can just remove get_pixbuf to get a gtk.Image type
|
||||
def generateGridIcons(self, dirPath, files):
|
||||
for file in files:
|
||||
image = self.iconFactory.createIcon(dirPath, file)
|
||||
self.toWorkPool.append([image.get_pixbuf(), file])
|
||||
self.threadLock = False
|
||||
self.gtkLock = True
|
||||
self.toWorkPool.append([image, file])
|
||||
|
||||
|
||||
# NOTE: If nothing else is updating, this function gets called immediatly when return is True.
|
||||
# Returning False ends checks and "continues normal flow"
|
||||
def addToGrid(self, args):
|
||||
# NOTE: Returning true tells gtk to check again in the future when idle.
|
||||
# False ends checks and "continues normal flow"
|
||||
files = args[0]
|
||||
|
||||
if len(self.toWorkPool) > 0:
|
||||
for dataSet in self.toWorkPool:
|
||||
self.store.append(dataSet)
|
||||
self.store.append([dataSet[0].get_pixbuf(), dataSet[1]])
|
||||
|
||||
if len(self.store) == len(files): # Confirm processed all files and cleanup
|
||||
self.gtkLock = False
|
||||
self.threadLock = False
|
||||
self.toWorkPool.clear()
|
||||
self.toWorkPool.clear()
|
||||
if len(self.store) == len(files): # Processed all files
|
||||
return False
|
||||
# Check again when idle; If nothing else is updating, this function
|
||||
# gets called immediatly. So, we play hot potato by setting lock to Thread
|
||||
else:
|
||||
self.toWorkPool.clear()
|
||||
self.gtkLock = False
|
||||
self.threadLock = True
|
||||
time.sleep(.005) # Fixes refresh and up icon not being added.
|
||||
else: # Check again when idle
|
||||
return True
|
||||
|
||||
def iconDblLeftClick(self, widget, item):
|
@ -5,7 +5,6 @@ gi.require_version('Gdk', '3.0')
|
||||
|
||||
from gi.repository import Gtk as gtk
|
||||
from gi.repository import Gio as gio
|
||||
from gi.repository import GdkPixbuf
|
||||
from xdg.DesktopEntry import DesktopEntry
|
||||
|
||||
# Python Imports
|
||||
@ -50,10 +49,10 @@ class Icon:
|
||||
if isfile(hashImgPth) == False:
|
||||
self.generateVideoThumbnail(fullPath, hashImgPth)
|
||||
|
||||
thumbnl = self.createIconImageBuffer(hashImgPth, self.viIconWH)
|
||||
thumbnl = self.createScaledImage(hashImgPth, self.viIconWH)
|
||||
# Image Icon
|
||||
elif file.lower().endswith(self.imagesList):
|
||||
thumbnl = self.createIconImageBuffer(fullPath, self.viIconWH)
|
||||
thumbnl = self.createScaledImage(fullPath, self.viIconWH)
|
||||
# .desktop file parsing
|
||||
elif fullPath.lower().endswith( ('.desktop',) ):
|
||||
thumbnl = self.parseDesktopFiles(fullPath)
|
||||
@ -91,7 +90,7 @@ class Icon:
|
||||
hashImgPth = steamIconsDir + fileHash + ".jpg"
|
||||
if isfile(hashImgPth) == True:
|
||||
# Use video sizes since headers are bigger
|
||||
return self.createIconImageBuffer(hashImgPth, self.viIconWH)
|
||||
return self.createScaledImage(hashImgPth, self.viIconWH)
|
||||
|
||||
execStr = xdgObj.getExec()
|
||||
parts = execStr.split("steam://rungameid/")
|
||||
@ -110,9 +109,9 @@ class Icon:
|
||||
proc.wait()
|
||||
|
||||
# Use video sizes since headers are bigger
|
||||
return self.createIconImageBuffer(hashImgPth, self.viIconWH)
|
||||
return self.createScaledImage(hashImgPth, self.viIconWH)
|
||||
elif os.path.exists(icon):
|
||||
return self.createIconImageBuffer(icon, self.systemIconImageWH)
|
||||
return self.createScaledImage(icon, self.systemIconImageWH)
|
||||
else:
|
||||
for (dirpath, dirnames, filenames) in os.walk(iconsDirs):
|
||||
for file in filenames:
|
||||
@ -121,7 +120,7 @@ class Icon:
|
||||
altIconPath = dirpath + "/" + file
|
||||
break
|
||||
|
||||
return self.createIconImageBuffer(altIconPath, self.systemIconImageWH)
|
||||
return self.createScaledImage(altIconPath, self.systemIconImageWH)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return None
|
||||
@ -129,17 +128,15 @@ class Icon:
|
||||
|
||||
def getSystemThumbnail(self, filename, size):
|
||||
try:
|
||||
iconPath = None
|
||||
if os.path.exists(filename):
|
||||
file = gio.File.new_for_path(filename)
|
||||
info = file.query_info('standard::icon' , 0 , gio.Cancellable())
|
||||
gioFile = gio.File.new_for_path(filename)
|
||||
info = gioFile.query_info('standard::icon' , 0 , gio.Cancellable())
|
||||
icon = info.get_icon().get_names()[0]
|
||||
iconTheme = gtk.IconTheme.get_default()
|
||||
iconFile = iconTheme.lookup_icon(icon , size , 0)
|
||||
|
||||
if iconFile != None:
|
||||
iconPath = iconFile.get_filename()
|
||||
return self.createIconImageBuffer(iconPath, self.systemIconImageWH)
|
||||
iconData = iconTheme.lookup_icon(icon , size , 0)
|
||||
if iconData:
|
||||
iconPath = iconData.get_filename()
|
||||
return gtk.Image.new_from_file(iconPath) # This seems to cause a lot of core dump issues...
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
@ -149,15 +146,15 @@ class Icon:
|
||||
return None
|
||||
|
||||
|
||||
def createIconImageBuffer(self, path, wxh):
|
||||
def createScaledImage(self, path, wxh):
|
||||
try:
|
||||
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(path, wxh[0], wxh[1], False)
|
||||
pixbuf = gtk.Image.new_from_file(path).get_pixbuf()
|
||||
scaledPixBuf = pixbuf.scale_simple(wxh[0], wxh[1], 2) # 2 = BILINEAR and is best by default
|
||||
return gtk.Image.new_from_pixbuf(scaledPixBuf)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return None
|
||||
|
||||
return gtk.Image.new_from_pixbuf(pixbuf)
|
||||
|
||||
|
||||
def generateVideoThumbnail(self, fullPath, hashImgPth):
|
||||
try:
|
||||
proc = subprocess.Popen([self.thubnailGen, "-t", "65%", "-s", "300", "-c", "jpg", "-i", fullPath, "-o", hashImgPth])
|