From bd8a4eead95cf42dffb4d64aa52d2d2dfc846115 Mon Sep 17 00:00:00 2001 From: Davy Renaud Date: Thu, 18 Aug 2011 11:31:11 +0300 Subject: [PATCH 01/17] Update the config file location for 2.3 release The config file location to get the default VGL_COMPRESS value has changed. The UI need to know it in order to set the value of the compression combobox at init. --- app/Config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100755 => 100644 app/Config.py diff --git a/app/Config.py b/app/Config.py old mode 100755 new mode 100644 index fe82ed9..77aa586 --- a/app/Config.py +++ b/app/Config.py @@ -65,7 +65,7 @@ to_unconfigure_color='#FF0033' #BUMBLEBEE DEFAULT CONFIGURATION -config_file_path='/etc/default/bumblebee' +config_file_path='/etc/bumblebee/bumblebee.conf' [default_compression]=[re.sub(r'VGL_COMPRESS=(.*)\n', r'\1', line) for line in open(config_file_path) if 'VGL_COMPRESS' in line] #CATEGORIES CONFIGURATION From daccf2d6a867faa674b58a8d4eb1a08ab29a0461 Mon Sep 17 00:00:00 2001 From: Davy Renaud Date: Thu, 18 Aug 2011 11:35:21 +0300 Subject: [PATCH 02/17] Remove reference to ecoptirun in the install script --- INSTALL | 4 ---- 1 file changed, 4 deletions(-) diff --git a/INSTALL b/INSTALL index f7d460e..c695000 100644 --- a/INSTALL +++ b/INSTALL @@ -32,9 +32,6 @@ ######################################## #NEED TO BE TESTED -#Copy ecoptirun : a modified script to take up to date manually -#cp ecoptirun /usr/local/bin --> Moved to the bumblebee project.. - #Copy software files /app, /icons, bumblebee-indicator in /usr/local/bin cp -R app/ /usr/local/bin/app cp -R icons/ /usr/local/bin/icons @@ -53,7 +50,6 @@ cp icons/bumblebee.svg /usr/share/icons/ #Set the correct right for some files chmod +x /usr/local/bin/bumblebee-indicator chmod +x /usr/local/bin/app/* -chmod +x /usr/local/bin/ecoptirun chmod +x /usr/share/applications/bumblebee-app-settings.desktop chmod +x /usr/share/applications/bumblebee-indicator.desktop From 12474cae939664daa706c7e0df435d78dabc1c81 Mon Sep 17 00:00:00 2001 From: Davy RENAUD Date: Thu, 18 Aug 2011 11:01:15 +0200 Subject: [PATCH 03/17] Get the display value once only at init of indicator There might be a better way to get the value inside the file, but the most important with this change is do avoid this check every two seconds!!! --- bumblebee-indicator | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/bumblebee-indicator b/bumblebee-indicator index 0e3dfa0..1b0c8d6 100755 --- a/bumblebee-indicator +++ b/bumblebee-indicator @@ -37,6 +37,7 @@ import pynotify #SYSTEM MODULE import os +import re import subprocess ###ORIGINAL CLASS @@ -64,6 +65,10 @@ class BumblebeeIndicator(): #TODO The icons style and accesibility must be enhanced : see icons/test directory self.ind.set_icon(app.Config.icon_file_directory + "bumblebee-indicator.svg",'Bumblebee is unactive') self.ind.set_attention_icon (app.Config.icon_file_directory + "bumblebee-indicator-active.svg",'Bumblebee is active') + + [vgl_display]=[re.sub(r'VGL_DISPLAY=:(.*)\n', r'\1', line) for line in open(app.Config.config_file_path) if 'VGL_DISPLAY' in line] + self.lock_file = "/tmp/.X%s-lock" % vgl_display + print self.lock_file self.card_state=False @@ -145,10 +150,7 @@ class BumblebeeIndicator(): return True def attention_state_condition(self): - stdout_handle = os.popen("cat /etc/default/bumblebee |grep VGL_DISPLAY |cut -f2 -d:", "r") - vgl_display = stdout_handle.read().rstrip("\n") - vgl_display = "/tmp/.X%s-lock" % vgl_display - if os.path.exists(vgl_display): return True + if os.path.exists(self.lock_file): return True else: return False def set_attention_state(self, notify=True): From 5df0aa8e3a13acd29dacdf9e8128e2adba34b97a Mon Sep 17 00:00:00 2001 From: Lekensteyn Date: Thu, 18 Aug 2011 11:13:27 +0200 Subject: [PATCH 04/17] Ignore .pyc files --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0d20b64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc From e35c7889675e688712ce1978822729d853aaefde Mon Sep 17 00:00:00 2001 From: Davy RENAUD Date: Thu, 18 Aug 2011 12:26:31 +0200 Subject: [PATCH 05/17] Change the bumblebee-ui.cfg for a dynamic check of configured files The bumblebee-ui.cfg file is not needed anymore because the configured app are determined for the indicator by parsing the local desktop file to look if there are configured. This doesn't fix tuxmouraille now but a solution will be found soon. --- app/AppSettings.py | 19 ------------------- app/Config.py | 4 ---- app/DesktopFile.py | 22 +++++----------------- bumblebee-indicator | 13 ++++++------- 4 files changed, 11 insertions(+), 47 deletions(-) diff --git a/app/AppSettings.py b/app/AppSettings.py index 4f47ec9..702369e 100755 --- a/app/AppSettings.py +++ b/app/AppSettings.py @@ -37,24 +37,6 @@ import Config from DesktopFile import DesktopFile, DesktopFileSet -#CREATE FILE IF NOT EXIST -if os.path.exists(Config.ui_config_file_path): - print "Using configuration file: " + Config.ui_config_file_path -else: - print "Configuration File does not exist, creating.." - configdir = os.path.dirname(Config.ui_config_file_directory) - try: - os.stat(configdir) - except: - os.mkdir(configdir) - - file = open(Config.ui_config_file_path, 'w') - file.write("[Bumblebee UI]\n") - file.write("preferred_app = []\n") - file.write("\n") - file.close() - - #ICON CONFIGURATION class IconSet: """This small class contain the settings computed for categories""" @@ -358,7 +340,6 @@ def apply_app_set (self,widget,data=None): False, False, False, Config.to_configure_color) self.to_unconfigure_file.clear() self.config_app_view.expand_all() - self.file_set.store_configured() def apply_app_change (self, iter, file_name, actions, configured, mode, display_bg, bg_color): actions[0](file_name) diff --git a/app/Config.py b/app/Config.py index 77aa586..61b2384 100644 --- a/app/Config.py +++ b/app/Config.py @@ -42,10 +42,6 @@ #ICONS FILE PATH icon_file_directory = '/usr/share/bumblebee-ui/icons/' -#CONFIG FILES PATH -ui_config_file_directory = user_desktop_file_directory -ui_config_file_path = ui_config_file_directory + 'bumblebee-ui.cfg' - #ACCEPTED COMPRESSION compression_list=['jpeg','proxy','rgb','yuv','xv'] diff --git a/app/DesktopFile.py b/app/DesktopFile.py index 8bce3c9..385403c 100755 --- a/app/DesktopFile.py +++ b/app/DesktopFile.py @@ -48,7 +48,7 @@ class DesktopFileSet: def __init__(self): self.get_local() self.get_global() - self.get_configured_from_cfg() + #self.get_configured_from_check() def get_desktop_file_set(self, directory): return set([re.sub(r'(.*)\.desktop',r'\1',x) for x in glob.glob1( directory, '*.desktop' )]) @@ -61,21 +61,10 @@ def get_global (self): ##CAN BE TEST SO THERE IS NO CONFIGURATION FILE BUT THE UPLOAD IS LONGER #FIXME The preferred app list should be check dynamically with a special function to parse user file( conf is needed when bumblebee indicator change -# def get_configured_from_check (self): -# self.configured_set = set([ app for app in list(self.local_set) if DesktopFile(app).is_configured() ]) - - def get_configured_from_cfg (self): - self.open_cfg() - self.configured_set = set(eval(self.ui_config.get('Bumblebee UI','preferred_app'))) - - def open_cfg (self): - self.ui_config = ConfigParser.RawConfigParser() - self.ui_config.read(Config.ui_config_file_path) - - def store_configured (self): - self.open_cfg() - self.ui_config.set('Bumblebee UI','preferred_app', str(list(self.configured_set))) - with open(Config.ui_config_file_path,'w') as file_object: self.ui_config.write(file_object) + def get_configured_from_check (self): + self.get_local() + self.configured_set = set([ app for app in list(self.local_set) if DesktopFile(app).is_configured() ]) + print "The list of configured app is get by parsing the local desktop files" def get_apps_info (self): for file_name in self.local_set: @@ -84,7 +73,6 @@ def get_apps_info (self): app_config = desktop_file.get_app_config() if app_config[0]==True : self.configured_set.add(file_name) yield app_info_list + [True] + app_config - self.store_configured() for file_name in self.global_set: app_info_list = DesktopFile(file_name, local=False).get_app_info() yield app_info_list + [True] + 4*[False] + ['default'] diff --git a/bumblebee-indicator b/bumblebee-indicator index 1b0c8d6..d56b4e3 100755 --- a/bumblebee-indicator +++ b/bumblebee-indicator @@ -65,13 +65,12 @@ class BumblebeeIndicator(): #TODO The icons style and accesibility must be enhanced : see icons/test directory self.ind.set_icon(app.Config.icon_file_directory + "bumblebee-indicator.svg",'Bumblebee is unactive') self.ind.set_attention_icon (app.Config.icon_file_directory + "bumblebee-indicator-active.svg",'Bumblebee is active') - - [vgl_display]=[re.sub(r'VGL_DISPLAY=:(.*)\n', r'\1', line) for line in open(app.Config.config_file_path) if 'VGL_DISPLAY' in line] - self.lock_file = "/tmp/.X%s-lock" % vgl_display - print self.lock_file self.card_state=False + [vgl_display]=[re.sub(r'VGL_DISPLAY=:(.*)\n', r'\1', line) for line in open(app.Config.config_file_path) if 'VGL_DISPLAY' in line] + self.lock_file = "/tmp/.X%s-lock" % vgl_display + self.build_menu() self.menu.show() @@ -124,7 +123,7 @@ class BumblebeeIndicator(): subitem.connect("activate", self.call_app, ['optirun', 'glxgears']) subitem.show() self.pref_menu.append(subitem) - file_set.get_configured_from_cfg() + file_set.get_configured_from_check() for file_name in file_set.configured_set: [Name, File_name, Categorie, Icon_name] = DesktopFile(file_name).get_app_info() subitem = gtk.MenuItem(label=Name) @@ -150,7 +149,7 @@ class BumblebeeIndicator(): return True def attention_state_condition(self): - if os.path.exists(self.lock_file): return True + if os.path.exists(self.lock_file): return True else: return False def set_attention_state(self, notify=True): @@ -172,7 +171,7 @@ class BumblebeeIndicator(): def call_app(self, widget, app_exec): #FIXME There is a problem when closing the launched app and when the indicator has been closed: the indicator is still running : What a daemon!! - subprocess.Popen(app_exec,shell=False) + subprocess.Popen(app_exec,shell=False) def about_box(self, widget, data=None): dialog = gtk.MessageDialog(None, type=gtk.MESSAGE_INFO,buttons=gtk.BUTTONS_NONE,message_format="Preferences/About") From 55a1b1a3047672b124909b92ee576bae72c15c13 Mon Sep 17 00:00:00 2001 From: Davy RENAUD Date: Thu, 18 Aug 2011 14:25:40 +0200 Subject: [PATCH 06/17] Clean the way the configuration are get inside bumblebee.conf file The value are parsed when importing Config.py --- app/Config.py | 12 ++++++++++-- bumblebee-indicator | 3 +-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/Config.py b/app/Config.py index 61b2384..20298f9 100644 --- a/app/Config.py +++ b/app/Config.py @@ -29,7 +29,6 @@ import os import glob -import re import gtk import ConfigParser @@ -62,7 +61,16 @@ #BUMBLEBEE DEFAULT CONFIGURATION config_file_path='/etc/bumblebee/bumblebee.conf' -[default_compression]=[re.sub(r'VGL_COMPRESS=(.*)\n', r'\1', line) for line in open(config_file_path) if 'VGL_COMPRESS' in line] +#GET BUMBLEBEE CONFIGURATION VALUE +def get_config_value(variable_name): + """Function to get configuration value inside a shell script""" + for line in open(config_file_path): + if variable_name in line: + variable, value= line.split('=',1) + return value.replace("\n","") + +default_compression= get_config_value('VGL_COMPRESS') +vgl_display= get_config_value('VGL_DISPLAY').replace(":","") #CATEGORIES CONFIGURATION diff --git a/bumblebee-indicator b/bumblebee-indicator index d56b4e3..b713692 100755 --- a/bumblebee-indicator +++ b/bumblebee-indicator @@ -68,8 +68,7 @@ class BumblebeeIndicator(): self.card_state=False - [vgl_display]=[re.sub(r'VGL_DISPLAY=:(.*)\n', r'\1', line) for line in open(app.Config.config_file_path) if 'VGL_DISPLAY' in line] - self.lock_file = "/tmp/.X%s-lock" % vgl_display + self.lock_file = "/tmp/.X%s-lock" % app.Config.vgl_display self.build_menu() From e0a5aba748c466f2a11a4ec0763c49cacd8d1318 Mon Sep 17 00:00:00 2001 From: Davy RENAUD Date: Thu, 18 Aug 2011 16:03:18 +0200 Subject: [PATCH 07/17] Cleaning some rests of bumblebee-ui.cfg file Also commented the about box that i have to change to the about proposed by tuxmourraille --- app/AppSettings.py | 7 ++----- app/DesktopFile.py | 7 ------- bumblebee-indicator | 15 +++++++-------- 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/app/AppSettings.py b/app/AppSettings.py index 702369e..e5a99c7 100755 --- a/app/AppSettings.py +++ b/app/AppSettings.py @@ -70,17 +70,14 @@ class Applications_settings(): def delete_event(self,widget,event,data=None): return False - - ##FIXME There is a problem with subprocess: there is maybe a cleaner way to get it def destroy(self,widget): if __name__=="__main__": gtk.main_quit() else : self.window.destroy() - def __init__(self, file_set=DesktopFileSet()): + def __init__(self): #FIXME Seems not to be clean or shorter enough - self.file_set=file_set - + self.file_set=DesktopFileSet() self.icon_set=IconSet() ### MAIN WINDOW self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) diff --git a/app/DesktopFile.py b/app/DesktopFile.py index 385403c..0bbb550 100755 --- a/app/DesktopFile.py +++ b/app/DesktopFile.py @@ -48,7 +48,6 @@ class DesktopFileSet: def __init__(self): self.get_local() self.get_global() - #self.get_configured_from_check() def get_desktop_file_set(self, directory): return set([re.sub(r'(.*)\.desktop',r'\1',x) for x in glob.glob1( directory, '*.desktop' )]) @@ -59,19 +58,15 @@ def get_local (self): def get_global (self): self.global_set = self.get_desktop_file_set(Config.global_desktop_file_directory) - self.local_set - ##CAN BE TEST SO THERE IS NO CONFIGURATION FILE BUT THE UPLOAD IS LONGER - #FIXME The preferred app list should be check dynamically with a special function to parse user file( conf is needed when bumblebee indicator change def get_configured_from_check (self): self.get_local() self.configured_set = set([ app for app in list(self.local_set) if DesktopFile(app).is_configured() ]) - print "The list of configured app is get by parsing the local desktop files" def get_apps_info (self): for file_name in self.local_set: desktop_file = DesktopFile(file_name, local=True) app_info_list = desktop_file.get_app_info() app_config = desktop_file.get_app_config() - if app_config[0]==True : self.configured_set.add(file_name) yield app_info_list + [True] + app_config for file_name in self.global_set: app_info_list = DesktopFile(file_name, local=False).get_app_info() @@ -88,7 +83,6 @@ def configure_file (self, file_name): self.global_set.remove(file_name) print 'Bumblebee Shortcuts added to a desktop file created: ' + file_name else : print "ERROR : The app name of configured file is not recognized" - self.configured_set.add(file_name) def unconfigure_file (self, file_name): if DesktopFile(file_name).unconfigure_file(): @@ -96,7 +90,6 @@ def unconfigure_file (self, file_name): self.global_set.add(file_name) print 'Desktop file created for Bumblebee removed: ' + file_name else: print 'Desktop file modified for Bumblebee is unconfigured: ' + file_name - self.configured_set.remove(file_name) #TODO : Rewrite in order to allow use of the script without user interface diff --git a/bumblebee-indicator b/bumblebee-indicator index b713692..d60a68e 100755 --- a/bumblebee-indicator +++ b/bumblebee-indicator @@ -37,7 +37,6 @@ import pynotify #SYSTEM MODULE import os -import re import subprocess ###ORIGINAL CLASS @@ -166,18 +165,18 @@ class BumblebeeIndicator(): self.switch.set_active(False) def app_configure(self,widget): - Applications_settings(file_set=file_set) + Applications_settings() def call_app(self, widget, app_exec): #FIXME There is a problem when closing the launched app and when the indicator has been closed: the indicator is still running : What a daemon!! subprocess.Popen(app_exec,shell=False) - def about_box(self, widget, data=None): - dialog = gtk.MessageDialog(None, type=gtk.MESSAGE_INFO,buttons=gtk.BUTTONS_NONE,message_format="Preferences/About") - dialog.format_secondary_text("This is Optimus by mrs_sheep. \n It is based on bumblebee by MrMEEE. \n The configuration can (by now) only be set thorugh the config file!") - dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE) - dialog.run() - dialog.destroy() +# def about_box(self, widget, data=None): +# dialog = gtk.MessageDialog(None, type=gtk.MESSAGE_INFO,buttons=gtk.BUTTONS_NONE,message_format="Preferences/About") +# dialog.format_secondary_text("This is Optimus by mrs_sheep. \n It is based on bumblebee by MrMEEE. \n The configuration can (by now) only be set thorugh the config file!") +# dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE) +# dialog.run() +# dialog.destroy() def main(self): From 9ccaef2ee4da735aab2cfb37f9b9de7b2d0c1f1e Mon Sep 17 00:00:00 2001 From: Davy RENAUD Date: Thu, 18 Aug 2011 17:57:49 +0200 Subject: [PATCH 08/17] Cleaning the preferred app menu and other stuff: - The preferred apps menu now contain default preferred app lists stored in Config.py, and has been factorized properly i think - Some comment about the code have been added for the indicator - The about menu has been removed and there are other little change --- app/Config.py | 6 +++-- app/DesktopFile.py | 6 +++-- bumblebee-indicator | 66 +++++++++++++++++---------------------------- 3 files changed, 33 insertions(+), 45 deletions(-) diff --git a/app/Config.py b/app/Config.py index 20298f9..9f0ec22 100644 --- a/app/Config.py +++ b/app/Config.py @@ -28,9 +28,7 @@ ### END LICENSE import os -import glob import gtk -import ConfigParser #DESKTOP FILES PATH user_home_directory = os.path.expanduser('~') @@ -86,6 +84,10 @@ def get_config_value(variable_name): unmatch_categorie=['Miscellaneous','applications-other'] uncategorized_categorie=['Uncategorized', 'application-x-executable'] +#DEFAULT APPLICATIONS IN THE PREFERRED APP MENU : +default_preferred_apps =[ ['Glxgears', ['optirun', 'glxgears']] , + ['Glxspheres', ['optirun', 'glxspheres']] ] + #TODO : There might be a way to use string formatting to simplify the config definition #FIXME There must be a better way to store config diff --git a/app/DesktopFile.py b/app/DesktopFile.py index 0bbb550..8e191bb 100755 --- a/app/DesktopFile.py +++ b/app/DesktopFile.py @@ -59,8 +59,10 @@ def get_global (self): self.global_set = self.get_desktop_file_set(Config.global_desktop_file_directory) - self.local_set def get_configured_from_check (self): - self.get_local() - self.configured_set = set([ app for app in list(self.local_set) if DesktopFile(app).is_configured() ]) + for app in list(self.local_set): + desktop_file = DesktopFile(app) + if desktop_file.is_configured(): + yield [ desktop_file.get_app_info()[0], desktop_file.get_exec_list() ] def get_apps_info (self): for file_name in self.local_set: diff --git a/bumblebee-indicator b/bumblebee-indicator index d60a68e..f1a90b4 100755 --- a/bumblebee-indicator +++ b/bumblebee-indicator @@ -50,14 +50,12 @@ class BumblebeeIndicator(): def notify_state(self, title, msg, icon_name): self.notification= pynotify.Notification(title, msg, IconSet().get_uri(icon_name,48)) self.notification.set_urgency(pynotify.URGENCY_CRITICAL) - #self.notification.set_timeout(pynotify.EXPIRES_NEVER) ###### NICE TO SHOW A MESSAGE SIMPLY #FIXME The notification is to slow and this doesn't work #self.notification.set_timeout(1000) self.notification.show() ###INITIALIZATION OF INDICATOR AND MENU def __init__(self): - #TODO Choose the best category for the indicator : appindicator.CATEGORY_APPLICATION_STATUS or appindicator.CATEGORY_SYSTEM_SERVICES self.ind = appindicator.Indicator ("bumblebee-indicator", "bumblebee-indicator", appindicator.CATEGORY_HARDWARE) self.ind.set_status (appindicator.STATUS_ACTIVE) self.ind.set_icon_theme_path(app.Config.icon_file_directory) @@ -84,7 +82,7 @@ class BumblebeeIndicator(): self.switch.set_sensitive(False) self.menu.append(self.switch) - self.build_menu_separator() + self.build_menu_separator(self.menu) self.prefered_app_submenu = gtk.MenuItem("Preferred Apps") self.update_menu() @@ -97,11 +95,7 @@ class BumblebeeIndicator(): #TODO An UI to configure Bumblebee would be nice - #item3 = gtk.MenuItem("Configure Bumblebee") - #item3.show() - #self.menu.append(item3) - - self.build_menu_separator() + self.build_menu_separator(self.menu) quit = gtk.ImageMenuItem(gtk.STOCK_QUIT) quit.connect("activate", self.quit) @@ -109,33 +103,28 @@ class BumblebeeIndicator(): self.menu.show_all() - def build_menu_separator(self): + def build_menu_separator(self, menu): separator = gtk.SeparatorMenuItem() separator.show() - self.menu.append(separator) + menu.append(separator) -#FUNCTION TO GET THE MENU FROM THE CONFIG FILE +# FUNCTIONS TO BUILD THE "PREFERRED APP" MENU FROM THE CONFIG FILE def update_menu(self, widget=None): - self.pref_menu=gtk.Menu() - subitem = gtk.MenuItem("Glxgears") - subitem.connect("activate", self.call_app, ['optirun', 'glxgears']) - subitem.show() - self.pref_menu.append(subitem) - file_set.get_configured_from_check() - for file_name in file_set.configured_set: - [Name, File_name, Categorie, Icon_name] = DesktopFile(file_name).get_app_info() - subitem = gtk.MenuItem(label=Name) - #TODO : Discuss about style : is an icon needed for this simple shortcut - #subitem = gtk.ImageMenuItem() - #subitem.set_image(gtk.image_new_from_pixbuf(IconSet().get_pixbuf(Icon_name,icon_size=gtk.ICON_SIZE_MENU))) - #subitem.set_label(Name) - subitem.connect("activate", self.call_app, DesktopFile(file_name).get_exec_list()) - subitem.show() - self.pref_menu.append(subitem) - self.pref_menu.show() - self.prefered_app_submenu.set_submenu(self.pref_menu) - - + pref_menu=gtk.Menu() + self.add_submenu_items( pref_menu, app.Config.default_preferred_apps ) + self.build_menu_separator( pref_menu ) + self.add_submenu_items( pref_menu, DesktopFileSet().get_configured_from_check() ) + pref_menu.show() + self.prefered_app_submenu.set_submenu(pref_menu) + + def add_submenu_items(self, submenu, items_list): + for Name, Exec_list in items_list : + subitem = gtk.MenuItem(label=Name) + subitem.connect("activate", self.call_app, Exec_list) + subitem.show() + submenu.append( subitem ) + +# FUNCTIONS TO GET THE STATE OF THE INDICATOR def initial_state_checker(self): if self.attention_state_condition(): self.set_attention_state(notify=False) else : self.set_active_state(notify=False) @@ -150,6 +139,7 @@ class BumblebeeIndicator(): if os.path.exists(self.lock_file): return True else: return False +# FUNCTIONS TO SET THE STATE OF THE INDICATOR AND LAUNCH NOTIFICATION def set_attention_state(self, notify=True): self.ind.set_status(appindicator.STATUS_ATTENTION) self.card_state = True @@ -164,21 +154,17 @@ class BumblebeeIndicator(): self.switch.set_label("Discrete card : OFF") self.switch.set_active(False) +# FUNCTION TO DEFINE THE APPLICATIONS SETTING LINK IN THE INDICATOR + def app_configure(self,widget): Applications_settings() +# FUNCTION TO LAUNCH THE APPS WITHIN THE INDICATOR def call_app(self, widget, app_exec): #FIXME There is a problem when closing the launched app and when the indicator has been closed: the indicator is still running : What a daemon!! subprocess.Popen(app_exec,shell=False) - -# def about_box(self, widget, data=None): -# dialog = gtk.MessageDialog(None, type=gtk.MESSAGE_INFO,buttons=gtk.BUTTONS_NONE,message_format="Preferences/About") -# dialog.format_secondary_text("This is Optimus by mrs_sheep. \n It is based on bumblebee by MrMEEE. \n The configuration can (by now) only be set thorugh the config file!") -# dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE) -# dialog.run() -# dialog.destroy() - +# MAIN LOOP LAUNCHING A STATE CHECK EVERY TWO SECONDS def main(self): self.state_checker() #FIXME It would be nice to avoid this loop : Maybe by using a signal emitted by the system @@ -187,8 +173,6 @@ class BumblebeeIndicator(): gtk.main() if __name__ == "__main__": - - file_set=DesktopFileSet() indicator = BumblebeeIndicator() indicator.main() From c8fecc6c390f22579802c1d2d17b0d9ee4afc718 Mon Sep 17 00:00:00 2001 From: Davy RENAUD Date: Thu, 18 Aug 2011 19:36:13 +0200 Subject: [PATCH 09/17] Clean the licence and delete all tabs: that 's why there so many changes --- INSTALL | 60 ++--- README | 46 ++-- app/AppSettings.py | 633 +++++++++++++++++++++----------------------- app/Config.py | 66 ++--- app/DesktopFile.py | 447 +++++++++++++++---------------- app/__init__.py | 32 +-- bumblebee-indicator | 101 ++++--- 7 files changed, 654 insertions(+), 731 deletions(-) diff --git a/INSTALL b/INSTALL index c695000..6cd73cd 100644 --- a/INSTALL +++ b/INSTALL @@ -1,57 +1,45 @@ -#! /bin/bash - ### BEGIN LICENSE # -# ---------------------------------------------------------------------------- -# "THE BEER-WARE LICENSE" (Revision 42): -# wrote this file. As long as you retain this notice you -# can do whatever you want with this stuff. If we meet some day, and you think -# this stuff is worth it, you can buy me a beer in return Davy Renaud (glyptostroboides) -# ---------------------------------------------------------------------------- -# - -# This file is part of bumblebee-ui. +# This file is part of bumblebee-ui. # -# bumblebee-ui 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 3 of the License, or -# (at your option) any later version. +# bumblebee-ui 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 3 of the License, or +# (at your option) any later version. # -# bumblebee-ui 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. +# bumblebee-ui 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 bumblebee-ui. If not, see . +# You should have received a copy of the GNU General Public License +# along with bumblebee-ui. If not, see . # ### END LICENSE -######################################## -#BE CAREFULL THIS IS A RELEASE CANDIDATE -######################################## -#NEED TO BE TESTED +#This script is just an example and should not be used +#Wait for good scripts or do it manually #Copy software files /app, /icons, bumblebee-indicator in /usr/local/bin -cp -R app/ /usr/local/bin/app -cp -R icons/ /usr/local/bin/icons -cp bumblebee-indicator /usr/local/bin +#cp -R app/ /usr/local/bin/app +#cp -R icons/ /usr/local/bin/icons +#cp bumblebee-indicator /usr/local/bin #Create bumblebee-app-settings a link to AppSettings.py -ln -s /usr/local/bin/app/AppSettings.py /usr/local/bin/bumblebee-app-settings +#ln -s /usr/local/bin/app/AppSettings.py /usr/local/bin/bumblebee-app-settings #Copy desktop files in /usr/share/applications -cp bumblebee-app-settings.desktop /usr/share/applications/ -cp bumblebee-indicator.desktop /usr/share/applications/ +#cp bumblebee-app-settings.desktop /usr/share/applications/ +#cp bumblebee-indicator.desktop /usr/share/applications/ #Copy or link icons in /usr/share/icons or /usr/share/pixmaps -cp icons/bumblebee.svg /usr/share/icons/ +#cp icons/bumblebee.svg /usr/share/icons/ #Set the correct right for some files -chmod +x /usr/local/bin/bumblebee-indicator -chmod +x /usr/local/bin/app/* -chmod +x /usr/share/applications/bumblebee-app-settings.desktop -chmod +x /usr/share/applications/bumblebee-indicator.desktop +#chmod +x /usr/local/bin/bumblebee-indicator +#chmod +x /usr/local/bin/app/* +#chmod +x /usr/share/applications/bumblebee-app-settings.desktop +#chmod +x /usr/share/applications/bumblebee-indicator.desktop #TO DO MANUALLY #Add bumblebee-indicator at startup diff --git a/README b/README index ac4437f..20d516f 100644 --- a/README +++ b/README @@ -1,39 +1,27 @@ -#! /bin/bash - ### BEGIN LICENSE # -# ---------------------------------------------------------------------------- -# "THE BEER-WARE LICENSE" (Revision 42): -# wrote this file. As long as you retain this notice you -# can do whatever you want with this stuff. If we meet some day, and you think -# this stuff is worth it, you can buy me a beer in return Davy Renaud (glyptostroboides) -# ---------------------------------------------------------------------------- -# - -# This file is part of bumblebee-ui. +# This file is part of bumblebee-ui. # -# bumblebee-ui 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 3 of the License, or -# (at your option) any later version. +# bumblebee-ui 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 3 of the License, or +# (at your option) any later version. # -# bumblebee-ui 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. +# bumblebee-ui 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 bumblebee-ui. If not, see . +# You should have received a copy of the GNU General Public License +# along with bumblebee-ui. If not, see . # ### END LICENSE -######################################## -#BE CAREFULL THIS IS A RELEASE CANDIDATE -######################################## -#NEED TO BE TESTED +This is a user interface for bumblebee. +A complete explanation of the feature of this user interface are explained here : + https://github.com/Bumblebee-Project/bumblebee-ui/wiki +Please give it a try and report bugs to : + https://github.com/Bumblebee-Project/bumblebee-ui/issues +Thanks for your help. -This user interface is a release candidate and one functionnality is still laking : be able to configure bumblebee. -This app allow you to configure applications desktop file to use ecoptirun script with different options. -This app contain also an experimental indicator that is far from optimal but works for the moment. -Enjoy and please improve the code if you have time. diff --git a/app/AppSettings.py b/app/AppSettings.py index e5a99c7..9f4db85 100755 --- a/app/AppSettings.py +++ b/app/AppSettings.py @@ -1,29 +1,21 @@ #!/usr/bin/python -# -*- coding: utf-8 -*- +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- ### BEGIN LICENSE # -# ---------------------------------------------------------------------------- -# "THE BEER-WARE LICENSE" (Revision 42): -# wrote this file. As long as you retain this notice you -# can do whatever you want with this stuff. If we meet some day, and you think -# this stuff is worth it, you can buy me a beer in return Davy Renaud (glyptostroboides) -# ---------------------------------------------------------------------------- +# This file is part of bumblebee-ui. # - -# This file is part of bumblebee-ui. -# -# bumblebee-ui 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 3 of the License, or -# (at your option) any later version. +# bumblebee-ui 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 3 of the License, or +# (at your option) any later version. # -# bumblebee-ui 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. +# bumblebee-ui 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 bumblebee-ui. If not, see . +# You should have received a copy of the GNU General Public License +# along with bumblebee-ui. If not, see . # ### END LICENSE @@ -39,337 +31,330 @@ #ICON CONFIGURATION class IconSet: - """This small class contain the settings computed for categories""" - def __init__(self): - self.icon_theme= gtk.icon_theme_get_default() - self.icon_theme.append_search_path(Config.icon_file_directory) + """This small class contain the settings computed for categories""" + def __init__(self): + self.icon_theme= gtk.icon_theme_get_default() + self.icon_theme.append_search_path(Config.icon_file_directory) - def get_uri (self, icon_name, icon_size): - return "file://" + self.get_path(icon_name, icon_size) + def get_uri (self, icon_name, icon_size): + return "file://" + self.get_path(icon_name, icon_size) - def get_pixbuf (self, icon_name, icon_size=Config.icon_size): - try : - return self.icon_theme.load_icon(icon_name, icon_size, 0) - except : - try : return gtk.gdk.pixbuf_new_from_file_at_size(icon_name, icon_size, icon_size) - except : return self.icon_theme.load_icon(Config.default_icon_name, icon_size, 0) + def get_pixbuf (self, icon_name, icon_size=Config.icon_size): + try : + return self.icon_theme.load_icon(icon_name, icon_size, 0) + except : + try : return gtk.gdk.pixbuf_new_from_file_at_size(icon_name, icon_size, icon_size) + except : return self.icon_theme.load_icon(Config.default_icon_name, icon_size, 0) - def get_path (self, icon_name, icon_size=Config.icon_size): - try : return self.icon_theme.lookup_icon(icon_name, icon_size, 0).get_filename() - except : self.get_path(Config.default_icon_name) + def get_path (self, icon_name, icon_size=Config.icon_size): + try : return self.icon_theme.lookup_icon(icon_name, icon_size, 0).get_filename() + except : self.get_path(Config.default_icon_name) - -###TODO Factorize the init which is too long +#TODO Factorize the init which is too long class Applications_settings(): - #TODO This initialization should be avoid or rethinked - to_modify_file=[] - to_configure_file={} - to_unconfigure_file={} - categories_iter_with_child={} - configured_file_exist=False +#TODO This initialization should be avoid or rethinked + to_modify_file=[] + to_configure_file={} + to_unconfigure_file={} + categories_iter_with_child={} + configured_file_exist=False - def delete_event(self,widget,event,data=None): - return False - - def destroy(self,widget): - if __name__=="__main__": gtk.main_quit() - else : self.window.destroy() - - def __init__(self): - #FIXME Seems not to be clean or shorter enough - self.file_set=DesktopFileSet() - self.icon_set=IconSet() - ### MAIN WINDOW - self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) - self.window.connect("delete_event", self.delete_event) - self.window.connect("destroy", self.destroy) - self.window.set_title("Bumblebee - Applications Settings") - self.window.set_border_width(0) - self.window.set_size_request(600,600) - ### MAIN WINDOW ICON : monitor and launcher - self.window.set_icon(self.icon_set.get_pixbuf('bumblebee', 48)) - - ### NOTEBOOK - self.notebook= gtk.Notebook() - self.notebook.set_tab_pos(gtk.POS_TOP) - self.notebook.set_border_width(10) - self.window.add(self.notebook) - - ### SELECT APPLICATION - ### LIST - self.build_app_list() + def delete_event(self,widget,event,data=None): + return False - ### VIEW - self.select_app_view = gtk.TreeView(self.app_list) - self.treeselection = self.select_app_view.get_selection() - self.treeselection.set_mode(gtk.SELECTION_NONE) - self.select_app_view.set_rules_hint(True) - self.select_app_view.show() - self.build_select_view() - - ### EXPAND CATEGORIES WITH CHILD - try : - for categorie in self.categories_iter_with_child: - categorie_iter,count= self.categories_iter_with_child[categorie] - self.select_app_view.expand_to_path(self.app_list.get_path(categorie_iter)) - except : self.select_app_view.expand_all() - - ### PAGE - self.select_page = self.build_notebook_page( - tab_title = "Select applications", - instruction_text = "Choose the application you want to configure to use with the discrete graphic card.", - view = self.select_app_view , - button_list = [self.action_button(stock=gtk.STOCK_APPLY, action=self.apply_app_set),self.action_button(label="Apply Now",action=self.apply_app_set)] ) - #TODO Create an apply now button which relaunch unity with unity --replace or use dynamic desktop configuration (See Ubuntu desktop specification) - - #CONFIGURE APPLICATION - ### LIST - self.configured_apps = self.app_list.filter_new(root=None) - self.configured_apps.set_visible_column(5) - - ### VIEW - self.config_app_view = gtk.TreeView(self.configured_apps) - self.config_app_view.set_rules_hint(True) - self.build_config_view() - self.config_app_view.show() - - ### PAGE - self.configure_page = self.build_notebook_page( - tab_title="Configure applications", - instruction_text="Choose the configuration for each application.\n Depending on mode the discrete card will be launched: always (Performance),\n only when plugged (Power Save) or with launcher shortcuts (Option)" , - view=self.config_app_view ) + def destroy(self,widget): + if __name__=="__main__": gtk.main_quit() + else : self.window.destroy() - #FIXME : Set the focus on configure page doesn't work - if self.configured_file_exist==True: self.notebook.set_current_page(self.configure_page) - else: self.select_app_view.expand_all() - - #SHOW ALL - self.window.show_all() - - def build_notebook_page(self , tab_title, instruction_text , view , button_list=[]): - ### INSTRUCTION FRAME - instruction_frame = self.return_instruction_frame(instruction_text) - ### SCROLL FRAME - scrolled_window=gtk.ScrolledWindow() - scrolled_window.add(view) - ### ACTION AREA - hbox=gtk.HBox(homogeneous=False, spacing=10) - ### SPECIFIC BUTTON - for button in button_list : hbox.pack_start(button, False, False, 10) - ### CLOSE BUTTON - hbox.pack_end(self.action_button(stock=gtk.STOCK_CLOSE, action=self.destroy), False, False, 10) - ### CONTAINER - vbox= gtk.VBox(homogeneous=False) - vbox.pack_start(instruction_frame, False, False, 0) - vbox.pack_start(scrolled_window, True, True, 10) - vbox.pack_end(hbox, False, False, 10) - ### NOTEBOOK PAGE - notebook_label= gtk.Label(tab_title) - return self.notebook.append_page(vbox, notebook_label) + def __init__(self): + #FIXME Seems not to be clean or shorter enough + self.file_set=DesktopFileSet() + self.icon_set=IconSet() + # MAIN WINDOW + self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) + self.window.connect("delete_event", self.delete_event) + self.window.connect("destroy", self.destroy) + self.window.set_title("Bumblebee - Applications Settings") + self.window.set_border_width(0) + self.window.set_size_request(600,600) + # MAIN WINDOW ICON : monitor and launcher + self.window.set_icon(self.icon_set.get_pixbuf('bumblebee', 48)) + + # NOTEBOOK + self.notebook= gtk.Notebook() + self.notebook.set_tab_pos(gtk.POS_TOP) + self.notebook.set_border_width(10) + self.window.add(self.notebook) + + # SELECT APPLICATION + # LIST + self.build_app_list() + + # VIEW + self.select_app_view = gtk.TreeView(self.app_list) + self.treeselection = self.select_app_view.get_selection() + self.treeselection.set_mode(gtk.SELECTION_NONE) + self.select_app_view.set_rules_hint(True) + self.select_app_view.show() + self.build_select_view() + + # EXPAND CATEGORIES WITH CHILD + try : + for categorie in self.categories_iter_with_child: + categorie_iter,count= self.categories_iter_with_child[categorie] + self.select_app_view.expand_to_path(self.app_list.get_path(categorie_iter)) + except : self.select_app_view.expand_all() + + # PAGE + self.select_page = self.build_notebook_page( + tab_title = "Select applications", + instruction_text = "Choose the application you want to configure to use with the discrete graphic card.", + view = self.select_app_view , + button_list = [self.action_button(stock=gtk.STOCK_APPLY, action=self.apply_app_set),self.action_button(label="Apply Now",action=self.apply_app_set)] ) +#TODO Create an apply now button which relaunch unity with unity --replace or use dynamic desktop configuration (See Ubuntu desktop specification) + # CONFIGURE APPLICATION + # LIST + self.configured_apps = self.app_list.filter_new(root=None) + self.configured_apps.set_visible_column(5) + + # VIEW + self.config_app_view = gtk.TreeView(self.configured_apps) + self.config_app_view.set_rules_hint(True) + self.build_config_view() + self.config_app_view.show() + + # PAGE + self.configure_page = self.build_notebook_page( + tab_title="Configure applications", + instruction_text="Choose the configuration for each application.\n Depending on mode the discrete card will be launched: always (Performance),\n only when plugged (Power Save) or with launcher shortcuts (Option)" , + view=self.config_app_view ) + +#FIXME : Set the focus on configure page doesn't work + if self.configured_file_exist==True: self.notebook.set_current_page(self.configure_page) + else: self.select_app_view.expand_all() + + #SHOW ALL + self.window.show_all() + + def build_notebook_page(self , tab_title, instruction_text , view , button_list=[]): + # INSTRUCTION FRAME + instruction_frame = self.return_instruction_frame(instruction_text) + # SCROLL FRAME + scrolled_window=gtk.ScrolledWindow() + scrolled_window.add(view) + # ACTION AREA + hbox=gtk.HBox(homogeneous=False, spacing=10) + # SPECIFIC BUTTON + for button in button_list : hbox.pack_start(button, False, False, 10) + # CLOSE BUTTON + hbox.pack_end(self.action_button(stock=gtk.STOCK_CLOSE, action=self.destroy), False, False, 10) + # CONTAINER + vbox= gtk.VBox(homogeneous=False) + vbox.pack_start(instruction_frame, False, False, 0) + vbox.pack_start(scrolled_window, True, True, 10) + vbox.pack_end(hbox, False, False, 10) + # NOTEBOOK PAGE + notebook_label= gtk.Label(tab_title) + return self.notebook.append_page(vbox, notebook_label) + + def return_instruction_frame(self,text): + """Return an instruction frame with the text given""" + instruction_frame = gtk.Frame() + instruction = gtk.Label(text) + #instruction.set_justify(gtk.JUSTIFY_LEFT) + instruction_frame.set_border_width(10) +#FIXME : There is a problem with the instruction frame text rendering : use size_allocate to dynamicaly set the size of label + #instruction.set_line_wrap(True) + instruction_frame.add(instruction) + return instruction_frame + + def action_button(self, action, label=None, stock=None): + button= gtk.Button(label,stock) + button.set_size_request(width=100,height=-1) + button.connect("clicked",action) + return button - def return_instruction_frame(self,text): - """Return an instruction frame with the text given""" - instruction_frame = gtk.Frame() - instruction = gtk.Label(text) - #instruction.set_justify(gtk.JUSTIFY_LEFT) - instruction_frame.set_border_width(10) - #FIXME : There is a problem with the instruction frame text rendering : use size_allocate to dynamicaly set the size of label - #instruction.set_line_wrap(True) - instruction_frame.add(instruction) - return instruction_frame + def build_app_list(self): + """Function to build the store with this columns : + *Application Name or Categorie Name, *File Name, *Application Categorie, *Application Icon Path, Is Not Category, Configured, (Selected by default), Mode, 32bits, Compression, Background display, Background color + for categories : Categorie Name, None, None, Icon Path, False , Has child configured, False, None, + """ + self.app_list = gtk.TreeStore(str,str,str,gtk.gdk.Pixbuf,bool,bool,bool,str,bool,str,bool,str) + self.categorie_iter={} + # CATEFORIE ROWS + for [categorie, icon_name] in Config.categorie_list + [Config.unmatch_categorie, Config.uncategorized_categorie]: + iter=self.app_list.append(None, [categorie,None,None] + [self.icon_set.get_pixbuf(icon_name)] + 3*[False] + 3*[None] + [False, Config.to_configure_color]) + self.categorie_iter.update({categorie:iter}) + # APPLICATIONS ROWS + for app_info in self.file_set.get_apps_info(): + parent_iter=self.categorie_iter.get(app_info[2]) + app_info[3]=self.icon_set.get_pixbuf(app_info[3]) + if app_info[5] == True: + self.configured_file_exist=True + self.app_list.append(parent_iter, app_info + [True, Config.configured_color]) + self.app_list[parent_iter][5]=True #Used to only show the categories with configured child + self.add_child_for_categorie(app_info[2]) + else : self.app_list.append(parent_iter, app_info + [False, Config.to_configure_color]) - def action_button(self, action, label=None, stock=None): - button= gtk.Button(label,stock) - button.set_size_request(width=100,height=-1) - button.connect("clicked",action) - return button - - def build_app_list(self): - """Function to build the store with this columns : - *Application Name or Categorie Name, *File Name, *Application Categorie, *Application Icon Path, Is Not Category, Configured, (Selected by default), Mode, 32bits, Compression, Background display, Background color - for categories : Categorie Name, None, None, Icon Path, False , Has child configured, False, None, - """ - self.app_list = gtk.TreeStore(str,str,str,gtk.gdk.Pixbuf,bool,bool,bool,str,bool,str,bool,str) - self.categorie_iter={} - #CATEFORIE ROWS - for [categorie, icon_name] in Config.categorie_list + [Config.unmatch_categorie, Config.uncategorized_categorie]: - iter=self.app_list.append(None, [categorie,None,None] + [self.icon_set.get_pixbuf(icon_name)] + 3*[False] + 3*[None] + [False, Config.to_configure_color]) - self.categorie_iter.update({categorie:iter}) - #APPLICATIONS ROWS - for app_info in self.file_set.get_apps_info(): - parent_iter=self.categorie_iter.get(app_info[2]) - app_info[3]=self.icon_set.get_pixbuf(app_info[3]) - if app_info[5] == True: - self.configured_file_exist=True - self.app_list.append(parent_iter, app_info + [True, Config.configured_color]) - self.app_list[parent_iter][5]=True #Used to only show the categories with configured child - self.add_child_for_categorie(app_info[2]) - else : self.app_list.append(parent_iter, app_info + [False, Config.to_configure_color]) + def build_select_view(self): + # APPLICATION OR CATEGORIE NAME COLUMN + self.column = gtk.TreeViewColumn('Applications') - def build_select_view(self): - #APPLICATION OR CATEGORIE NAME COLUMN - self.column = gtk.TreeViewColumn('Applications') - - #SELECT CHECKBOX - rendererToggle = gtk.CellRendererToggle() - self.column.pack_start(rendererToggle, True) - self.column.set_attributes(rendererToggle, active=6, visible=4) - rendererToggle.set_property('activatable', True) - rendererToggle.connect('toggled', self.on_select_app) + # SELECT CHECKBOX + rendererToggle = gtk.CellRendererToggle() + self.column.pack_start(rendererToggle, True) + self.column.set_attributes(rendererToggle, active=6, visible=4) + rendererToggle.set_property('activatable', True) + rendererToggle.connect('toggled', self.on_select_app) - #APPLICATION ICON - rendererIcon=gtk.CellRendererPixbuf() - self.column.pack_start(rendererIcon, True) - self.column.set_attributes(rendererIcon, pixbuf=3) + # APPLICATION ICON + rendererIcon=gtk.CellRendererPixbuf() + self.column.pack_start(rendererIcon, True) + self.column.set_attributes(rendererIcon, pixbuf=3) - #APPLICATION NAME - rendererText=gtk.CellRendererText() - self.column.pack_start(rendererText, True) - self.column.set_attributes(rendererText, text=0) + # APPLICATION NAME + rendererText=gtk.CellRendererText() + self.column.pack_start(rendererText, True) + self.column.set_attributes(rendererText, text=0) - #BACKGROUND COLOR SET - for renderer in [rendererToggle, rendererIcon, rendererText]: - self.column.add_attribute(renderer, "cell-background-set", 10) - self.column.add_attribute(renderer, "cell-background", 11) - - #self.column.set_min_width(300) : cause problem with the pack start - ###FIXME : the style must be refined in order to have a better display for the user : size if the icon, name of the application and categorie display - ###FIXME : there must be a better way also to change the row color depending on state (this color can be changed by a color id that can be used to know the state of the application ??? in order to have a smoother treestore - self.column.set_max_width(350) + # BACKGROUND COLOR SET + for renderer in [rendererToggle, rendererIcon, rendererText]: + self.column.add_attribute(renderer, "cell-background-set", 10) + self.column.add_attribute(renderer, "cell-background", 11) + #self.column.set_min_width(300) : cause problem with the pack start +#FIXME : the style must be refined in order to have a better display for the user : size if the icon, name of the application and categorie display +#FIXME : there must be a better way also to change the row color depending on state (this color can be changed by a color id that can be used to know the state of the application ??? in order to have a smoother treestore + self.column.set_max_width(350) - #FILE NAME COLUMN - self.select_app_view.append_column(self.column) - rendererText2=gtk.CellRendererText() - column1 = gtk.TreeViewColumn('File Name',rendererText2, text=1) - column1.add_attribute(rendererText2, "cell-background-set",10) - column1.add_attribute(rendererText2, "cell-background",11) - self.select_app_view.append_column(column1) - self.select_app_view.set_level_indentation(10) - - def on_select_app(self, cell, row): - ###TODO : Find a better way to manage row color change - self.app_list[row][6] = not self.app_list[row][6] - Configured, Selected= self.app_list[row][5], self.app_list[row][6] - if Configured==True and Selected==False : #The app will be Unconfigured - self.app_list[row][10],self.app_list[row][11]=True,Config.to_unconfigure_color - self.to_unconfigure_file.update({self.app_list[row][1]:self.app_list.get_iter(row)}) - elif Configured==True and Selected==True : #The configured app is reselected: Nothing to apply - self.app_list[row][10],self.app_list[row][11]=True,Config.configured_color - del self.to_unconfigure_file[self.app_list[row][1]] - elif Configured==False and Selected==True : #The app will be Configured - self.app_list[row][10],self.app_list[row][11]=True,Config.to_configure_color - self.to_configure_file.update({self.app_list[row][1]:self.app_list.get_iter(row)}) - elif Configured==False and Selected==False : #The app is not configured and unselected: Nothing to apply - self.app_list[row][10]=False - del self.to_configure_file[self.app_list[row][1]] + #FILE NAME COLUMN + self.select_app_view.append_column(self.column) + rendererText2=gtk.CellRendererText() + column1 = gtk.TreeViewColumn('File Name',rendererText2, text=1) + column1.add_attribute(rendererText2, "cell-background-set",10) + column1.add_attribute(rendererText2, "cell-background",11) + self.select_app_view.append_column(column1) + self.select_app_view.set_level_indentation(10) + + def on_select_app(self, cell, row): +#TODO : Find a better way to manage row color change + self.app_list[row][6] = not self.app_list[row][6] + Configured, Selected= self.app_list[row][5], self.app_list[row][6] + if Configured==True and Selected==False : #The app will be Unconfigured + self.app_list[row][10],self.app_list[row][11]=True,Config.to_unconfigure_color + self.to_unconfigure_file.update({self.app_list[row][1]:self.app_list.get_iter(row)}) + elif Configured==True and Selected==True : #The configured app is reselected: Nothing to apply + self.app_list[row][10],self.app_list[row][11]=True,Config.configured_color + del self.to_unconfigure_file[self.app_list[row][1]] + elif Configured==False and Selected==True : #The app will be Configured + self.app_list[row][10],self.app_list[row][11]=True,Config.to_configure_color + self.to_configure_file.update({self.app_list[row][1]:self.app_list.get_iter(row)}) + elif Configured==False and Selected==False : #The app is not configured and unselected: Nothing to apply + self.app_list[row][10]=False + del self.to_configure_file[self.app_list[row][1]] - def build_config_view(self): - """Function to create a setting list for applications configured for Bumblebee""" - #APPLICATION NAME COLUMNS - self.column=gtk.TreeViewColumn('Applications') + def build_config_view(self): + """Function to create a setting list for applications configured for Bumblebee""" + # APPLICATION NAME COLUMNS + self.column=gtk.TreeViewColumn('Applications') + + rendererIcon=gtk.CellRendererPixbuf() + self.column.pack_start(rendererIcon, False) + self.column.set_attributes(rendererIcon, pixbuf=3) + rendererText=gtk.CellRendererText() + self.column.pack_start(rendererText, False) + self.column.set_attributes(rendererText, text=0) + + self.config_app_view.append_column(self.column) + + # MODE, DRIVER AND COMPRESSION COLUMN + self.build_combo_column("Mode", 7, Config.mode_keys.values()) + + self.build_config_column ("32bits Driver", 8) + + self.build_combo_column("Compression", 9, ["default"] + Config.compression_list) + + self.config_app_view.set_level_indentation(20) + self.config_app_view.expand_all() + self.config_app_view.set_show_expanders(False) - rendererIcon=gtk.CellRendererPixbuf() - self.column.pack_start(rendererIcon, False) - self.column.set_attributes(rendererIcon, pixbuf=3) - rendererText=gtk.CellRendererText() - self.column.pack_start(rendererText, False) - self.column.set_attributes(rendererText, text=0) + def build_combo_column(self, column_name, column_id, value_list): + """Function to build the columns with selection from a list""" + # COMBOBOX CELL + combo_list = gtk.ListStore(str) + for value in value_list: combo_list.append([value]) + rendererCombo = gtk.CellRendererCombo() + rendererCombo.set_properties(model=combo_list, editable=True) + rendererCombo.set_property("has-entry", False) + rendererCombo.set_property("text-column", 0) + rendererCombo.connect("edited", self.on_combo_edit, column_id) + # COMBOBOX COLUMN + column = gtk.TreeViewColumn(column_name) + column.pack_start(rendererCombo, False) + column.add_attribute(rendererCombo, "text", column_id) + column.add_attribute(rendererCombo, "visible", 4) + self.config_app_view.append_column(column) - self.config_app_view.append_column(self.column) - - # MODE, DRIVER AND COMPRESSION COLUMN - self.build_combo_column("Mode", 7, Config.mode_keys.values()) - - self.build_config_column ("32bits Driver", 8) - - self.build_combo_column("Compression", 9, ["default"] + Config.compression_list) - - self.config_app_view.set_level_indentation(20) - self.config_app_view.expand_all() - self.config_app_view.set_show_expanders(False) + def on_combo_edit(self, cell , path , new_text, column_id): + filter_iter = self.configured_apps.get_iter(path) + iter = self.configured_apps.convert_iter_to_child_iter(filter_iter) + self.app_list[iter][column_id] = new_text + DesktopFile(self.app_list[iter][1]).set_exec_config(self.app_list[iter][7],self.app_list[iter][8],self.app_list[iter][9]) - def build_combo_column(self, column_name, column_id, value_list): - """Function to build the columns with selection from a list""" - # COMBOBOX CELL - combo_list = gtk.ListStore(str) - for value in value_list: combo_list.append([value]) - rendererCombo = gtk.CellRendererCombo() - rendererCombo.set_properties(model=combo_list, editable=True) - rendererCombo.set_property("has-entry", False) - rendererCombo.set_property("text-column", 0) - rendererCombo.connect("edited", self.on_combo_edit, column_id) - # COMBOBOX COLUMN - column = gtk.TreeViewColumn(column_name) - column.pack_start(rendererCombo, False) - column.add_attribute(rendererCombo, "text", column_id) - column.add_attribute(rendererCombo, "visible", 4) - self.config_app_view.append_column(column) - - def on_combo_edit(self, cell , path , new_text, column_id): - filter_iter = self.configured_apps.get_iter(path) - iter = self.configured_apps.convert_iter_to_child_iter(filter_iter) - self.app_list[iter][column_id] = new_text - DesktopFile(self.app_list[iter][1]).set_exec_config(self.app_list[iter][7],self.app_list[iter][8],self.app_list[iter][9]) - - def build_config_column(self, column_name, column_id): - rendererToggle = gtk.CellRendererToggle() - rendererToggle.set_property('activatable', True) - rendererToggle.connect('toggled', self.on_config_check ,(self.configured_apps, column_id)) - - column = gtk.TreeViewColumn(column_name, rendererToggle, active=column_id, visible=4) - self.config_app_view.append_column(column) - - def on_config_check(self, cell, row, user_data): - model, column = user_data - iter = model.convert_iter_to_child_iter(model.get_iter(row)) - self.app_list[iter][column] = not self.app_list[iter][column] - DesktopFile(self.app_list[iter][1]).set_exec_config(self.app_list[iter][7],self.app_list[iter][8],self.app_list[iter][9]) + def build_config_column(self, column_name, column_id): + rendererToggle = gtk.CellRendererToggle() + rendererToggle.set_property('activatable', True) + rendererToggle.connect('toggled', self.on_config_check ,(self.configured_apps, column_id)) + + column = gtk.TreeViewColumn(column_name, rendererToggle, active=column_id, visible=4) + self.config_app_view.append_column(column) + def on_config_check(self, cell, row, user_data): + model, column = user_data + iter = model.convert_iter_to_child_iter(model.get_iter(row)) + self.app_list[iter][column] = not self.app_list[iter][column] + DesktopFile(self.app_list[iter][1]).set_exec_config(self.app_list[iter][7],self.app_list[iter][8],self.app_list[iter][9]) - def apply_app_set (self,widget,data=None): - for file_name, iter in self.to_configure_file.iteritems(): #The app is to configure - self.apply_app_change ( iter, file_name, [self.file_set.configure_file, self.add_child_for_categorie], - True, Config.mode_keys['option'], True, Config.configured_color) - self.to_configure_file.clear() - - for file_name, iter in self.to_unconfigure_file.iteritems(): #The app is to unconfigure - self.apply_app_change ( iter, file_name, [self.file_set.unconfigure_file, self.remove_child_for_categorie], - False, False, False, Config.to_configure_color) - self.to_unconfigure_file.clear() - self.config_app_view.expand_all() + def apply_app_set (self,widget,data=None): + for file_name, iter in self.to_configure_file.iteritems(): #The app is to configure + self.apply_app_change ( iter, file_name, [self.file_set.configure_file, self.add_child_for_categorie], + True, Config.mode_keys['option'], True, Config.configured_color) + self.to_configure_file.clear() + for file_name, iter in self.to_unconfigure_file.iteritems(): #The app is to unconfigure + self.apply_app_change ( iter, file_name, [self.file_set.unconfigure_file, self.remove_child_for_categorie], + False, False, False, Config.to_configure_color) + self.to_unconfigure_file.clear() + self.config_app_view.expand_all() - def apply_app_change (self, iter, file_name, actions, configured, mode, display_bg, bg_color): - actions[0](file_name) - self.app_list.set(iter, 5, configured, 7, mode, 10, display_bg, 11, bg_color) - actions[1](self.app_list.get_value(iter,2)) + def apply_app_change (self, iter, file_name, actions, configured, mode, display_bg, bg_color): + actions[0](file_name) + self.app_list.set(iter, 5, configured, 7, mode, 10, display_bg, 11, bg_color) + actions[1](self.app_list.get_value(iter,2)) - #TODO There must be thing done to deal with categories having configured child : simplify this function - def add_child_for_categorie(self,categorie_name): - if self.categories_iter_with_child.has_key(categorie_name): - parent_iter, count=self.categories_iter_with_child[categorie_name] - child_count= count+1 - else: - child_count=1 - self.categories_iter_with_child.update({categorie_name:[self.categorie_iter[categorie_name], child_count]}) - self.app_list.set(self.categorie_iter[categorie_name], 5, True) +#TODO There must be thing done to deal with categories having configured child : simplify this function + def add_child_for_categorie(self,categorie_name): + if self.categories_iter_with_child.has_key(categorie_name): + parent_iter, count=self.categories_iter_with_child[categorie_name] + child_count= count+1 + else: child_count=1 + self.categories_iter_with_child.update({categorie_name:[self.categorie_iter[categorie_name], child_count]}) + self.app_list.set(self.categorie_iter[categorie_name], 5, True) - def remove_child_for_categorie(self,categorie_name): - if self.categories_iter_with_child.has_key(categorie_name): - parent_iter, count=self.categories_iter_with_child[categorie_name] - child_count= count-1 - self.categories_iter_with_child.update({categorie_name:[parent_iter, child_count]}) - if child_count==0 : - del self.categories_iter_with_child[categorie_name] - self.app_list.set(self.categorie_iter[categorie_name], 5, False) + def remove_child_for_categorie(self,categorie_name): + if self.categories_iter_with_child.has_key(categorie_name): + parent_iter, count=self.categories_iter_with_child[categorie_name] + child_count= count-1 + self.categories_iter_with_child.update({categorie_name:[parent_iter, child_count]}) + if child_count==0 : + del self.categories_iter_with_child[categorie_name] + self.app_list.set(self.categorie_iter[categorie_name], 5, False) - def main(self): - gtk.main() - return 0 + def main(self): + gtk.main() + return 0 if __name__=="__main__": - Appset = Applications_settings() - Appset.main() - + Appset = Applications_settings() + Appset.main() diff --git a/app/Config.py b/app/Config.py index 9f0ec22..2ab446d 100644 --- a/app/Config.py +++ b/app/Config.py @@ -1,29 +1,21 @@ #!/usr/bin/python -# -*- coding: utf-8 -*- +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- ### BEGIN LICENSE # -# ---------------------------------------------------------------------------- -# "THE BEER-WARE LICENSE" (Revision 42): -# wrote this file. As long as you retain this notice you -# can do whatever you want with this stuff. If we meet some day, and you think -# this stuff is worth it, you can buy me a beer in return Davy Renaud (glyptostroboides) -# ---------------------------------------------------------------------------- +# This file is part of bumblebee-ui. # - -# This file is part of bumblebee-ui. -# -# bumblebee-ui 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 3 of the License, or -# (at your option) any later version. +# bumblebee-ui 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 3 of the License, or +# (at your option) any later version. # -# bumblebee-ui 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. +# bumblebee-ui 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 bumblebee-ui. If not, see . +# You should have received a copy of the GNU General Public License +# along with bumblebee-ui. If not, see . # ### END LICENSE @@ -45,8 +37,8 @@ #MODE LIST #TODO Need to be set to a list maybe mode_keys={'perf':"Performance", - 'eco':"Power Save", - 'option':"Optional"} + 'eco':"Power Save", + 'option':"Optional"} #ICON FILES THEME icon_size=24 @@ -61,11 +53,11 @@ config_file_path='/etc/bumblebee/bumblebee.conf' #GET BUMBLEBEE CONFIGURATION VALUE def get_config_value(variable_name): - """Function to get configuration value inside a shell script""" - for line in open(config_file_path): - if variable_name in line: - variable, value= line.split('=',1) - return value.replace("\n","") + """Function to get configuration value inside a shell script""" + for line in open(config_file_path): + if variable_name in line: + variable, value= line.split('=',1) + return value.replace("\n","") default_compression= get_config_value('VGL_COMPRESS') vgl_display= get_config_value('VGL_DISPLAY').replace(":","") @@ -74,24 +66,24 @@ def get_config_value(variable_name): ####TODO There might be a way to get those key from a menu configuration file categorie_list=[['Game', 'applications-games'], - ['AudioVideo', 'applications-multimedia'], - ['Graphics', 'applications-graphics'], - ['Network', 'applications-internet'], - ['Office', 'applications-office'], - ['Settings', 'applications-system'], - ['System', 'applications-electronics'], - ['Utility', 'applications-utilities']] + ['AudioVideo', 'applications-multimedia'], + ['Graphics', 'applications-graphics'], + ['Network', 'applications-internet'], + ['Office', 'applications-office'], + ['Settings', 'applications-system'], + ['System', 'applications-electronics'], + ['Utility', 'applications-utilities']] unmatch_categorie=['Miscellaneous','applications-other'] uncategorized_categorie=['Uncategorized', 'application-x-executable'] #DEFAULT APPLICATIONS IN THE PREFERRED APP MENU : default_preferred_apps =[ ['Glxgears', ['optirun', 'glxgears']] , - ['Glxspheres', ['optirun', 'glxspheres']] ] + ['Glxspheres', ['optirun', 'glxspheres']] ] #TODO : There might be a way to use string formatting to simplify the config definition #FIXME There must be a better way to store config if __name__=="__main__" : - print "Config.py can't run as a standalone application" - quit() + print "Config.py can't run as a standalone application" + quit() diff --git a/app/DesktopFile.py b/app/DesktopFile.py index 8e191bb..c444f3f 100755 --- a/app/DesktopFile.py +++ b/app/DesktopFile.py @@ -1,29 +1,21 @@ #!/usr/bin/python -# -*- coding: utf-8 -*- +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- ### BEGIN LICENSE # -# ---------------------------------------------------------------------------- -# "THE BEER-WARE LICENSE" (Revision 42): -# wrote this file. As long as you retain this notice you -# can do whatever you want with this stuff. If we meet some day, and you think -# this stuff is worth it, you can buy me a beer in return Davy Renaud (glyptostroboides) -# ---------------------------------------------------------------------------- +# This file is part of bumblebee-ui. # - -# This file is part of bumblebee-ui. -# -# bumblebee-ui 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 3 of the License, or -# (at your option) any later version. +# bumblebee-ui 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 3 of the License, or +# (at your option) any later version. # -# bumblebee-ui 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. +# bumblebee-ui 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 bumblebee-ui. If not, see . +# You should have received a copy of the GNU General Public License +# along with bumblebee-ui. If not, see . # ### END LICENSE @@ -44,249 +36,244 @@ #FIXME Clean this class and find shorter and cleaner way class DesktopFileSet: - """This class contain list of files in local directory or in global directory and a list of configured files""" - def __init__(self): - self.get_local() - self.get_global() + """This class contain list of files in local directory or in global directory and a list of configured files""" + def __init__(self): + self.get_local() + self.get_global() - def get_desktop_file_set(self, directory): - return set([re.sub(r'(.*)\.desktop',r'\1',x) for x in glob.glob1( directory, '*.desktop' )]) - - def get_local (self): - self.local_set = self.get_desktop_file_set(Config.user_desktop_file_directory) + def get_desktop_file_set(self, directory): + return set([re.sub(r'(.*)\.desktop',r'\1',x) for x in glob.glob1( directory, '*.desktop' )]) + + def get_local (self): + self.local_set = self.get_desktop_file_set(Config.user_desktop_file_directory) - def get_global (self): - self.global_set = self.get_desktop_file_set(Config.global_desktop_file_directory) - self.local_set + def get_global (self): + self.global_set = self.get_desktop_file_set(Config.global_desktop_file_directory) - self.local_set - def get_configured_from_check (self): - for app in list(self.local_set): - desktop_file = DesktopFile(app) - if desktop_file.is_configured(): - yield [ desktop_file.get_app_info()[0], desktop_file.get_exec_list() ] + def get_configured_from_check (self): + for app in list(self.local_set): + desktop_file = DesktopFile(app) + if desktop_file.is_configured(): + yield [ desktop_file.get_app_info()[0], desktop_file.get_exec_list() ] - def get_apps_info (self): - for file_name in self.local_set: - desktop_file = DesktopFile(file_name, local=True) - app_info_list = desktop_file.get_app_info() - app_config = desktop_file.get_app_config() - yield app_info_list + [True] + app_config - for file_name in self.global_set: - app_info_list = DesktopFile(file_name, local=False).get_app_info() - yield app_info_list + [True] + 4*[False] + ['default'] - + def get_apps_info (self): + for file_name in self.local_set: + desktop_file = DesktopFile(file_name, local=True) + app_info_list = desktop_file.get_app_info() + app_config = desktop_file.get_app_config() + yield app_info_list + [True] + app_config + for file_name in self.global_set: + app_info_list = DesktopFile(file_name, local=False).get_app_info() + yield app_info_list + [True] + 4*[False] + ['default'] - def configure_file (self, file_name): - if file_name in self.local_set: - DesktopFile(file_name, local=True).add_shortcuts() #False : don't add the tag : created for bumblebee - print 'Bumblebee Shortcuts added to: ' + file_name - elif file_name in self.global_set: - DesktopFile(file_name, local=False).add_shortcuts() #True : add the tag : created for bumblebee - self.local_set.add(file_name) - self.global_set.remove(file_name) - print 'Bumblebee Shortcuts added to a desktop file created: ' + file_name - else : print "ERROR : The app name of configured file is not recognized" + def configure_file (self, file_name): + if file_name in self.local_set: + DesktopFile(file_name, local=True).add_shortcuts() #False : don't add the tag : created for bumblebee + print 'Bumblebee Shortcuts added to: ' + file_name + elif file_name in self.global_set: + DesktopFile(file_name, local=False).add_shortcuts() #True : add the tag : created for bumblebee + self.local_set.add(file_name) + self.global_set.remove(file_name) + print 'Bumblebee Shortcuts added to a desktop file created: ' + file_name + else : print "ERROR : The app name of configured file is not recognized" - def unconfigure_file (self, file_name): - if DesktopFile(file_name).unconfigure_file(): - self.local_set.remove(file_name) - self.global_set.add(file_name) - print 'Desktop file created for Bumblebee removed: ' + file_name - else: print 'Desktop file modified for Bumblebee is unconfigured: ' + file_name + def unconfigure_file (self, file_name): + if DesktopFile(file_name).unconfigure_file(): + self.local_set.remove(file_name) + self.global_set.add(file_name) + print 'Desktop file created for Bumblebee removed: ' + file_name + else: print 'Desktop file modified for Bumblebee is unconfigured: ' + file_name #TODO : Rewrite in order to allow use of the script without user interface -#MAIN DESKTOP FILE CLASS +# MAIN DESKTOP FILE CLASS class DesktopFile: -###INITIALIZATION OF A DESKTOP FILE OBJECT - def __init__(self,file_name,local=True): - """Function that create a desktop file object that can be parsed""" - self.file_name_without_extension=file_name - self.file_name_with_extension=self.file_name_without_extension + ".desktop" - self.local = local - if self.local == True : - self.file_path = Config.user_desktop_file_directory + self.file_name_with_extension - elif self.local == False : self.file_path = Config.global_desktop_file_directory + self.file_name_with_extension - self.config = ConfigParser.ConfigParser() - self.config.optionxform = str - self.config.read(self.file_path) +# INITIALIZATION OF A DESKTOP FILE OBJECT + def __init__(self,file_name,local=True): + """Function that create a desktop file object that can be parsed""" + self.file_name_without_extension=file_name + self.file_name_with_extension=self.file_name_without_extension + ".desktop" + self.local = local + if self.local == True : + self.file_path = Config.user_desktop_file_directory + self.file_name_with_extension + elif self.local == False : self.file_path = Config.global_desktop_file_directory + self.file_name_with_extension + self.config = ConfigParser.ConfigParser() + self.config.optionxform = str + self.config.read(self.file_path) -###FUNCTIONS TO GET THE VALUES INSIDE ALL DESKTOP FILES - def get_app_info(self): - """Function to get values inside a desktop file object : - Application Name, File Name, Application Categories List, Application Icon Path""" - return [self.config.get('Desktop Entry','Name'), self.file_name_without_extension, self.get_category(), self.get_icon_path()] +# FUNCTIONS TO GET THE VALUES INSIDE ALL DESKTOP FILES + def get_app_info(self): + """Function to get values inside a desktop file object : + Application Name, File Name, Application Categories List, Application Icon Path""" + return [self.config.get('Desktop Entry','Name'), self.file_name_without_extension, self.get_category(), self.get_icon_path()] - def get_category(self, app_category=Config.unmatch_categorie[0]): - """Function to get the main category if categories are defined in the desktop file""" - try: - for item in reversed(self.config.get('Desktop Entry','Categories').split(';')): - for matching_item in reversed(Config.categorie_list): - if item==matching_item[0] : app_category = str(item) - except ConfigParser.NoOptionError: app_category=Config.uncategorized_categorie[0] - finally: return app_category + def get_category(self, app_category=Config.unmatch_categorie[0]): + """Function to get the main category if categories are defined in the desktop file""" + try: + for item in reversed(self.config.get('Desktop Entry','Categories').split(';')): + for matching_item in reversed(Config.categorie_list): + if item==matching_item[0] : app_category = str(item) + except ConfigParser.NoOptionError: app_category=Config.uncategorized_categorie[0] + finally: return app_category - def get_icon_path(self): - """Function to get the icon path or the icon name if an icon is defined in the desktop file""" - try : - icon_name=self.config.get('Desktop Entry', 'Icon') - if os.path.exists(icon_name): return icon_name - else: - try : return os.path.splitext(os.path.basename(icon_name))[0] - except : return Config.default_icon_name - except ConfigParser.NoOptionError: - return Config.default_icon_name - - - def is_configured(self): - """Function to check if the desktop file is configured for Bumblebee or not""" - try: - if (self.config.has_section('BumblebeeDisable Shortcut Group') - and self.config.has_section('BumblebeeEnable Shortcut Group') - and self.config.has_option('Desktop Entry','X-Ayatana-Desktop-Shortcuts')): return True - else: return False - except: return False + def get_icon_path(self): + """Function to get the icon path or the icon name if an icon is defined in the desktop file""" + try : + icon_name=self.config.get('Desktop Entry', 'Icon') + if os.path.exists(icon_name): return icon_name + else: + try : return os.path.splitext(os.path.basename(icon_name))[0] + except : return Config.default_icon_name + except ConfigParser.NoOptionError: + return Config.default_icon_name + + def is_configured(self): + """Function to check if the desktop file is configured for Bumblebee or not""" + try: + if (self.config.has_section('BumblebeeDisable Shortcut Group') + and self.config.has_section('BumblebeeEnable Shortcut Group') + and self.config.has_option('Desktop Entry','X-Ayatana-Desktop-Shortcuts')): return True + else: return False + except: return False -###FUNCTIONS TO GET VALUE INSIDE LOCAL DESKTOP FILES - def get_app_config(self): - """Function to search for configuration inside a local desktop file object : - Configured, (Selected by default : unselected), Mode, 32bits, Compression - """ - self.app_exec= self.config.get('Desktop Entry','Exec') - if self.is_configured(): return [True, True] + self.get_mode() - else: return [False, False] + [None] + self.get_exec_config(self.app_exec)[1:] - #else: return [False, False] + [None] + [False] + ['default'] - - - def get_mode(self): - """Function to get the mode and the exec config in a desktop file""" - Shortcuts = self.config.get('Desktop Entry', 'X-Ayatana-Desktop-Shortcuts') - exec_config= self.get_exec_config(self.app_exec) - if ( 'BumblebeeEnable' in Shortcuts and 'optirun ' in self.app_exec and exec_config[0] == True ): - return [Config.mode_keys['perf']] + exec_config[1:] - elif ( 'BumblebeeDisable' in Shortcuts and 'optirun ' in self.app_exec and exec_config[0] == False ) : - return [Config.mode_keys['eco']] + exec_config[1:] - elif ( 'BumblebeeDisable' in Shortcuts and not 'optirun ' in self.app_exec ): - return [Config.mode_keys['option']] + self.get_exec_config(self.config.get('BumblebeeDisable Shortcut Group','Exec'))[1:] - else: return ['Unrecognized mode'] + exec_config[1:] - - def set_true(arg, next_arg=None): return {arg:True} +# FUNCTIONS TO GET VALUE INSIDE LOCAL DESKTOP FILES + def get_app_config(self): + """Function to search for configuration inside a local desktop file object : + Configured, (Selected by default : unselected), Mode, 32bits, Compression + """ + self.app_exec= self.config.get('Desktop Entry','Exec') + if self.is_configured(): return [True, True] + self.get_mode() + else: return [False, False] + [None] + self.get_exec_config(self.app_exec)[1:] + #else: return [False, False] + [None] + [False] + ['default'] - def get_compression(arg, next_arg=None, default=Config.default_compression): - if (next_arg in Config.compression_list and next_arg != default): return {arg:next_arg} + def get_mode(self): + """Function to get the mode and the exec config in a desktop file""" + Shortcuts = self.config.get('Desktop Entry', 'X-Ayatana-Desktop-Shortcuts') + exec_config= self.get_exec_config(self.app_exec) + if ( 'BumblebeeEnable' in Shortcuts and 'optirun ' in self.app_exec and exec_config[0] == True ): + return [Config.mode_keys['perf']] + exec_config[1:] + elif ( 'BumblebeeDisable' in Shortcuts and 'optirun ' in self.app_exec and exec_config[0] == False ) : + return [Config.mode_keys['eco']] + exec_config[1:] + elif ( 'BumblebeeDisable' in Shortcuts and not 'optirun ' in self.app_exec ): + return [Config.mode_keys['option']] + self.get_exec_config(self.config.get('BumblebeeDisable Shortcut Group','Exec'))[1:] + else: return ['Unrecognized mode'] + exec_config[1:] + + def set_true(arg, next_arg=None): return {arg:True} - def get_exec_config(self, Exec, i=-1, - case={'-32':set_true, '-f':set_true, '-c':get_compression}, - skip=['optirun', 'optirun', '-d', ':0', ':1', ':2'] + Config.compression_list): - """Function to search for configuration inside optirun arguments in the desktop file object : - Force_eco, 32bits, Compression""" + def get_compression(arg, next_arg=None, default=Config.default_compression): + if (next_arg in Config.compression_list and next_arg != default): return {arg:next_arg} + def get_exec_config(self, Exec, i=-1, + case={'-32':set_true, '-f':set_true, '-c':get_compression}, + skip=['optirun', 'optirun', '-d', ':0', ':1', ':2'] + Config.compression_list): + """Function to search for configuration inside optirun arguments in the desktop file object : + Force_eco, 32bits, Compression""" arg_list=re.split(' ',Exec) - exec_config={'-f':False, '-32':False, '-c':'default'} - for arg in arg_list: - i = i+1 - if arg in case: exec_config.update(case.get(arg)(arg,next_arg=arg_list[i+1])) - elif arg in skip: continue - else: break - return [exec_config['-f']] + [exec_config['-32']] + [exec_config['-c']] + exec_config={'-f':False, '-32':False, '-c':'default'} + for arg in arg_list: + i = i+1 + if arg in case: exec_config.update(case.get(arg)(arg,next_arg=arg_list[i+1])) + elif arg in skip: continue + else: break + return [exec_config['-f']] + [exec_config['-32']] + [exec_config['-c']] -#FUNCTION TO GET THE LIST OF ARGUMENT FOR SUBPROCESS - def get_exec_list(self): - return re.split(' ',self.config.get('BumblebeeDisable Shortcut Group','Exec')) +# FUNCTION TO GET THE LIST OF ARGUMENT FOR SUBPROCESS + def get_exec_list(self): + return re.split(' ',self.config.get('BumblebeeDisable Shortcut Group','Exec')) - -###FUNCTIONS TO CONFIGURE THE FILES WITH SHORTCUTS - def write_config_to_file(self,output_file_name): - with open(output_file_name,'w') as file_object: - self.config.write(file_object) +# FUNCTIONS TO CONFIGURE THE FILES WITH SHORTCUTS + def write_config_to_file(self,output_file_name): + with open(output_file_name,'w') as file_object: + self.config.write(file_object) - def configure_file(self): - """Function to configure the local or global desktop file""" - if self.local == False: - try : self.config.set('Desktop Entry', 'Comment', self.config.get('Desktop Entry','Comment') + '(Bumblebee enabled)') - except ConfigParser.NoOptionError: - self.config.set('Desktop Entry', 'Comment', 'This file has been created for Bumblebee (Bumblebee enabled)') - self.add_shortcuts() - os.chmod(Config.user_desktop_file_directory + self.file_name_with_extension,0755) - elif self.local == True: - self.add_shortcuts + def configure_file(self): + """Function to configure the local or global desktop file""" + if self.local == False: + try : self.config.set('Desktop Entry', 'Comment', self.config.get('Desktop Entry','Comment') + '(Bumblebee enabled)') + except ConfigParser.NoOptionError: + self.config.set('Desktop Entry', 'Comment', 'This file has been created for Bumblebee (Bumblebee enabled)') + self.add_shortcuts() + os.chmod(Config.user_desktop_file_directory + self.file_name_with_extension,0755) + elif self.local == True: + self.add_shortcuts - def add_shortcuts(self): - """Function to add shorcut section for bumblebee and add a shortcut to the desktop file object""" - self.prepend_option('Desktop Entry', 'X-Ayatana-Desktop-Shortcuts', 'BumblebeeDisable') - Exec = self.config.get('Desktop Entry', 'Exec') - #TODO Check if this is really needed - #self.config.set('Desktop Entry','OnlyShowIn','GNOME;Unity;") - self.add_shortcut_section('BumblebeeDisable Shortcut Group', 'Launch with Bumblebee', 'optirun -f ' + Exec) #Default setting is optional and forced - self.add_shortcut_section('BumblebeeEnable Shortcut Group', 'Launch without Bumblebee', Exec) - self.write_config_to_file(Config.user_desktop_file_directory + self.file_name_with_extension) - if self.local == False: os.chmod(Config.user_desktop_file_directory + self.file_name_with_extension,0755) + def add_shortcuts(self): + """Function to add shorcut section for bumblebee and add a shortcut to the desktop file object""" + self.prepend_option('Desktop Entry', 'X-Ayatana-Desktop-Shortcuts', 'BumblebeeDisable') + Exec = self.config.get('Desktop Entry', 'Exec') + #TODO Check if this is really needed + #self.config.set('Desktop Entry','OnlyShowIn','GNOME;Unity;") + self.add_shortcut_section('BumblebeeDisable Shortcut Group', 'Launch with Bumblebee', 'optirun -f ' + Exec) #Default setting is optional and forced + self.add_shortcut_section('BumblebeeEnable Shortcut Group', 'Launch without Bumblebee', Exec) + self.write_config_to_file(Config.user_desktop_file_directory + self.file_name_with_extension) + if self.local == False: os.chmod(Config.user_desktop_file_directory + self.file_name_with_extension,0755) - def add_shortcut_section(self,Section_title,Section_name,Section_exec): - self.config.add_section(Section_title) - self.config.set(Section_title, 'Name', Section_name) - self.config.set(Section_title, 'Exec', Section_exec) - self.config.set(Section_title, 'TargetEnvironment', 'Unity') + def add_shortcut_section(self,Section_title,Section_name,Section_exec): + self.config.add_section(Section_title) + self.config.set(Section_title, 'Name', Section_name) + self.config.set(Section_title, 'Exec', Section_exec) + self.config.set(Section_title, 'TargetEnvironment', 'Unity') - def prepend_option(self,section,option,value): - """Function to prepend a value to an option inside section of a desktop file object""" - if self.config.has_option(section,option) == True: self.config.set(section,option, value + ";" + self.config.get(section,option)) - else : self.config.set(section,option,value) + def prepend_option(self,section,option,value): + """Function to prepend a value to an option inside section of a desktop file object""" + if self.config.has_option(section,option) == True: self.config.set(section,option, value + ";" + self.config.get(section,option)) + else : self.config.set(section,option,value) -###FUNCTIONS TO UNCONFIGURE FILES OR REMOVE THEM - def is_created(self): - """Function to check if the file is tagged as created for Bumblebee or not""" - try: #FIXME Bumblebee Enable must not be set in comment but somewhere else - if 'Bumblebee enabled' in self.config.get('Desktop Entry','Comment'): return True - else : return False - except ConfigParser.NoOptionError: return False +# FUNCTIONS TO UNCONFIGURE FILES OR REMOVE THEM + def is_created(self): + """Function to check if the file is tagged as created for Bumblebee or not""" + try: #FIXME Bumblebee Enable must not be set in comment but somewhere else + if 'Bumblebee enabled' in self.config.get('Desktop Entry','Comment'): return True + else : return False + except ConfigParser.NoOptionError: return False - def unconfigure_file(self): - """Function to unconfigure a file configured for Bumblebee : remove the shortcuts or remove the file if it's tagged as created for Bumblebee""" - if self.is_created(): - os.remove(self.file_path) - return True - else: - self.remove_shortcuts() - return False + def unconfigure_file(self): + """Function to unconfigure a file configured for Bumblebee : remove the shortcuts or remove the file if it's tagged as created for Bumblebee""" + if self.is_created(): + os.remove(self.file_path) + return True + else: + self.remove_shortcuts() + return False - def remove_shortcuts(self): - """Function to remove shorcut section for bumblebee and remove the shortcuts to the desktop file object""" - self.config.set('Desktop Entry','Exec',self.config.get('BumblebeeEnable Shortcut Group','Exec')) - Shortcuts=self.config.get('Desktop Entry','X-Ayatana-Desktop-Shortcuts') - if Shortcuts=='BumblebeeDisable' or Shortcuts=='BumblebeeEnable': self.config.remove_option('Desktop Entry','X-Ayatana-Desktop-Shortcuts') - else : self.remove_prepend_option('Desktop Entry','X-Ayatana-Desktop-Shortcuts','BumblebeeDisable\;|BumblebeeEnable\;') - self.config.remove_section('BumblebeeDisable Shortcut Group') - self.config.remove_section('BumblebeeEnable Shortcut Group') - self.write_config_to_file(self.file_path) + def remove_shortcuts(self): + """Function to remove shorcut section for bumblebee and remove the shortcuts to the desktop file object""" + self.config.set('Desktop Entry','Exec',self.config.get('BumblebeeEnable Shortcut Group','Exec')) + Shortcuts=self.config.get('Desktop Entry','X-Ayatana-Desktop-Shortcuts') + if Shortcuts=='BumblebeeDisable' or Shortcuts=='BumblebeeEnable': self.config.remove_option('Desktop Entry','X-Ayatana-Desktop-Shortcuts') + else : self.remove_prepend_option('Desktop Entry','X-Ayatana-Desktop-Shortcuts','BumblebeeDisable\;|BumblebeeEnable\;') + self.config.remove_section('BumblebeeDisable Shortcut Group') + self.config.remove_section('BumblebeeEnable Shortcut Group') + self.write_config_to_file(self.file_path) - def remove_prepend_option(self,section,option,value): - """Function to remove a value from an option inside section of a desktop file object""" - if self.config.has_option(section,option) == True: self.config.set(section,option,re.sub(value,'',self.config.get(section,option))) + def remove_prepend_option(self,section,option,value): + """Function to remove a value from an option inside section of a desktop file object""" + if self.config.has_option(section,option) == True: self.config.set(section,option,re.sub(value,'',self.config.get(section,option))) -###FUNCTIONS TO CONFIGURE THE EXECUTION OF THE APPLICATION +# FUNCTIONS TO CONFIGURE THE EXECUTION OF THE APPLICATION - def set_exec_config(self, mode, bits32, compression): - """Function to set the option for optirun : default, 32 bits, on battery, compression""" - option='' - if bits32==True: option+='-32 ' - if not (compression == "default" or compression == Config.default_compression) : option+='-c '+ compression + ' ' - clean_exec= self.config.get('BumblebeeEnable Shortcut Group','Exec') - self.config.set('BumblebeeDisable Shortcut Group','Exec','optirun -f ' + option + clean_exec) - if mode == Config.mode_keys['perf']: - self.set_exec_config_default('optirun -f ' + option + clean_exec, 'BumblebeeDisable', 'BumblebeeEnable') - elif mode == Config.mode_keys['eco']: - self.set_exec_config_default('optirun ' + option + clean_exec, 'BumblebeeEnable', 'BumblebeeDisable') - else: - self.set_exec_config_default(clean_exec, 'BumblebeeEnable', 'BumblebeeDisable') - self.write_config_to_file(self.file_path) + def set_exec_config(self, mode, bits32, compression): + """Function to set the option for optirun : default, 32 bits, on battery, compression""" + option='' + if bits32==True: option+='-32 ' + if not (compression == "default" or compression == Config.default_compression) : option+='-c '+ compression + ' ' + clean_exec= self.config.get('BumblebeeEnable Shortcut Group','Exec') + self.config.set('BumblebeeDisable Shortcut Group','Exec','optirun -f ' + option + clean_exec) + if mode == Config.mode_keys['perf']: + self.set_exec_config_default('optirun -f ' + option + clean_exec, 'BumblebeeDisable', 'BumblebeeEnable') + elif mode == Config.mode_keys['eco']: + self.set_exec_config_default('optirun ' + option + clean_exec, 'BumblebeeEnable', 'BumblebeeDisable') + else: + self.set_exec_config_default(clean_exec, 'BumblebeeEnable', 'BumblebeeDisable') + self.write_config_to_file(self.file_path) - def set_exec_config_default(self,Exec,Initial_shortcut,Final_shortcut): - self.config.set('Desktop Entry','Exec',Exec) - self.config.set('Desktop Entry','X-Ayatana-Desktop-Shortcuts', re.sub(Initial_shortcut,Final_shortcut,self.config.get('Desktop Entry','X-Ayatana-Desktop-Shortcuts'))) + def set_exec_config_default(self,Exec,Initial_shortcut,Final_shortcut): + self.config.set('Desktop Entry','Exec',Exec) + self.config.set('Desktop Entry','X-Ayatana-Desktop-Shortcuts', re.sub(Initial_shortcut,Final_shortcut,self.config.get('Desktop Entry','X-Ayatana-Desktop-Shortcuts'))) if __name__=="__main__" : - print "DesktopFile.py can't run as a standalone application" - quit() + print "DesktopFile.py can't run as a standalone application" + quit() diff --git a/app/__init__.py b/app/__init__.py index 086b8e3..1d60a65 100755 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,29 +1,21 @@ #!/usr/bin/python -# -*- coding: utf-8 -*- +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- ### BEGIN LICENSE # -# ---------------------------------------------------------------------------- -# "THE BEER-WARE LICENSE" (Revision 42): -# wrote this file. As long as you retain this notice you -# can do whatever you want with this stuff. If we meet some day, and you think -# this stuff is worth it, you can buy me a beer in return Davy Renaud (glyptostroboides) -# ---------------------------------------------------------------------------- +# This file is part of bumblebee-ui. # - -# This file is part of bumblebee-ui. -# -# bumblebee-ui 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 3 of the License, or -# (at your option) any later version. +# bumblebee-ui 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 3 of the License, or +# (at your option) any later version. # -# bumblebee-ui 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. +# bumblebee-ui 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 bumblebee-ui. If not, see . +# You should have received a copy of the GNU General Public License +# along with bumblebee-ui. If not, see . # ### END LICENSE diff --git a/bumblebee-indicator b/bumblebee-indicator index f1a90b4..631d86d 100755 --- a/bumblebee-indicator +++ b/bumblebee-indicator @@ -1,33 +1,25 @@ #!/usr/bin/python -# -*- coding: utf-8 -*- +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- ### BEGIN LICENSE # -# ---------------------------------------------------------------------------- -# "THE BEER-WARE LICENSE" (Revision 42): -# wrote this file. As long as you retain this notice you -# can do whatever you want with this stuff. If we meet some day, and you think -# this stuff is worth it, you can buy me a beer in return Davy Renaud (glyptostroboides) -# ---------------------------------------------------------------------------- +# This file is part of bumblebee-ui. # - -# This file is part of bumblebee-ui. -# -# bumblebee-ui 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 3 of the License, or -# (at your option) any later version. +# bumblebee-ui 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 3 of the License, or +# (at your option) any later version. # -# bumblebee-ui 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. +# bumblebee-ui 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 bumblebee-ui. If not, see . +# You should have received a copy of the GNU General Public License +# along with bumblebee-ui. If not, see . # ### END LICENSE -#UI MODULE +# UI MODULE import pygtk pygtk.require('2.0') import gtk @@ -35,11 +27,11 @@ import gobject import appindicator import pynotify -#SYSTEM MODULE +# SYSTEM MODULE import os import subprocess -###ORIGINAL CLASS +# ORIGINAL CLASS import app.Config from app.AppSettings import Applications_settings, IconSet from app.DesktopFile import DesktopFile, DesktopFileSet @@ -48,27 +40,26 @@ class BumblebeeIndicator(): #TODO There must be a better way to get the icon than the URI #FIXME The notification must be replaced when still visible def notify_state(self, title, msg, icon_name): - self.notification= pynotify.Notification(title, msg, IconSet().get_uri(icon_name,48)) + self.notification= pynotify.Notification(title, msg, IconSet().get_uri(icon_name,48)) self.notification.set_urgency(pynotify.URGENCY_CRITICAL) - #FIXME The notification is to slow and this doesn't work +#FIXME The notification is to slow and this doesn't work #self.notification.set_timeout(1000) self.notification.show() -###INITIALIZATION OF INDICATOR AND MENU +# INITIALIZATION OF INDICATOR AND MENU def __init__(self): self.ind = appindicator.Indicator ("bumblebee-indicator", "bumblebee-indicator", appindicator.CATEGORY_HARDWARE) self.ind.set_status (appindicator.STATUS_ACTIVE) self.ind.set_icon_theme_path(app.Config.icon_file_directory) - #TODO The icons style and accesibility must be enhanced : see icons/test directory - self.ind.set_icon(app.Config.icon_file_directory + "bumblebee-indicator.svg",'Bumblebee is unactive') +#TODO The icons style and accesibility must be enhanced : see icons/test directory + self.ind.set_icon(app.Config.icon_file_directory + "bumblebee-indicator.svg",'Bumblebee is unactive') self.ind.set_attention_icon (app.Config.icon_file_directory + "bumblebee-indicator-active.svg",'Bumblebee is active') self.card_state=False - - self.lock_file = "/tmp/.X%s-lock" % app.Config.vgl_display - + self.lock_file = "/tmp/.X%s-lock" % app.Config.vgl_display + self.build_menu() - + self.menu.show() self.ind.set_menu(self.menu) @@ -81,9 +72,9 @@ class BumblebeeIndicator(): self.initial_state_checker() self.switch.set_sensitive(False) self.menu.append(self.switch) - + self.build_menu_separator(self.menu) - + self.prefered_app_submenu = gtk.MenuItem("Preferred Apps") self.update_menu() self.prefered_app_submenu.connect('activate', self.update_menu) @@ -93,7 +84,7 @@ class BumblebeeIndicator(): item2.connect("activate", self.app_configure) self.menu.append(item2) - #TODO An UI to configure Bumblebee would be nice +#TODO An UI to configure Bumblebee would be nice self.build_menu_separator(self.menu) @@ -108,36 +99,36 @@ class BumblebeeIndicator(): separator.show() menu.append(separator) -# FUNCTIONS TO BUILD THE "PREFERRED APP" MENU FROM THE CONFIG FILE +# FUNCTIONS TO BUILD THE "PREFERRED APP" MENU FROM THE LOCAL DESKTOP FILES def update_menu(self, widget=None): pref_menu=gtk.Menu() - self.add_submenu_items( pref_menu, app.Config.default_preferred_apps ) - self.build_menu_separator( pref_menu ) - self.add_submenu_items( pref_menu, DesktopFileSet().get_configured_from_check() ) + self.add_submenu_items( pref_menu, app.Config.default_preferred_apps ) + self.build_menu_separator( pref_menu ) + self.add_submenu_items( pref_menu, DesktopFileSet().get_configured_from_check() ) pref_menu.show() self.prefered_app_submenu.set_submenu(pref_menu) def add_submenu_items(self, submenu, items_list): - for Name, Exec_list in items_list : - subitem = gtk.MenuItem(label=Name) - subitem.connect("activate", self.call_app, Exec_list) + for Name, Exec_list in items_list : + subitem = gtk.MenuItem(label=Name) + subitem.connect("activate", self.call_app, Exec_list) subitem.show() - submenu.append( subitem ) + submenu.append( subitem ) -# FUNCTIONS TO GET THE STATE OF THE INDICATOR +# FUNCTIONS TO CHECK FOR THE STATE OF THE INDICATOR def initial_state_checker(self): - if self.attention_state_condition(): self.set_attention_state(notify=False) - else : self.set_active_state(notify=False) + if self.attention_state_condition(): self.set_attention_state(notify=False) + else : self.set_active_state(notify=False) def state_checker(self): - if self.attention_state_condition(): - if self.card_state == False : self.set_attention_state() + if self.attention_state_condition(): + if self.card_state == False : self.set_attention_state() elif self.card_state == True: self.set_active_state() - return True + return True def attention_state_condition(self): - if os.path.exists(self.lock_file): return True - else: return False + if os.path.exists(self.lock_file): return True + else: return False # FUNCTIONS TO SET THE STATE OF THE INDICATOR AND LAUNCH NOTIFICATION def set_attention_state(self, notify=True): @@ -157,18 +148,18 @@ class BumblebeeIndicator(): # FUNCTION TO DEFINE THE APPLICATIONS SETTING LINK IN THE INDICATOR def app_configure(self,widget): - Applications_settings() + Applications_settings() # FUNCTION TO LAUNCH THE APPS WITHIN THE INDICATOR def call_app(self, widget, app_exec): - #FIXME There is a problem when closing the launched app and when the indicator has been closed: the indicator is still running : What a daemon!! +#FIXME There is a problem when closing the launched app and when the indicator has been closed: the indicator is still running : What a daemon!! subprocess.Popen(app_exec,shell=False) # MAIN LOOP LAUNCHING A STATE CHECK EVERY TWO SECONDS def main(self): self.state_checker() - #FIXME It would be nice to avoid this loop : Maybe by using a signal emitted by the system - #gtk.timeout_add(1000,self.state_checker) +#FIXME It would be nice to avoid this loop : Maybe by using a signal emitted by the system + #gtk.timeout_add(2000,self.state_checker) gobject.timeout_add_seconds(2, self.state_checker) gtk.main() From 14caf6549bdade26378c21cea0910c734ec42fdd Mon Sep 17 00:00:00 2001 From: Davy RENAUD Date: Fri, 19 Aug 2011 01:06:43 +0200 Subject: [PATCH 10/17] Correct an indentation mistake caused by last commit --- bumblebee-indicator | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bumblebee-indicator b/bumblebee-indicator index 631d86d..170f012 100755 --- a/bumblebee-indicator +++ b/bumblebee-indicator @@ -42,7 +42,7 @@ class BumblebeeIndicator(): def notify_state(self, title, msg, icon_name): self.notification= pynotify.Notification(title, msg, IconSet().get_uri(icon_name,48)) self.notification.set_urgency(pynotify.URGENCY_CRITICAL) -#FIXME The notification is to slow and this doesn't work + #FIXME The notification is to slow and this doesn't work #self.notification.set_timeout(1000) self.notification.show() @@ -123,7 +123,7 @@ class BumblebeeIndicator(): def state_checker(self): if self.attention_state_condition(): if self.card_state == False : self.set_attention_state() - elif self.card_state == True: self.set_active_state() + elif self.card_state == True: self.set_active_state() return True def attention_state_condition(self): From 755c23de93fb787d34711aeada505c92ad9084a7 Mon Sep 17 00:00:00 2001 From: Davy RENAUD Date: Fri, 19 Aug 2011 03:14:41 +0200 Subject: [PATCH 11/17] Factorize a little the indicator status notification. Changed also the message displayed by the indicator, till the power saving feature is back And a small little change concerning parsing configuration value inside shell file --- app/Config.py | 12 +++++++++--- bumblebee-indicator | 27 ++++++++++++++++----------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/app/Config.py b/app/Config.py index 2ab446d..5ed7c3e 100644 --- a/app/Config.py +++ b/app/Config.py @@ -55,9 +55,8 @@ def get_config_value(variable_name): """Function to get configuration value inside a shell script""" for line in open(config_file_path): - if variable_name in line: - variable, value= line.split('=',1) - return value.replace("\n","") + if variable_name in line: + return line.split('=',1)[1].replace("\n","") default_compression= get_config_value('VGL_COMPRESS') vgl_display= get_config_value('VGL_DISPLAY').replace(":","") @@ -80,6 +79,13 @@ def get_config_value(variable_name): default_preferred_apps =[ ['Glxgears', ['optirun', 'glxgears']] , ['Glxspheres', ['optirun', 'glxspheres']] ] +#NOTIFICATION MESSAGES : +#TODO Revert when the possibility to turn off the card is back +attention_label="Bumblebee : ON" +attention_comment="Bumblebee is in use" +active_label="Bumblebee : OFF" +active_comment="Bumblebee is not used anymore" + #TODO : There might be a way to use string formatting to simplify the config definition #FIXME There must be a better way to store config diff --git a/bumblebee-indicator b/bumblebee-indicator index 170f012..c854dfe 100755 --- a/bumblebee-indicator +++ b/bumblebee-indicator @@ -132,19 +132,24 @@ class BumblebeeIndicator(): # FUNCTIONS TO SET THE STATE OF THE INDICATOR AND LAUNCH NOTIFICATION def set_attention_state(self, notify=True): - self.ind.set_status(appindicator.STATUS_ATTENTION) - self.card_state = True - if notify == True: self.notify_state("Discrete card : ON", "Discrete graphic card is powered on", "bumblebee-indicator-active") - self.switch.set_label("Discrete card : ON") - self.switch.set_active(True) + self.set_status(True, appindicator.STATUS_ATTENTION, + app.Config.attention_label, + app.Config.attention_comment, + "bumblebee-indicator-active", notify) def set_active_state(self, notify=True): - self.ind.set_status(appindicator.STATUS_ACTIVE) - self.card_state = False - if notify == True: self.notify_state("Discrete card : OFF", "Discrete graphic card is powered off", "bumblebee-indicator") - self.switch.set_label("Discrete card : OFF") - self.switch.set_active(False) - + self.set_status(False, appindicator.STATUS_ACTIVE, + app.Config.active_label, + app.Config.active_comment, + "bumblebee-indicator", notify) + + def set_status(self, status, indicator, label, comment, icon, notify): + self.ind.set_status(indicator) + self.card_state = status + if notify == True: self.notify_state(label, comment, icon) + self.switch.set_label(label) + self.switch.set_active(status) + # FUNCTION TO DEFINE THE APPLICATIONS SETTING LINK IN THE INDICATOR def app_configure(self,widget): From 01aa2b26226fabf2609b3fc259585f7031d0c203 Mon Sep 17 00:00:00 2001 From: Davy RENAUD Date: Fri, 19 Aug 2011 16:57:29 +0200 Subject: [PATCH 12/17] Correct a bug leading to leave some desktop file copied by the ui in the local desktop file directory You have to manually remove the desktop file left behind, if ever. Sorry. --- app/DesktopFile.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/DesktopFile.py b/app/DesktopFile.py index c444f3f..da03e62 100755 --- a/app/DesktopFile.py +++ b/app/DesktopFile.py @@ -68,10 +68,10 @@ def get_apps_info (self): def configure_file (self, file_name): if file_name in self.local_set: - DesktopFile(file_name, local=True).add_shortcuts() #False : don't add the tag : created for bumblebee + DesktopFile(file_name, local=True).configure_file() #False : don't add the tag : created for bumblebee print 'Bumblebee Shortcuts added to: ' + file_name elif file_name in self.global_set: - DesktopFile(file_name, local=False).add_shortcuts() #True : add the tag : created for bumblebee + DesktopFile(file_name, local=False).configure_file() #True : add the tag : created for bumblebee self.local_set.add(file_name) self.global_set.remove(file_name) print 'Bumblebee Shortcuts added to a desktop file created: ' + file_name @@ -189,13 +189,13 @@ def write_config_to_file(self,output_file_name): def configure_file(self): """Function to configure the local or global desktop file""" if self.local == False: - try : self.config.set('Desktop Entry', 'Comment', self.config.get('Desktop Entry','Comment') + '(Bumblebee enabled)') + try : self.config.set('Desktop Entry', 'Comment', self.config.get('Desktop Entry','Comment') + ' (created for Bumblebee)') except ConfigParser.NoOptionError: - self.config.set('Desktop Entry', 'Comment', 'This file has been created for Bumblebee (Bumblebee enabled)') + self.config.set('Desktop Entry', 'Comment', 'This file has been created for Bumblebee.') self.add_shortcuts() os.chmod(Config.user_desktop_file_directory + self.file_name_with_extension,0755) elif self.local == True: - self.add_shortcuts + self.add_shortcuts() def add_shortcuts(self): """Function to add shorcut section for bumblebee and add a shortcut to the desktop file object""" @@ -224,7 +224,7 @@ def prepend_option(self,section,option,value): def is_created(self): """Function to check if the file is tagged as created for Bumblebee or not""" try: #FIXME Bumblebee Enable must not be set in comment but somewhere else - if 'Bumblebee enabled' in self.config.get('Desktop Entry','Comment'): return True + if 'created for Bumblebee' in self.config.get('Desktop Entry','Comment'): return True else : return False except ConfigParser.NoOptionError: return False From 94afd07599a28604af94af4fe78885aec928e06d Mon Sep 17 00:00:00 2001 From: skad Date: Thu, 26 Jan 2012 10:30:36 +0100 Subject: [PATCH 13/17] Making INSTALL work clean Installation in good directory Create an UNINSTALL to remove Bumblebee-ui Use the default icon theme path for bumblebee indicator debug for config file vgl_display info missing remove the -f option in DesktopFile with make bumblebee indicator won't launch any application corect the icon path in Config.py and bumblebee-indicator.py --- INSTALL | 36 +++++++++++------------------------- README | 3 ++- app/Config.py | 4 ++-- app/DesktopFile.py | 6 +++--- 4 files changed, 18 insertions(+), 31 deletions(-) mode change 100644 => 100755 INSTALL diff --git a/INSTALL b/INSTALL old mode 100644 new mode 100755 index 6cd73cd..e184b5d --- a/INSTALL +++ b/INSTALL @@ -17,34 +17,20 @@ # ### END LICENSE -#This script is just an example and should not be used -#Wait for good scripts or do it manually - -#Copy software files /app, /icons, bumblebee-indicator in /usr/local/bin -#cp -R app/ /usr/local/bin/app -#cp -R icons/ /usr/local/bin/icons -#cp bumblebee-indicator /usr/local/bin - -#Create bumblebee-app-settings a link to AppSettings.py -#ln -s /usr/local/bin/app/AppSettings.py /usr/local/bin/bumblebee-app-settings - -#Copy desktop files in /usr/share/applications -#cp bumblebee-app-settings.desktop /usr/share/applications/ -#cp bumblebee-indicator.desktop /usr/share/applications/ - -#Copy or link icons in /usr/share/icons or /usr/share/pixmaps -#cp icons/bumblebee.svg /usr/share/icons/ - -#Set the correct right for some files -#chmod +x /usr/local/bin/bumblebee-indicator -#chmod +x /usr/local/bin/app/* -#chmod +x /usr/share/applications/bumblebee-app-settings.desktop -#chmod +x /usr/share/applications/bumblebee-indicator.desktop +cp icons/*.* /usr/share/icons/hicolor/48x48/apps/ +mkdir /usr/share/bumblebee-ui/ +cp app/*.* /usr/share/bumblebee-ui/ +cp bumblebee-app-settings.desktop /usr/share/applications/ +cp bumblebee-indicator.desktop /usr/share/applications/ +ln -s /usr/share/bumblebee-ui/AppSettings.py /usr/local/bin/bumblebee-app-settings +ln -s /usr/share/bumblebee-ui/Bumblebee-Indicator.py /usr/local/bin/bumblebee-indicator + +chmod +x /usr/share/applications/bumblebee-app-settings.desktop +chmod +x /usr/share/applications/bumblebee-indicator.desktop +chmod +x -R /usr/share/bumblebee-ui/ #TO DO MANUALLY #Add bumblebee-indicator at startup # # # -# - diff --git a/README b/README index 20d516f..ec894ae 100644 --- a/README +++ b/README @@ -24,4 +24,5 @@ Please give it a try and report bugs to : https://github.com/Bumblebee-Project/bumblebee-ui/issues Thanks for your help. - +Instalation : just run INSTALL +Uninstalation : just run UNINSTALL in /usr/share/bumblee-iu/ diff --git a/app/Config.py b/app/Config.py index 5ed7c3e..921f618 100644 --- a/app/Config.py +++ b/app/Config.py @@ -29,7 +29,7 @@ global_desktop_file_directory = '/usr/share/applications/' #ICONS FILE PATH -icon_file_directory = '/usr/share/bumblebee-ui/icons/' +icon_file_directory = '/usr/share/icons/hicolor/48x48/apps/' #ACCEPTED COMPRESSION compression_list=['jpeg','proxy','rgb','yuv','xv'] @@ -59,7 +59,7 @@ def get_config_value(variable_name): return line.split('=',1)[1].replace("\n","") default_compression= get_config_value('VGL_COMPRESS') -vgl_display= get_config_value('VGL_DISPLAY').replace(":","") +vgl_display= get_config_value('VirtualDisplay').replace(":","") #CATEGORIES CONFIGURATION diff --git a/app/DesktopFile.py b/app/DesktopFile.py index da03e62..daa20ee 100755 --- a/app/DesktopFile.py +++ b/app/DesktopFile.py @@ -203,7 +203,7 @@ def add_shortcuts(self): Exec = self.config.get('Desktop Entry', 'Exec') #TODO Check if this is really needed #self.config.set('Desktop Entry','OnlyShowIn','GNOME;Unity;") - self.add_shortcut_section('BumblebeeDisable Shortcut Group', 'Launch with Bumblebee', 'optirun -f ' + Exec) #Default setting is optional and forced + self.add_shortcut_section('BumblebeeDisable Shortcut Group', 'Launch with Bumblebee', 'optirun ' + Exec) #Default setting is optional and forced self.add_shortcut_section('BumblebeeEnable Shortcut Group', 'Launch without Bumblebee', Exec) self.write_config_to_file(Config.user_desktop_file_directory + self.file_name_with_extension) if self.local == False: os.chmod(Config.user_desktop_file_directory + self.file_name_with_extension,0755) @@ -260,9 +260,9 @@ def set_exec_config(self, mode, bits32, compression): if bits32==True: option+='-32 ' if not (compression == "default" or compression == Config.default_compression) : option+='-c '+ compression + ' ' clean_exec= self.config.get('BumblebeeEnable Shortcut Group','Exec') - self.config.set('BumblebeeDisable Shortcut Group','Exec','optirun -f ' + option + clean_exec) + self.config.set('BumblebeeDisable Shortcut Group','Exec','optirun ' + option + clean_exec) if mode == Config.mode_keys['perf']: - self.set_exec_config_default('optirun -f ' + option + clean_exec, 'BumblebeeDisable', 'BumblebeeEnable') + self.set_exec_config_default('optirun ' + option + clean_exec, 'BumblebeeDisable', 'BumblebeeEnable') elif mode == Config.mode_keys['eco']: self.set_exec_config_default('optirun ' + option + clean_exec, 'BumblebeeEnable', 'BumblebeeDisable') else: From 1529e45031834fee99117016e26fd27ba5c9ed04 Mon Sep 17 00:00:00 2001 From: skad Date: Thu, 26 Jan 2012 10:34:34 +0100 Subject: [PATCH 14/17] Delete of bumblebee-indicator after move in app/Bumblebee-Indicator.py --- bumblebee-indicator | 174 -------------------------------------------- 1 file changed, 174 deletions(-) delete mode 100755 bumblebee-indicator diff --git a/bumblebee-indicator b/bumblebee-indicator deleted file mode 100755 index c854dfe..0000000 --- a/bumblebee-indicator +++ /dev/null @@ -1,174 +0,0 @@ -#!/usr/bin/python -# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- -### BEGIN LICENSE -# -# This file is part of bumblebee-ui. -# -# bumblebee-ui 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 3 of the License, or -# (at your option) any later version. -# -# bumblebee-ui 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 bumblebee-ui. If not, see . -# -### END LICENSE - -# UI MODULE -import pygtk -pygtk.require('2.0') -import gtk -import gobject -import appindicator -import pynotify - -# SYSTEM MODULE -import os -import subprocess - -# ORIGINAL CLASS -import app.Config -from app.AppSettings import Applications_settings, IconSet -from app.DesktopFile import DesktopFile, DesktopFileSet - -class BumblebeeIndicator(): -#TODO There must be a better way to get the icon than the URI -#FIXME The notification must be replaced when still visible - def notify_state(self, title, msg, icon_name): - self.notification= pynotify.Notification(title, msg, IconSet().get_uri(icon_name,48)) - self.notification.set_urgency(pynotify.URGENCY_CRITICAL) - #FIXME The notification is to slow and this doesn't work - #self.notification.set_timeout(1000) - self.notification.show() - -# INITIALIZATION OF INDICATOR AND MENU - def __init__(self): - self.ind = appindicator.Indicator ("bumblebee-indicator", "bumblebee-indicator", appindicator.CATEGORY_HARDWARE) - self.ind.set_status (appindicator.STATUS_ACTIVE) - self.ind.set_icon_theme_path(app.Config.icon_file_directory) -#TODO The icons style and accesibility must be enhanced : see icons/test directory - self.ind.set_icon(app.Config.icon_file_directory + "bumblebee-indicator.svg",'Bumblebee is unactive') - self.ind.set_attention_icon (app.Config.icon_file_directory + "bumblebee-indicator-active.svg",'Bumblebee is active') - - self.card_state=False - self.lock_file = "/tmp/.X%s-lock" % app.Config.vgl_display - - self.build_menu() - - self.menu.show() - self.ind.set_menu(self.menu) - - def quit(self, widget, data=None): - gtk.main_quit() - - def build_menu(self): - self.menu = gtk.Menu() - self.switch = gtk.CheckMenuItem() - self.initial_state_checker() - self.switch.set_sensitive(False) - self.menu.append(self.switch) - - self.build_menu_separator(self.menu) - - self.prefered_app_submenu = gtk.MenuItem("Preferred Apps") - self.update_menu() - self.prefered_app_submenu.connect('activate', self.update_menu) - self.menu.append(self.prefered_app_submenu) - - item2 = gtk.MenuItem("Configure Apps") - item2.connect("activate", self.app_configure) - self.menu.append(item2) - -#TODO An UI to configure Bumblebee would be nice - - self.build_menu_separator(self.menu) - - quit = gtk.ImageMenuItem(gtk.STOCK_QUIT) - quit.connect("activate", self.quit) - self.menu.append(quit) - - self.menu.show_all() - - def build_menu_separator(self, menu): - separator = gtk.SeparatorMenuItem() - separator.show() - menu.append(separator) - -# FUNCTIONS TO BUILD THE "PREFERRED APP" MENU FROM THE LOCAL DESKTOP FILES - def update_menu(self, widget=None): - pref_menu=gtk.Menu() - self.add_submenu_items( pref_menu, app.Config.default_preferred_apps ) - self.build_menu_separator( pref_menu ) - self.add_submenu_items( pref_menu, DesktopFileSet().get_configured_from_check() ) - pref_menu.show() - self.prefered_app_submenu.set_submenu(pref_menu) - - def add_submenu_items(self, submenu, items_list): - for Name, Exec_list in items_list : - subitem = gtk.MenuItem(label=Name) - subitem.connect("activate", self.call_app, Exec_list) - subitem.show() - submenu.append( subitem ) - -# FUNCTIONS TO CHECK FOR THE STATE OF THE INDICATOR - def initial_state_checker(self): - if self.attention_state_condition(): self.set_attention_state(notify=False) - else : self.set_active_state(notify=False) - - def state_checker(self): - if self.attention_state_condition(): - if self.card_state == False : self.set_attention_state() - elif self.card_state == True: self.set_active_state() - return True - - def attention_state_condition(self): - if os.path.exists(self.lock_file): return True - else: return False - -# FUNCTIONS TO SET THE STATE OF THE INDICATOR AND LAUNCH NOTIFICATION - def set_attention_state(self, notify=True): - self.set_status(True, appindicator.STATUS_ATTENTION, - app.Config.attention_label, - app.Config.attention_comment, - "bumblebee-indicator-active", notify) - - def set_active_state(self, notify=True): - self.set_status(False, appindicator.STATUS_ACTIVE, - app.Config.active_label, - app.Config.active_comment, - "bumblebee-indicator", notify) - - def set_status(self, status, indicator, label, comment, icon, notify): - self.ind.set_status(indicator) - self.card_state = status - if notify == True: self.notify_state(label, comment, icon) - self.switch.set_label(label) - self.switch.set_active(status) - -# FUNCTION TO DEFINE THE APPLICATIONS SETTING LINK IN THE INDICATOR - - def app_configure(self,widget): - Applications_settings() - -# FUNCTION TO LAUNCH THE APPS WITHIN THE INDICATOR - def call_app(self, widget, app_exec): -#FIXME There is a problem when closing the launched app and when the indicator has been closed: the indicator is still running : What a daemon!! - subprocess.Popen(app_exec,shell=False) - -# MAIN LOOP LAUNCHING A STATE CHECK EVERY TWO SECONDS - def main(self): - self.state_checker() -#FIXME It would be nice to avoid this loop : Maybe by using a signal emitted by the system - #gtk.timeout_add(2000,self.state_checker) - gobject.timeout_add_seconds(2, self.state_checker) - gtk.main() - -if __name__ == "__main__": - indicator = BumblebeeIndicator() - indicator.main() - From 8a569eae2f39dbf60de0cec94bc3aef42b443aab Mon Sep 17 00:00:00 2001 From: skad Date: Thu, 26 Jan 2012 11:06:20 +0100 Subject: [PATCH 15/17] Add : Bumblebee-Indicator.py UNINSTALL --- app/Bumblebee-Indicator.py | 174 +++++++++++++++++++++++++++++++++++++ app/UNINSTALL | 31 +++++++ 2 files changed, 205 insertions(+) create mode 100755 app/Bumblebee-Indicator.py create mode 100755 app/UNINSTALL diff --git a/app/Bumblebee-Indicator.py b/app/Bumblebee-Indicator.py new file mode 100755 index 0000000..bcdfd06 --- /dev/null +++ b/app/Bumblebee-Indicator.py @@ -0,0 +1,174 @@ +#!/usr/bin/python +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- +### BEGIN LICENSE +# +# This file is part of bumblebee-ui. +# +# bumblebee-ui 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 3 of the License, or +# (at your option) any later version. +# +# bumblebee-ui 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 bumblebee-ui. If not, see . +# +### END LICENSE + +# UI MODULE +import pygtk +pygtk.require('2.0') +import gtk +import gobject +import appindicator +import pynotify + +# SYSTEM MODULE +import os +import subprocess + +# ORIGINAL CLASS +import Config +from AppSettings import Applications_settings, IconSet +from DesktopFile import DesktopFile, DesktopFileSet + +class BumblebeeIndicator(): +#TODO There must be a better way to get the icon than the URI +#FIXME The notification must be replaced when still visible + def notify_state(self, title, msg, icon_name): + pynotify.init("Bumblebee notification") + self.notification= pynotify.Notification(title, msg, IconSet().get_uri(icon_name,48)) + self.notification.set_urgency(pynotify.URGENCY_CRITICAL) + #FIXME The notification is to slow and this doesn't work + #self.notification.set_timeout(1000) + self.notification.show() + +# INITIALIZATION OF INDICATOR AND MENU + def __init__(self): + self.ind = appindicator.Indicator ("bumblebee-indicator", "bumblebee-indicator", appindicator.CATEGORY_HARDWARE) + self.ind.set_status (appindicator.STATUS_ACTIVE) +#TODO The icons style and accesibility must be enhanced : see icons/test directory + self.ind.set_icon("bumblebee-indicator.svg",'Bumblebee is unactive') + self.ind.set_attention_icon ("bumblebee-indicator-active.svg",'Bumblebee is active') + + self.card_state=False + self.lock_file = "/tmp/.X%s-lock" % Config.vgl_display + + self.build_menu() + + self.menu.show() + self.ind.set_menu(self.menu) + + def quit(self, widget, data=None): + gtk.main_quit() + + def build_menu(self): + self.menu = gtk.Menu() + self.switch = gtk.CheckMenuItem() + self.initial_state_checker() + self.switch.set_sensitive(False) + self.menu.append(self.switch) + + self.build_menu_separator(self.menu) + + self.prefered_app_submenu = gtk.MenuItem("Preferred Apps") + self.update_menu() + self.prefered_app_submenu.connect('activate', self.update_menu) + self.menu.append(self.prefered_app_submenu) + + item2 = gtk.MenuItem("Configure Apps") + item2.connect("activate", self.app_configure) + self.menu.append(item2) + +#TODO An UI to configure Bumblebee would be nice + + self.build_menu_separator(self.menu) + + quit = gtk.ImageMenuItem(gtk.STOCK_QUIT) + quit.connect("activate", self.quit) + self.menu.append(quit) + + self.menu.show_all() + + def build_menu_separator(self, menu): + separator = gtk.SeparatorMenuItem() + separator.show() + menu.append(separator) + +# FUNCTIONS TO BUILD THE "PREFERRED APP" MENU FROM THE LOCAL DESKTOP FILES + def update_menu(self, widget=None): + pref_menu=gtk.Menu() + self.add_submenu_items( pref_menu, Config.default_preferred_apps ) + self.build_menu_separator( pref_menu ) + self.add_submenu_items( pref_menu, DesktopFileSet().get_configured_from_check() ) + pref_menu.show() + self.prefered_app_submenu.set_submenu(pref_menu) + + def add_submenu_items(self, submenu, items_list): + for Name, Exec_list in items_list : + subitem = gtk.MenuItem(label=Name) + subitem.connect("activate", self.call_app, Exec_list) + subitem.show() + submenu.append( subitem ) + +# FUNCTIONS TO CHECK FOR THE STATE OF THE INDICATOR + def initial_state_checker(self): + if self.attention_state_condition(): self.set_attention_state(notify=False) + else : self.set_active_state(notify=False) + + def state_checker(self): + if self.attention_state_condition(): + if self.card_state == False : self.set_attention_state() + elif self.card_state == True: self.set_active_state() + return True + + def attention_state_condition(self): + if os.path.exists(self.lock_file): return True + else: return False + +# FUNCTIONS TO SET THE STATE OF THE INDICATOR AND LAUNCH NOTIFICATION + def set_attention_state(self, notify=True): + self.set_status(True, appindicator.STATUS_ATTENTION, + Config.attention_label, + Config.attention_comment, + "bumblebee-indicator-active", notify) + + def set_active_state(self, notify=True): + self.set_status(False, appindicator.STATUS_ACTIVE, + Config.active_label, + Config.active_comment, + "bumblebee-indicator", notify) + + def set_status(self, status, indicator, label, comment, icon, notify): + self.ind.set_status(indicator) + self.card_state = status + if notify == True: self.notify_state(label, comment, icon) + self.switch.set_label(label) + self.switch.set_active(status) + +# FUNCTION TO DEFINE THE APPLICATIONS SETTING LINK IN THE INDICATOR + + def app_configure(self,widget): + Applications_settings() + +# FUNCTION TO LAUNCH THE APPS WITHIN THE INDICATOR + def call_app(self, widget, app_exec): +#FIXME There is a problem when closing the launched app and when the indicator has been closed: the indicator is still running : What a daemon!! + subprocess.Popen(app_exec,shell=False) + +# MAIN LOOP LAUNCHING A STATE CHECK EVERY TWO SECONDS + def main(self): + self.state_checker() +#FIXME It would be nice to avoid this loop : Maybe by using a signal emitted by the system + #gtk.timeout_add(2000,self.state_checker) + gobject.timeout_add_seconds(2, self.state_checker) + gtk.main() + +if __name__ == "__main__": + indicator = BumblebeeIndicator() + indicator.main() + diff --git a/app/UNINSTALL b/app/UNINSTALL new file mode 100755 index 0000000..74a5bd0 --- /dev/null +++ b/app/UNINSTALL @@ -0,0 +1,31 @@ +### BEGIN LICENSE +# +# This file is part of bumblebee-ui. +# +# bumblebee-ui 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 3 of the License, or +# (at your option) any later version. +# +# bumblebee-ui 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 bumblebee-ui. If not, see . +# +### END LICENSE + +rm /usr/share/icons/hicolor/48x48/apps/bumblebee* +rm -R /usr/share/bumblebee-ui/ +rm /usr/share/applications/bumblebee-app-settings.desktop +rm /usr/share/applications/bumblebee-indicator.desktop +rm /usr/local/bin/bumblebee-app-settings +rm /usr/local/bin/bumblebee-indicator + +#TO DO MANUALLY +#remove bumblebee-indicator at startup +# +# +# From 5484764edeb9efe52ebecabac70f63d4b705ba26 Mon Sep 17 00:00:00 2001 From: jscurtu Date: Sun, 30 Aug 2015 19:59:34 +0200 Subject: [PATCH 16/17] Update UNINSTALL --- app/UNINSTALL | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/UNINSTALL b/app/UNINSTALL index 74a5bd0..fae3867 100755 --- a/app/UNINSTALL +++ b/app/UNINSTALL @@ -17,7 +17,7 @@ # ### END LICENSE -rm /usr/share/icons/hicolor/48x48/apps/bumblebee* +rm /usr/share/icons/bumblebee* rm -R /usr/share/bumblebee-ui/ rm /usr/share/applications/bumblebee-app-settings.desktop rm /usr/share/applications/bumblebee-indicator.desktop From 7c99456ff5d9c622f8e9caa0d6e33bf68c2da247 Mon Sep 17 00:00:00 2001 From: jscurtu Date: Sun, 30 Aug 2015 20:00:28 +0200 Subject: [PATCH 17/17] Update INSTALL --- INSTALL | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/INSTALL b/INSTALL index e184b5d..bdc6ed2 100755 --- a/INSTALL +++ b/INSTALL @@ -17,7 +17,7 @@ # ### END LICENSE -cp icons/*.* /usr/share/icons/hicolor/48x48/apps/ +cp icons/*.* /usr/share/icons/ mkdir /usr/share/bumblebee-ui/ cp app/*.* /usr/share/bumblebee-ui/ cp bumblebee-app-settings.desktop /usr/share/applications/