added layout structure

This commit is contained in:
Maxim Stewart 2020-03-29 19:07:06 -05:00
parent 668857f10c
commit 3436dd09ee
9 changed files with 921 additions and 21 deletions

Binary file not shown.

View File

@ -30,6 +30,9 @@
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child type="center">
<object class="GtkFileChooserButton" id="selectDirDialog">
<property name="visible">True</property>
@ -45,6 +48,22 @@
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButtonBox" id="taskBarWorkspacesVer">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="layout_style">start</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
@ -53,23 +72,66 @@
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<property name="can_focus">False</property>
<child>
<object class="GtkViewport">
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkIconView" id="Desktop">
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin">6</property>
<property name="selection_mode">multiple</property>
<property name="can_focus">False</property>
<child>
<object class="GtkIconView" id="Desktop">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin">6</property>
<property name="selection_mode">multiple</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="width_request">180</property>
<property name="height_request">64</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">never</property>
<property name="shadow_type">in</property>
<property name="max_content_width">225</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkBox" id="taskBarButtonsVer">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
@ -94,10 +156,9 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButtonBox" id="taskBarButtons">
<object class="GtkBox" id="taskBarButtonsHor">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="layout_style">start</property>
<child>
<placeholder/>
</child>
@ -113,7 +174,7 @@
</packing>
</child>
<child>
<object class="GtkButtonBox" id="taskBarWorkspaces">
<object class="GtkButtonBox" id="taskBarWorkspacesHor">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="layout_style">start</property>
@ -124,7 +185,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
<property name="position">1</property>
</packing>
</child>
</object>

View File

@ -27,7 +27,6 @@ class GridSignals:
# Add filter to allow only folders to be selected
selectDirDialog.add_filter(filefilter)
selectDirDialog.set_filename(self.currentPath)
print(selectDirDialog.get_filename())
self.setNewDirectory(selectDirDialog)
@ -35,9 +34,7 @@ class GridSignals:
newPath = widget.get_filename()
self.gridClss = Grid(self.gridObj, self.settings)
self.gridClss.setNewDirectory(newPath)
if not "~/Desktop/" in newPath:
self.settings.saveSettings(newPath)
self.settings.saveSettings(newPath)
# File control events

View File

@ -19,16 +19,29 @@ class TaskbarSignals:
def __init__(self, settings):
self.settings = settings
self.builder = self.settings.returnBuilder()
self.orientation = 1 # 0 = horizontal, 1 = vertical
self.setPagerWidget()
self.setTasklistWidget()
def setPagerWidget(self):
pager = wnck.Pager()
self.builder.get_object('taskBarWorkspaces').add(pager)
pager.set_orientation(self.orientation)
if self.orientation == 0:
self.builder.get_object('taskBarWorkspacesHor').add(pager)
else:
self.builder.get_object('taskBarWorkspacesVer').add(pager)
def setTasklistWidget(self):
barBtns = wnck.Tasklist()
barBtns.set_scroll_enabled(False)
barBtns.set_button_relief(2) # 0 = normal relief, 2 = no relief
barBtns.set_grouping(1) # 0 = mever group, 1 auto group, 2 = always group
self.builder.get_object('taskBarButtons').add(barBtns)
barBtns.set_grouping(1) # 0 = mever group, 1 auto group, 2 = always group
barBtns.set_orientation(self.orientation)
if self.orientation == 0:
self.builder.get_object('taskBarButtonsHor').add(barBtns)
else:
self.builder.get_object('taskBarButtonsVer').add(barBtns)

View File

@ -12,6 +12,8 @@ import os, subprocess, hashlib, threading
from os.path import isdir, isfile, join
# Application imports
from .icon_manager import easybuttons
def threaded(fn):
@ -91,7 +93,6 @@ class Icon:
try:
xdgObj = DesktopEntry(fullPath)
icon = xdgObj.getIcon()
iconsDirs = "/usr/share/icons"
altIconPath = ""
if "steam" in icon:
@ -128,6 +129,8 @@ class Icon:
elif os.path.exists(icon):
return self.createScaledImage(icon, self.systemIconImageWH)
else:
# return easybuttons.IconManager().getIcon(icon, 64)
iconsDirs = "/usr/share/icons"
for (dirpath, dirnames, filenames) in os.walk(iconsDirs):
for file in filenames:
appNM = "application-x-" + icon

View File

@ -0,0 +1,3 @@
from . import easybuttons
from . import execute
from . import filemonitor

View File

@ -0,0 +1,613 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2007-2014 Clement Lefebvre <root@linuxmint.com>
# Copyright (C) 2015 Martin Wimpress <code@ubuntu-mate.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
import os
import re
import shutil
import xdg.DesktopEntry
import xdg.Menu
import gi
gi.require_version('Gtk', '3.0')
from .execute import *
from .filemonitor import monitor as filemonitor
from gi.repository import Gtk, Gdk, GLib
from gi.repository import Pango
from gi.repository import GObject
class IconManager(GObject.GObject):
__gsignals__ = {
"changed" : (GObject.SignalFlags.RUN_LAST, None, () )
}
def __init__( self ):
GObject.GObject.__init__( self )
self.icons = { }
self.count = 0
# Some apps don't put a default icon in the default theme folder, so we will search all themes
def createTheme( d ):
theme = Gtk.IconTheme()
theme.set_custom_theme( d )
return theme
# This takes to much time and there are only a very few applications that use icons from different themes
#self.themes = map( createTheme, [ d for d in os.listdir( "/usr/share/icons" ) if os.path.isdir( os.path.join( "/usr/share/icons", d ) ) ] )
self.defaultTheme = Gtk.IconTheme.get_default()
# Setup and clean up the temp icon dir
configDir = GLib.get_user_config_dir()
self.iconDir = os.path.join(configDir, "mate-menu")
if not os.path.exists(self.iconDir):
os.makedirs(self.iconDir)
# Skip over files and dirs belonging to the applications plugin
contents = frozenset(os.listdir(self.iconDir)) - frozenset(('applications', 'applications.list'))
for fn in contents:
if os.path.isfile(os.path.join(self.iconDir, fn)):
print("Removing file : " + os.path.join(self.iconDir, fn))
os.remove(os.path.join(self.iconDir, fn))
else:
print(os.path.join(self.iconDir, fn) + " is not a file, skipping delete.")
self.defaultTheme.append_search_path(self.iconDir)
# Themes with the same content as the default them aren't needed
#self.themes = [ theme for theme in self.themes if theme.list_icons() != defaultTheme.list_icons() ]
self.themes = [ self.defaultTheme ]
# Listen for changes in the themes
for theme in self.themes:
theme.connect("changed", self.themeChanged )
def getIcon( self, iconName, iconSize ):
if not iconName:
return None
try:
iconFileName = ""
realIconName = ""
needTempFile = False
#[ iconWidth, iconHeight ] = self.getIconSize( iconSize )
if iconSize <= 0:
return None
elif os.path.isabs( iconName ):
iconFileName = iconName
needTempFile = True
else:
if iconName[-4:] in [".png", ".xpm", ".svg", ".gif"]:
realIconName = iconName[:-4]
else:
realIconName = iconName
if iconFileName and needTempFile and os.path.exists( iconFileName ):
tmpIconName = iconFileName.replace("/", "-")
realIconName = tmpIconName[:-4]
if not os.path.exists(os.path.join(self.iconDir, tmpIconName)):
shutil.copyfile(iconFileName, os.path.join(self.iconDir, tmpIconName))
self.defaultTheme.append_search_path(self.iconDir)
image = Gtk.Image()
icon_found = False
for theme in self.themes:
if theme.lookup_icon( realIconName, 0, Gtk.IconLookupFlags.FORCE_REGULAR ):
icon_found = True
break
if icon_found:
image.set_from_icon_name(realIconName, Gtk.IconSize.DND)
image.set_pixel_size(iconSize)
else:
image = None
return image
except Exception as e:
print("Exception " + e.__class__.__name__ + ": " + e.message)
return None
def themeChanged( self, theme ):
self.emit( "changed" )
GObject.type_register(IconManager)
class easyButton( Gtk.Button ):
def __init__( self, iconName, iconSize, labels = None, buttonWidth = -1, buttonHeight = -1 ):
GObject.GObject.__init__( self )
self.connections = [ ]
self.iconName = iconName
self.iconSize = iconSize
self.showIcon = True
self.set_relief( Gtk.ReliefStyle.NONE )
self.set_size_request( buttonWidth, buttonHeight )
HBox1 = Gtk.Box( orientation=Gtk.Orientation.HORIZONTAL )
HBox1.set_valign(Gtk.Align.CENTER)
HBox1.set_hexpand(True)
self.labelBox = Gtk.Box( orientation=Gtk.Orientation.VERTICAL, spacing=2 )
self.buttonImage = Gtk.Image()
icon = self.getIcon( self.iconSize )
if icon:
self.buttonImage = icon
else:
#[ iW, iH ] = iconManager.getIconSize( self.iconSize )
self.buttonImage.set_size_request( self.iconSize, self.iconSize )
self.image_box = Gtk.Box( orientation=Gtk.Orientation.HORIZONTAL )
self.image_box.pack_start(self.buttonImage, False, False, 5)
self.image_box.show_all()
HBox1.pack_start( self.image_box, False, False, 0 )
if labels:
for label in labels:
if isinstance( label, str ):
self.addLabel( label )
elif isinstance( label, list ):
self.addLabel( label[0], label[1] )
self.labelBox.show()
HBox1.pack_start( self.labelBox , True, True, 0)
HBox1.show()
self.add( HBox1 )
self.set_events(Gdk.EventMask.POINTER_MOTION_MASK)
self.connectSelf( "motion-notify-event", self.onMotion )
self.connectSelf( "enter-notify-event", self.onEnter )
self.connectSelf( "focus-in-event", self.onFocusIn )
self.connectSelf( "focus-out-event", self.onFocusOut )
self.connectSelf( "destroy", self.onDestroy )
self.connect( "released", self.onRelease )
# Reload icons when the theme changed
self.themeChangedHandlerId = iconManager.connect("changed", self.themeChanged )
def connectSelf( self, event, callback ):
self.connections.append( self.connect( event, callback ) )
def onMotion( self, widget, event ):
# Only grab if mouse is actually hovering
if self.mouse_entered:
self.grab_focus()
self.mouse_entered = False
def onEnter( self, widget, event ):
# Prevent false "enter" notifications by determining
# whether the mouse is actually hovering on the button.
self.mouse_entered = True
def onFocusIn( self, widget, event ):
self.set_state_flags( Gtk.StateFlags.PRELIGHT, False )
def onFocusOut( self, widget, event ):
self.unset_state_flags( Gtk.StateFlags.PRELIGHT )
def onRelease( self, widget ):
widget.get_style_context().set_state( Gtk.StateFlags.NORMAL )
def onDestroy( self, widget ):
self.buttonImage.clear()
iconManager.disconnect( self.themeChangedHandlerId )
for connection in self.connections:
self.disconnect( connection )
del self.connections
def addLabel( self, text, styles = None ):
label = Gtk.Label()
if "<b>" in text or "<span" in text:
label.set_markup(text.replace('&', '&amp;')) # don't remove our pango
else:
label.set_text(text)
if styles:
labelStyle = Pango.AttrList()
for attr in styles:
labelStyle.insert( attr )
label.set_attributes( labelStyle )
label.set_ellipsize( Pango.EllipsizeMode.END )
if (Gtk.MAJOR_VERSION, Gtk.MINOR_VERSION) >= (3, 16):
label.set_xalign(0.0)
label.set_yalign(1.0)
else:
label.set_alignment( 0.0, 1.0 )
label.set_max_width_chars(0)
label.show()
self.labelBox.pack_start( label , True, True, 0)
def getIcon ( self, iconSize ):
if not self.iconName:
return None
icon = iconManager.getIcon( self.iconName, iconSize )
if icon is None:
icon = iconManager.getIcon( "gtk-missing-image", iconSize )
return icon
def setIcon ( self, iconName ):
self.iconName = iconName
self.iconChanged()
# IconTheme changed, setup new button icons
def themeChanged( self, theme ):
self.iconChanged()
def iconChanged( self ):
icon = self.getIcon( self.iconSize )
self.buttonImage.destroy()
if icon:
self.buttonImage = icon
self.image_box.pack_start(self.buttonImage, False, False, 5)
self.image_box.show_all()
else:
#[iW, iH ] = iconManager.getIconSize( self.iconSize )
self.buttonImage.set_size_request( self.iconSize, self.iconSize )
def setIconSize( self, size ):
self.iconSize = size
icon = self.getIcon( self.iconSize )
self.buttonImage.destroy()
if icon:
self.buttonImage = icon
self.image_box.pack_start(self.buttonImage, False, False, 5)
self.image_box.show_all()
elif self.iconSize:
#[ iW, iH ] = iconManager.getIconSize( self.iconSize )
self.buttonImage.set_size_request( self.iconSize, self.iconSize )
class ApplicationLauncher( easyButton ):
def __init__( self, desktopFile, iconSize):
if isinstance( desktopFile, xdg.Menu.MenuEntry ):
desktopItem = desktopFile.DesktopEntry
desktopFile = desktopItem.filename
self.appDirs = desktop.desktopFile.AppDirs
elif isinstance( desktopFile, xdg.Menu.DesktopEntry ):
desktopItem = desktopFile
desktopFile = desktopItem.filename
self.appDirs = [ os.path.dirname( desktopItem.filename ) ]
else:
desktopItem = xdg.DesktopEntry.DesktopEntry( desktopFile )
self.appDirs = [ os.path.dirname( desktopFile ) ]
self.desktopFile = desktopFile
self.startupMonitorId = 0
self.relevance = 0
self.loadDesktopEntry( desktopItem )
self.desktopEntryMonitors = []
base = os.path.basename( self.desktopFile )
for dir in self.appDirs:
self.desktopEntryMonitors.append( filemonitor.addMonitor( os.path.join(dir, base) , self.desktopEntryFileChangedCallback ) )
easyButton.__init__( self, self.appIconName, iconSize )
self.setupLabels()
# Drag and Drop
self.connectSelf( "drag-data-get", self.dragDataGet )
targets = ( Gtk.TargetEntry.new( "text/plain", 0, 100 ), Gtk.TargetEntry.new( "text/uri-list", 0, 101 ) )
self.drag_source_set( Gdk.ModifierType.BUTTON1_MASK, targets, Gdk.DragAction.COPY )
icon = self.getIcon( Gtk.IconSize.DND )
if icon:
iconName, s = icon.get_icon_name()
self.drag_source_set_icon_name( iconName )
self.connectSelf( "focus-in-event", self.onFocusIn )
self.connectSelf( "focus-out-event", self.onFocusOut )
self.connectSelf( "clicked", self.execute )
def loadDesktopEntry( self, desktopItem ):
try:
self.appName = desktopItem.getName()
self.appGenericName = desktopItem.getGenericName()
self.appComment = desktopItem.getComment()
self.appExec = desktopItem.getExec().replace('\\\\', '\\')
self.appIconName = desktopItem.getIcon()
self.appCategories = desktopItem.getCategories()
self.appMateDocPath = desktopItem.get( "X-MATE-DocPath" ) or ""
self.useTerminal = desktopItem.getTerminal()
self.appPath = desktopItem.getPath()
self.appName = self.appName.strip()
self.appGenericName = self.appGenericName.strip()
self.appComment = self.appComment.strip()
configPath = os.environ.get( "XDG_CONFIG_HOME",
os.path.join( os.environ["HOME"], ".config" ) )
basename = os.path.basename( self.desktopFile )
self.startupFilePath = os.path.join( configPath, "autostart", basename )
if self.startupMonitorId:
filemonitor.removeMonitor( self.startupMonitorId )
if os.path.exists (self.startupFilePath):
self.startupMonitorId = filemonitor.addMonitor( self.startupFilePath, self.startupFileChanged )
except Exception as e:
print(e)
self.appName = ""
self.appGenericName = ""
self.appComment = ""
self.appExec = ""
self.appIconName = ""
self.appCategories = ""
self.appDocPath = ""
self.startupMonitorId = 0
def onFocusIn( self, widget, event ):
super(ApplicationLauncher, self).onFocusIn( widget, event )
self.set_relief( Gtk.ReliefStyle.HALF )
def onFocusOut( self, widget, event ):
super(ApplicationLauncher, self).onFocusOut( widget, event )
self.set_relief( Gtk.ReliefStyle.NONE )
def setupLabels( self ):
self.addLabel( self.appName )
def filterText( self, text ):
keywords = text.lower().split()
self.relevance = 0
appName = self.appName.lower()
appGenericName = self.appGenericName.lower()
appComment = self.appComment.lower()
appExec = self.appExec.lower()
for keyword in keywords:
keyw = keyword
# Hide if the term does not match
if keyw != "" and appName.find( keyw ) == -1 and appGenericName.find( keyw ) == -1 and appComment.find( keyw ) == -1 and appExec.find( keyw ) == -1:
self.hide()
return False
# Give better ranking to the actual app name
if appName == keyw:
self.relevance += 32
elif appName.find( keyw ) == 0:
self.relevance += 16
elif appName.find( keyw ) != -1:
self.relevance += 8
if appExec.find( keyw ) != -1:
self.relevance += 4
if appComment.find( keyw ) != -1:
self.relevance += 2
if appGenericName.find( keyw ) != -1:
self.relevance += 1
self.show()
return True
def getTooltip( self ):
tooltip = self.appName
if self.appComment != "" and self.appComment != self.appName:
tooltip = tooltip + "\n" + self.appComment
return tooltip
def dragDataGet( self, widget, context, selection, targetType, eventTime ):
if targetType == 100: # text/plain
selection.set_text( "'" + self.desktopFile + "'", -1 )
elif targetType == 101: # text/uri-list
if self.desktopFile[0:7] == "file://":
selection.set_uris( [ self.desktopFile ] )
else:
selection.set_uris( [ "file://" + self.desktopFile ] )
def execute( self, *args ):
def pathExists(file):
if os.path.exists(file):
return True
for path in os.environ["PATH"].split(os.pathsep):
if os.path.exists(os.path.join(path, file)):
return True
if self.appExec:
if self.useTerminal:
if pathExists("mate-terminal"):
cmd = "mate-terminal -e \"" + self.appExec + "\""
elif pathExists("x-terminal-emulator"):
cmd = "x-terminal-emulator -e \"" + self.appExec + "\""
else:
cmd = "xterm -e \"" + self.appExec + "\""
Execute(cmd, self.appPath)
else:
Execute(self.appExec, self.appPath)
# IconTheme changed, setup new icons for button and drag 'n drop
def iconChanged( self ):
easyButton.iconChanged( self )
icon = self.getIcon( Gtk.IconSize.DND )
if icon:
iconName, size = icon.get_icon_name()
self.drag_source_set_icon_name( iconName )
def startupFileChanged( self, *args ):
self.inStartup = os.path.exists( self.startupFilePath )
def removeFromStartup( self ):
if os.path.exists( self.startupFilePath ):
os.remove( self.startupFilePath )
def addToFavourites( self ):
configPath = os.environ.get( "XDG_CONFIG_HOME",
os.path.join( os.environ["HOME"], ".config" ) )
favouritesDir = os.path.join( configPath, "mate-menu", "applications" );
if not os.path.exists( favouritesDir ):
os.makedirs( favouritesDir )
shutil.copyfile( self.desktopFile, self.favouritesFilePath )
def removeFromFavourites( self ):
if os.path.exists( self.favouritesFilePath ):
os.remove( self.favouritesFilePath )
def isInStartup( self ):
#return self.inStartup
return os.path.exists( self.startupFilePath )
def onDestroy( self, widget ):
easyButton.onDestroy( self, widget )
if self.startupMonitorId:
filemonitor.removeMonitor( self.startupMonitorId )
for id in self.desktopEntryMonitors:
filemonitor.removeMonitor( id )
def desktopEntryFileChangedCallback (self):
GLib.timeout_add(200, self.onDesktopEntryFileChanged)
def onDesktopEntryFileChanged( self ):
exists = False
base = os.path.basename( self.desktopFile )
for dir in self.appDirs:
if os.path.exists( os.path.join( dir, base ) ):
# print(os.path.join( dir, base ), self.desktopFile)
self.loadDesktopEntry( xdg.DesktopEntry.DesktopEntry( os.path.join( dir, base ) ) )
for child in self.labelBox:
child.destroy()
self.iconName = self.appIconName
self.setupLabels()
self.iconChanged()
exists = True
break
if not exists:
# FIXME: What to do in this case?
self.destroy()
return False
class MenuApplicationLauncher( ApplicationLauncher ):
def __init__( self, desktopFile, iconSize, category, showComment, highlight=False ):
self.showComment = showComment
self.appCategory = category
self.highlight = highlight
ApplicationLauncher.__init__( self, desktopFile, iconSize )
def filterCategory( self, category ):
if self.appCategory == category or category == "":
self.show()
else:
self.hide()
def setupLabels( self ):
appName = self.appName
appComment = self.appComment
if self.highlight:
try:
#color = self.labelBox.get_style_context().get_color( Gtk.StateFlags.SELECTED ).to_string()
#if len(color) > 0 and color[0] == "#":
#appName = "<span foreground=\"%s\"><b>%s</b></span>" % (color, appName);
#appComment = "<span foreground=\"%s\"><b>%s</b></span>" % (color, appComment);
#appName = "<b>%s</b>" % (appName);
#appComment = "<b>%s</b>" % (appComment);
#else:
#appName = "<b>%s</b>" % (appName);
#appComment = "<b>%s</b>" % (appComment);
appName = "<b>%s</b>" % (appName);
appComment = "<b>%s</b>" % (appComment);
except Exception as detail:
print(detail)
pass
if self.showComment and self.appComment != "":
if self.iconSize <= 2:
self.addLabel( '<span size="small">%s</span>' % appName)
self.addLabel( '<span size="x-small">%s</span>' % appComment)
else:
self.addLabel( appName )
self.addLabel( '<span size="small">%s</span>' % appComment)
else:
self.addLabel( appName )
def execute( self, *args ):
self.highlight = False
for child in self.labelBox:
child.destroy()
self.setupLabels()
return super(MenuApplicationLauncher, self).execute(*args)
def setShowComment( self, showComment ):
self.showComment = showComment
for child in self.labelBox:
child.destroy()
self.setupLabels()
class FavApplicationLauncher( ApplicationLauncher ):
def __init__( self, desktopFile, iconSize, swapGeneric = False ):
self.swapGeneric = swapGeneric
ApplicationLauncher.__init__( self, desktopFile, iconSize )
def setupLabels( self ):
if self.appGenericName:
if self.swapGeneric:
self.addLabel( '<span weight="bold">%s</span>' % self.appName )
self.addLabel( self.appGenericName )
else:
self.addLabel( '<span weight="bold">%s</span>' % self.appGenericName )
self.addLabel( self.appName )
else:
self.addLabel( '<span weight="bold">%s</span>' % self.appName )
if self.appComment != "":
self.addLabel( self.appComment )
else:
self.addLabel ( "" )
def setSwapGeneric( self, swapGeneric ):
self.swapGeneric = swapGeneric
for child in self.labelBox:
child.destroy()
self.setupLabels()
class CategoryButton( easyButton ):
def __init__( self, iconName, iconSize, labels , f ):
easyButton.__init__( self, iconName, iconSize, labels )
self.filter = f
self.set_focus_on_click(False)
iconManager = IconManager()

View File

@ -0,0 +1,74 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2007-2014 Clement Lefebvre <root@linuxmint.com>
# Copyright (C) 2015 Martin Wimpress <code@ubuntu-mate.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
import os
import shlex
import subprocess
def RemoveArgs(Execline):
NewExecline = []
Specials=["\"%c\"", "%f","%F","%u","%U","%d","%D","%n","%N","%i","%c","%k","%v","%m","%M", "-caption", "/bin/sh", "sh", "-c", "STARTED_FROM_MENU=yes"]
for elem in Execline:
elem = elem.replace("'","")
elem = elem.replace("\"", "")
if elem not in Specials:
print(elem)
NewExecline.append(elem)
return NewExecline
# Actually execute the command
def ExecuteCommand(cmd , commandCwd=None):
if not commandCwd:
cwd = os.path.expanduser( "~" );
else:
tmpCwd = os.path.expanduser( commandCwd );
if (os.path.exists(tmpCwd)):
cwd = tmpCwd
if isinstance( cmd, str ):
if (cmd.find("/home/") >= 0) or (cmd.find("xdg-su") >= 0) or (cmd.find("\"") >= 0):
print("running manually...")
try:
os.chdir(cwd)
subprocess.Popen(shlex.split(cmd))
return True
except Exception as detail:
print(detail)
return False
cmd = cmd.split()
cmd = RemoveArgs(cmd)
try:
os.chdir( cwd )
string = ' '.join(cmd)
subprocess.Popen(shlex.split(string))
return True
except Exception as detail:
print(detail)
return False
# Execute cmd using the double fork method
def Execute(cmd, commandCwd=None):
child_pid = os.fork()
if child_pid == 0:
ExecuteCommand(cmd, commandCwd)
os._exit(0)
else:
os.wait()

View File

@ -0,0 +1,136 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2007-2014 Clement Lefebvre <root@linuxmint.com>
# Copyright (C) 2015 Martin Wimpress <code@ubuntu-mate.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
import os
import os.path
import threading
import time
from gi.repository import GLib
try:
import pyinotify
hasInotify = True
except ImportError:
hasInotify = False
if hasInotify:
class FileMonitor(object):
def __init__( self ):
self.monitorId = 0
self.wm = pyinotify.WatchManager()
self.wdds = {}
self.callbacks = {}
self.notifier = pyinotify.ThreadedNotifier(self.wm, self.fileChanged)
self.notifier.setDaemon( True )
self.notifier.start()
def addMonitor( self, filename, callback, args = None ):
try:
mask = pyinotify.IN_DELETE | pyinotify.IN_CREATE | pyinotify.IN_MODIFY
mId = self.wm.add_watch( filename, mask, rec = True)[filename]
if mId >= 0:
self.callbacks[mId] = ( callback, args )
except Exception as detail:
mId = 0
return mId
def removeMonitor( self, monitorId ):
if monitorId in self.callbacks:
self.wm.rm_watch( monitorId )
del self.callbacks[monitorId]
def fileChanged(self, event ):
if event.wd in self.callbacks:
callback = self.callbacks[event.wd]
if callback[1]:
GLib.idle_add( callback[0], callback[1] )
else:
GLib.idle_add( callback[0] )
else:
class _MonitoredFile( object ):
def __init__( self, filename, callback, monitorId, args ):
self.filename = filename
self.callback = callback
self.monitorId = monitorId
self.args = args
self.exists = os.path.exists( self.filename )
if self.exists:
self.mtime = os.stat( filename ).st_mtime
else:
self.mtime = 0
def hasChanged( self ):
if os.path.exists( self.filename ):
if not self.exists:
self.exists = True
self.mtime = os.stat( self.filename ).st_mtime
return True
else:
mtime = os.stat( self.filename ).st_mtime
if mtime != self.mtime:
self.mtime = mtime
return True
else:
if self.exists:
self.exists = False
return True
return False
class MonitorThread(threading.Thread):
def __init__(self, monitor):
threading.Thread.__init__ ( self )
self.monitor = monitor
def run(self):
while(1):
self.monitor.checkFiles()
time.sleep(1)
class FileMonitor(object):
def __init__( self ):
self.monitorId = 0
self.monitoredFiles = []
self.monitorThread = MonitorThread( self )
self.monitorThread.setDaemon( True )
self.monitorThread.start()
def addMonitor( self, filename, callback, args = None ):
self.monitorId += 1
self.monitoredFiles.append( _MonitoredFile( filename, callback, self.monitorId, args ) )
return self.monitorId
def removeMonitor( self, monitorId ):
for monitored in self.monitoredFiles:
if monitorId == monitored.monitorId:
self.monitoredFiles.remove( monitored )
break
def checkFiles( self ):
for monitored in self.monitoredFiles:
if monitored.hasChanged():
if monitored.args:
GLib.idle_add( monitored.callback, monitored.args )
else:
GLib.idle_add( monitored.callback )
monitor = FileMonitor()