def switchFavoritesView(self, tree): """ Show all/favorites """ self.saveTreeState() self.showOnlyFavs = not self.showOnlyFavs prefs.set(__name__, 'show-only-favorites', self.showOnlyFavs) self.loadArtists(self.tree, self.currLib) self.restoreTreeState()
def load(name): """ Load the given module, may raise LoadException """ mModulesLock.acquire() module = mModules[name] mModulesLock.release() # Check dependencies unmetDeps = __checkDeps(module[MOD_INFO][MODINFO_DEPS]) if len(unmetDeps) != 0: errMsg = _('The following Python modules are not available:') errMsg += '\n * ' errMsg += '\n * '.join(unmetDeps) errMsg += '\n\n' errMsg += _('You must install them if you want to enable this module.') raise LoadException(errMsg) # Instantiate the module try: module[MOD_INSTANCE] = getattr(module[MOD_PMODULE], module[MOD_CLASSNAME])() module[MOD_INSTANCE].start() mHandlersLock.acquire() if module[MOD_INSTANCE] in mHandlers[consts.MSG_EVT_MOD_LOADED]: module[MOD_INSTANCE].postMsg(consts.MSG_EVT_MOD_LOADED) mHandlersLock.release() log.logger.info('Module loaded: %s' % module[MOD_CLASSNAME]) mEnabledModules.append(name) prefs.set(__name__, 'enabled_modules', mEnabledModules) except: raise LoadException(traceback.format_exc())
def timerFunc(self): """ Move a bit the scales to their target value """ isFinished = True # Disconnect handlers before moving the scales for i in xrange(10): self.scales[i].disconnect(self.handlers[i]) # Move the scales a bit for i in xrange(10): currLvl = self.scales[i].get_value() targetLvl = self.targetLvls[i] difference = targetLvl - currLvl if abs(difference) <= 0.25: newLvl = targetLvl else: newLvl = currLvl + (difference / 8.0) isFinished = False self.lvls[i] = newLvl self.scales[i].set_value(newLvl) # Reconnect the handlers for i in xrange(10): self.handlers[i] = self.scales[i].connect('value-changed', self.onScaleValueChanged, i) # Set the equalizer to the new levels prefs.set(__name__, 'levels', self.lvls) modules.postMsg(consts.MSG_CMD_SET_EQZ_LVLS, {'lvls': self.lvls}) return not isFinished
def load_enabled_modules(): # Find modules, instantiate those that are mandatory or that have been previously enabled by the user sys.path.append(mModDir) for file in sorted(os.path.splitext(file)[0] for file in os.listdir(mModDir) if file.endswith('.py') and file not in blacklist): try: pModule = __import__(file) modInfo = getattr(pModule, 'MOD_INFO') # Should it be instanciated? instance = None if modInfo[MODINFO_MANDATORY] or modInfo[MODINFO_NAME] in mEnabledModules: if len(__checkDeps(modInfo[MODINFO_DEPS])) == 0: instance = getattr(pModule, file)() instance.start() log.logger.info('Module loaded: %s' % file) else: log.logger.error('Unable to load module %s because of missing dependencies' % file) # Add it to the dictionary mModules[modInfo[MODINFO_NAME]] = [pModule, file, instance, modInfo] except: log.logger.error('Unable to load module %s\n\n%s' % (file, traceback.format_exc())) # Remove enabled modules that are no longer available mEnabledModules[:] = [module for module in mEnabledModules if module in mModules] prefs.set(__name__, 'enabled_modules', mEnabledModules)
def delayedStartup(): """ Perform all the initialization stuff that is not mandatory to display the window This function should be called within the GTK main loop, once the window has been displayed """ import atexit, dbus.mainloop.glib, modules, signal def atExit(): """ Final function, called just before exiting the Python interpreter """ prefs.save() log.logger.info('Stopped') def onInterrupt(window): """ Handler for interrupt signals e.g., Ctrl-C """ window.hide() modules.postQuitMsg() # D-Bus dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) # Register a few handlers atexit.register(atExit) signal.signal(signal.SIGINT, lambda sig, frame: onInterrupt(window)) signal.signal(signal.SIGTERM, lambda sig, frame: onInterrupt(window)) # Now we can start all modules gobject.idle_add(modules.postMsg, consts.MSG_EVT_APP_STARTED) # Immediately show the preferences the first time the application is started if prefs.get(__name__, 'first-time', True): prefs.set(__name__, 'first-time', False) gobject.idle_add(modules.showPreferences)
def load(name): """ Load the given module, may raise LoadException """ mModulesLock.acquire() module = mModules[name] mModulesLock.release() # Check dependencies unmetDeps = __checkDeps(module[MOD_INFO][MODINFO_DEPS]) if len(unmetDeps) != 0: errMsg = _('The following Python modules are not available:') errMsg += '\n * ' errMsg += '\n * '.join(unmetDeps) errMsg += '\n\n' errMsg += _('You must install them if you want to enable this module.') raise LoadException, errMsg # Instantiate the module try: module[MOD_INSTANCE] = getattr(module[MOD_PMODULE], module[MOD_CLASSNAME])() module[MOD_INSTANCE].start() mHandlersLock.acquire() if module[MOD_INSTANCE] in mHandlers[consts.MSG_EVT_MOD_LOADED]: module[MOD_INSTANCE].postMsg(consts.MSG_EVT_MOD_LOADED) mHandlersLock.release() log.logger.info('Module loaded: %s' % module[MOD_CLASSNAME]) mEnabledModules.append(name) prefs.set(__name__, 'enabled_modules', mEnabledModules) except: raise LoadException, traceback.format_exc()
def onModUnloaded(self): """ The module is being unloaded """ prefs.set(__name__, 'was-paused', self.paused) prefs.set(__name__, 'was-playing', self.playing) prefs.set(__name__, 'position', self.currPos) prefs.set(__name__, 'track', self.currTrack) prefs.set(__name__, 'tracklist', self.currTracklist)
def setViewMode(self, mode): """ Change the view mode to the given one """ currMode = prefs.get(__name__, 'view-mode', DEFAULT_VIEW_MODE) # Give up if the new mode is the same as the current one if currMode == mode: return requestedSize = self.window.get_size() # First restore the initial window state (e.g., VIEW_MODE_FULL) if currMode == consts.VIEW_MODE_LEAN: requestedSize = self.__fromModeLean(requestedSize) elif currMode == consts.VIEW_MODE_MINI: requestedSize = self.__fromModeMini(requestedSize) elif currMode == consts.VIEW_MODE_NETBOOK: requestedSize = self.__fromModeNetbook(requestedSize) elif currMode == consts.VIEW_MODE_PLAYLIST: requestedSize = self.__fromModePlaylist(requestedSize) # Now we can switch to the new mode if mode == consts.VIEW_MODE_LEAN: requestedSize = self.__toModeLean(requestedSize) elif mode == consts.VIEW_MODE_MINI: requestedSize = self.__toModeMini(requestedSize) elif mode == consts.VIEW_MODE_NETBOOK: requestedSize = self.__toModeNetbook(requestedSize) elif mode == consts.VIEW_MODE_PLAYLIST: requestedSize = self.__toModePlaylist(requestedSize) # Do only one resize(), because intermediate get_size() don't return the correct size until the event queue has been processed by GTK self.window.resize(requestedSize[0], requestedSize[1]) # Save the new mode prefs.set(__name__, 'view-mode', mode)
def timerFunc(self): """ Move a bit the scales to their target value """ isFinished = True # Move the scales a bit for i in xrange(10): currLvl = self.scales[i].get_value() targetLvl = self.targetLvls[i] difference = targetLvl - currLvl if abs(difference) <= 0.25: newLvl = targetLvl else: newLvl = currLvl + (difference / 8.0) isFinished = False self.lvls[i] = newLvl self.scales[i].set_value(newLvl) # Set the equalizer to the new levels modules.postMsg(consts.MSG_CMD_SET_EQZ_LVLS, {'lvls': self.lvls}) if isFinished: self.timer = None prefs.set(__name__, 'levels', self.lvls) # Make sure labels are up to date (sometimes they aren't when we're done with the animation) # Also unblock the handlers for i in xrange(10): self.scales[i].queue_draw() self.scales[i].handler_unblock_by_func(self.onScaleValueChanged) return False return True
def handleMsg(self, msg, params): """ Handle messages sent to this module """ if msg == consts.MSG_EVT_APP_STARTED or msg == consts.MSG_EVT_MOD_LOADED: self.onAppStarted() idle_add(self.addAllExplorers) elif msg == consts.MSG_EVT_EXPLORER_CHANGED and params['modName'] == MOD_L10N and params['expName'] != self.currLib: # Create the tree if needed if self.tree is None: self.__createTree() # Save the state of the current library if self.currLib is not None: self.treeState[self.currLib] = self.tree.saveState(ROW_NAME) # Switch to the new one self.currLib = params['expName'] self.loadLibrary(self.tree, self.currLib) # Restore the state of the new library if len(self.tree) != 0 and self.currLib in self.treeState: self.tree.restoreState(self.treeState[self.currLib], ROW_NAME) elif msg == consts.MSG_EVT_APP_QUIT or msg == consts.MSG_EVT_MOD_UNLOADED: if self.currLib is not None: self.treeState[self.currLib] = self.tree.saveState(ROW_NAME) prefs.set(__name__, 'tree-state', self.treeState) prefs.set(__name__, 'libraries', self.libraries) self.removeAllExplorers()
def onModUnloaded(self): """ The module has been unloaded """ if self.currLib is not None: self.saveTreeState() self.saveFavorites(self.currLib, self.favorites) prefs.set(__name__, 'tree-states-2', self.treeStates) prefs.set(__name__, 'libraries', self.libraries) self.removeAllExplorers()
def handleMsg(self, msg, params): """ Handle messages sent to this module """ if msg == consts.MSG_EVT_EXPLORER_CHANGED and params['modName'] == MOD_L10N and self.currRoot != params['expName']: newRoot = params['expName'] # Create the tree if needed (this is done only the very first time) if self.tree is None: columns = (('', [(gtk.CellRendererPixbuf(), gtk.gdk.Pixbuf), (gtk.CellRendererText(), TYPE_STRING)], True), (None, [(None, TYPE_INT)], False), (None, [(None, TYPE_STRING)], False)) self.tree = extTreeview.ExtTreeView(columns, True) self.scrolled.add(self.tree) self.tree.setDNDSources([consts.DND_TARGETS[consts.DND_DAP_URI]]) self.tree.connect('drag-data-get', self.onDragDataGet) self.tree.connect('key-press-event', self.onKeyPressed) self.tree.connect('exttreeview-button-pressed', self.onMouseButton) self.tree.connect('exttreeview-row-collapsed', self.onRowCollapsed) self.expandedHandler = self.tree.connect('exttreeview-row-expanded', self.onRowExpanded) savedStates = prefs.get(__name__, 'saved-states', {}) # Save the current state if needed if self.currRoot is not None: savedStates[self.currRoot] = { 'tree-state': self.dumpTree(), 'selected-paths': self.tree.getSelectedPaths(), 'vscrollbar-pos': self.scrolled.get_vscrollbar().get_value(), 'hscrollbar-pos': self.scrolled.get_hscrollbar().get_value(), } prefs.set(__name__, 'saved-states', savedStates) self.tree.clear() self.currRoot = newRoot if newRoot not in savedStates: self.exploreDir(None, self.folders[self.currRoot]) if len(self.tree) != 0: self.tree.scroll_to_cell(0) else: savedState = savedStates[newRoot] self.tree.disconnect(self.expandedHandler) self.restoreTree(savedState['tree-state']) self.expandedHandler = self.tree.connect('exttreeview-row-expanded', self.onRowExpanded) idle_add(self.scrolled.get_vscrollbar().set_value, savedState['vscrollbar-pos']) idle_add(self.scrolled.get_hscrollbar().set_value, savedState['hscrollbar-pos']) idle_add(self.tree.selectPaths, savedState['selected-paths']) idle_add(self.refresh) elif msg == consts.MSG_EVT_APP_STARTED: self.onModLoaded() elif msg == consts.MSG_EVT_APP_QUIT: self.onModUnloaded()
def saveTreeState(self): """ Create a dictionary representing the current state of the tree """ self.treeState = { 'tree-state': self.getTreeDump(), 'selected-paths': self.tree.getSelectedPaths(), 'vscrollbar-pos': self.scrolled.get_vscrollbar().get_value(), 'hscrollbar-pos': self.scrolled.get_hscrollbar().get_value(), } prefs.set(__name__, 'saved-states', self.treeState) self.music_paths = self.get_music_paths_from_tree()
def handleMsg(self, msg, params): """ Handle message sent to this module """ if msg == consts.MSG_EVT_TRACK_POSITION: self.onNewTrackPosition(params['seconds']) elif msg == consts.MSG_EVT_PAUSED: self.onPaused() elif msg == consts.MSG_EVT_STOPPED: self.onStopped() elif msg == consts.MSG_EVT_UNPAUSED: self.onUnpaused() elif msg == consts.MSG_EVT_APP_QUIT: prefs.set(__name__, 'volume', self.btnVolume.get_value()) elif msg == consts.MSG_EVT_NEW_TRACK: self.onNewTrack(params['track']) elif msg == consts.MSG_EVT_APP_STARTED: self.onAppStarted() elif msg == consts.MSG_EVT_TRACK_MOVED: self.onTrackMoved(params['hasPrevious'], params['hasNext']) elif msg == consts.MSG_EVT_NEW_TRACKLIST: self.btnPlay.set_sensitive(len(params['tracks']) != 0) elif msg == consts.MSG_EVT_VOLUME_CHANGED: self.onVolumeChanged(params['value'])
def renameFolder(self, oldName, newName): """ Rename a folder """ self.folders[newName] = self.folders[oldName] del self.folders[oldName] savedStates = prefs.get(__name__, 'saved-states', {}) if oldName in savedStates: savedStates[newName] = savedStates[oldName] del savedStates[oldName] prefs.set(__name__, 'saved-states', savedStates) modules.postMsg(consts.MSG_CMD_EXPLORER_RENAME, {'modName': MOD_L10N, 'expName': oldName, 'newExpName': newName})
def __init__(self, wtree, window): """ Constructor """ self.wtree = wtree self.paned = wtree.get_object('pan-main') self.window = window # Enable the right radio menu button viewmode = prefs.get(__name__, 'view-mode', DEFAULT_VIEW_MODE) if viewmode == consts.VIEW_MODE_FULL: self.wtree.get_object('menu-mode-full').set_active(True) elif viewmode == consts.VIEW_MODE_LEAN: self.wtree.get_object('menu-mode-lean').set_active(True) elif viewmode == consts.VIEW_MODE_MINI: self.wtree.get_object('menu-mode-mini').set_active(True) elif viewmode == consts.VIEW_MODE_NETBOOK: self.wtree.get_object('menu-mode-netbook').set_active(True) elif viewmode == consts.VIEW_MODE_PLAYLIST: self.wtree.get_object('menu-mode-playlist').set_active(True) # Restore the size and the state of the window if prefs.get(__name__, 'win-is-maximized', DEFAULT_MAXIMIZED_STATE): self.window.maximize() savedWidth = prefs.get(__name__, 'win-width', DEFAULT_WIN_WIDTH) savedHeight = prefs.get(__name__, 'win-height', DEFAULT_WIN_HEIGHT) savedPanPos = prefs.get(__name__, 'paned-pos', DEFAULT_PANED_POS) self.window.resize(savedWidth, savedHeight) self.paned.set_position(savedPanPos) self.window.show_all() # Restore the view mode # We set the mode to VIEW_MODE_FULL in the preferences because the window is currently in this mode (initial startup state) prefs.set(__name__, 'view-mode', consts.VIEW_MODE_FULL) self.setViewMode(viewmode) # Restore once again the size (may have been modified while restoring the view mode) self.window.resize(savedWidth, savedHeight) self.paned.set_position(savedPanPos) # Finally connect the event handlers self.window.connect('delete-event', self.onDelete) self.window.connect('size-allocate', self.onResize) self.window.connect('window-state-event', self.onState) self.wtree.get_object('menu-mode-mini').connect('activate', self.onViewMode, consts.VIEW_MODE_MINI) self.wtree.get_object('menu-mode-full').connect('activate', self.onViewMode, consts.VIEW_MODE_FULL) self.wtree.get_object('menu-mode-lean').connect('activate', self.onViewMode, consts.VIEW_MODE_LEAN) self.wtree.get_object('menu-mode-netbook').connect('activate', self.onViewMode, consts.VIEW_MODE_NETBOOK) self.wtree.get_object('menu-mode-playlist').connect('activate', self.onViewMode, consts.VIEW_MODE_PLAYLIST) self.wtree.get_object('menu-help').connect('activate', self.onHelp) self.wtree.get_object('menu-about').connect('activate', self.onAbout) self.wtree.get_object('menu-preferences').connect('activate', self.onShowPreferences) self.wtree.get_object('menu-quit').connect('activate', lambda item: self.onDelete(window, None)) self.wtree.get_object('pan-main').connect('size-allocate', lambda win, rect: prefs.set(__name__, 'paned-pos', self.paned.get_position()))
def save_track_tree(self): # Save playing track if self.tree.hasMark(): last_path = tuple(self.tree.mark.get_path()) else: last_path = None prefs.set(__name__, 'last-played-track', last_path) dump = self.getTreeDump() logging.info('Saving playlist') pickleSave(self.savedPlaylist, dump) # tell gobject to keep saving the content in regular intervals return True
def onChanged(self, combo): """ A new explorer has been selected with the combo box """ idx = combo.get_active() if idx == -1: self.notebook.set_current_page(0) elif self.store[idx][ROW_IS_HEADER]: combo.set_active(self.currExplorerIdx) else: self.currExplorerIdx = idx prefs.set(__name__, 'last-explorer', (self.store[idx][ROW_MODULE], self.store[idx][ROW_NAME])) modules.postMsg(consts.MSG_EVT_EXPLORER_CHANGED, {'modName': self.store[idx][ROW_MODULE], 'expName': self.store[idx][ROW_NAME]}) self.notebook.set_current_page(self.store[idx][ROW_PAGE_NUM])
def save_track_tree(self): # Save playing track if self.tree.hasMark(): last_path = self.tree.mark.get_path() else: last_path = None prefs.set(__name__, 'last-played-track', last_path) dump = self.getTreeDump() logging.info('Saving playlist') pickleSave(self.savedPlaylist, dump) # tell gobject to keep saving the content in regular intervals return True
def onBtnOk(self, btn): """ Save new preferences """ # Skipping tracks newSkipTrack = self.cfgWin.getWidget('chk-skipTrack').get_active() oldSkipTrack = prefs.get(__name__, 'skip-track', PREFS_DEFAULT_SKIP_TRACK) prefs.set(__name__, 'skip-track', newSkipTrack) if oldSkipTrack != newSkipTrack and self.notif is not None: if newSkipTrack: self.notif.add_action('stop', _('Skip track'), self.onSkipTrack) else: self.notif.clear_actions() # Timeout newTimeout = int(self.cfgWin.getWidget('spn-duration').get_value()) oldTimeout = prefs.get(__name__, 'timeout', PREFS_DEFAULT_TIMEOUT) prefs.set(__name__, 'timeout', newTimeout) if oldTimeout != newTimeout and self.notif is not None: self.notif.set_timeout(newTimeout * 1000) # Other preferences prefs.set(__name__, 'title', self.cfgWin.getWidget('txt-title').get_text()) (start, end) = self.cfgWin.getWidget('txt-body').get_buffer().get_bounds() prefs.set( __name__, 'body', self.cfgWin.getWidget('txt-body').get_buffer().get_text( start, end, False)) self.cfgWin.hide()
def onBtnOk(self, btn): """ Save new preferences """ # Skipping tracks newSkipTrack = self.cfgWin.getWidget('chk-skipTrack').get_active() oldSkipTrack = prefs.get(__name__, 'skip-track', PREFS_DEFAULT_SKIP_TRACK) prefs.set(__name__, 'skip-track', newSkipTrack) if oldSkipTrack != newSkipTrack and self.notif is not None: if newSkipTrack: self.notif.add_action('stop', _('Skip track'), self.onSkipTrack) else: self.notif.clear_actions() # Timeout newTimeout = int(self.cfgWin.getWidget('spn-duration').get_value()) oldTimeout = prefs.get(__name__, 'timeout', PREFS_DEFAULT_TIMEOUT) prefs.set(__name__, 'timeout', newTimeout) if oldTimeout != newTimeout and self.notif is not None: self.notif.set_timeout(newTimeout * 1000) # Other preferences prefs.set(__name__, 'title', self.cfgWin.getWidget('txt-title').get_text()) (start, end) = self.cfgWin.getWidget('txt-body').get_buffer().get_bounds() prefs.set(__name__, 'body', self.cfgWin.getWidget('txt-body').get_buffer().get_text(start, end)) self.cfgWin.hide()
def onOk(self, btn): """ Save the new preferences """ if not os.path.isdir(os.path.dirname(self.txtFile.get_text())): gui.errorMsgBox( self.cfgWindow, _("Invalid path"), _("The path to the selected file is not valid. Please choose an existing path."), ) self.txtFile.grab_focus() else: prefs.set(__name__, "file", self.txtFile.get_text()) (start, end) = self.txtStatus.get_buffer().get_bounds() prefs.set(__name__, "status", self.txtStatus.get_buffer().get_text(start, end)) self.cfgWindow.hide()
def onRenameExplorer(self, modName, expName, newExpName): """ Rename the given explorer """ if newExpName != expName: self.allExplorers[(modName, newExpName)] = self.allExplorers[(modName, expName)] del self.allExplorers[(modName, expName)] # If the explorer we're renaming is currently selected, we need to rename the row # Otherwise, fillComboBox() won't be able to keep it selected idx = self.combo.get_active() if idx != -1 and self.store[idx][ROW_MODULE] == modName and self.store[idx][ROW_NAME] == expName: self.store[idx][ROW_NAME] = newExpName prefs.set(__name__, 'last-explorer', (modName, newExpName)) self.fillComboBox()
def onAppQuit(self): """ The module is going to be unloaded """ self.saveTreeState() prefs.set(__name__, 'saved-states', self.treeState) prefs.set(__name__, 'media-folders', self.folders) prefs.set(__name__, 'add-by-filename', self.addByFilename) prefs.set(__name__, 'show-hidden-files', self.showHiddenFiles)
def onScaleValueChanged(self, scale, idx): """ The user has moved one of the scales """ # Add a 'custom' entry to the presets if needed if self.preset is not None: self.preset = None prefs.set(__name__, 'preset', self.preset) self.combo.handler_block_by_func(self.onPresetChanged) self.comboStore.insert(0, (False, _('Custom'), None)) self.comboStore.insert(1, (True, '', None)) self.combo.set_active(0) self.combo.handler_unblock_by_func(self.onPresetChanged) self.lvls[idx] = scale.get_value() prefs.set(__name__, 'levels', self.lvls) modules.postMsg(consts.MSG_CMD_SET_EQZ_LVLS, {'lvls': self.lvls})
def onPresetChanged(self, combo): """ A preset has been selected """ idx = combo.get_active() if idx != -1: iter = self.comboStore.get_iter(idx) preset = self.comboStore.get_value(iter, ROW_PRESET_NAME) self.jumpToTargetLvls(self.comboStore.get_value(iter, ROW_PRESET_VALUES)) # Remove the 'Custom' entry if needed if self.preset is None: self.comboStore.remove(self.comboStore.get_iter((0, ))) self.comboStore.remove(self.comboStore.get_iter((0, ))) self.preset = preset prefs.set(__name__, 'preset', self.preset)
def onPresetChanged(self, combo): """ A preset has been selected """ idx = combo.get_active() if idx != -1: iter = self.comboStore.get_iter(idx) preset = self.comboStore.get_value(iter, ROW_PRESET_NAME) self.jumpToTargetLvls( self.comboStore.get_value(iter, ROW_PRESET_VALUES)) # Remove the 'Custom' entry if needed if self.preset is None: self.comboStore.remove(self.comboStore.get_iter((0, ))) self.comboStore.remove(self.comboStore.get_iter((0, ))) self.preset = preset prefs.set(__name__, 'preset', self.preset)
def onBtnOk(self, btn): """ The button 'Ok' has been pressed """ self.enabled = self.cfgWin.getWidget('chk-enabled').get_active() self.periodicity = int(self.cfgWin.getWidget('slider-periodicity').get_value()) prefs.set(__name__, 'enabled', self.enabled) prefs.set(__name__, 'periodicity', self.periodicity) # Restart timer, periodicity may have changed if self.timer is not None: gobject.source_remove(self.timer) if self.enabled: self.timer = gobject.timeout_add_seconds(self.periodicity * 60, self.timerFunc) self.cfgWin.hide()
def unload(name): """ Unload the given module """ mModulesLock.acquire() module = mModules[name] instance = module[MOD_INSTANCE] module[MOD_INSTANCE] = None mModulesLock.release() if instance is not None: mHandlersLock.acquire() instance.postMsg(consts.MSG_EVT_MOD_UNLOADED) for handlers in [handler for handler in mHandlers.itervalues() if instance in handler]: handlers.remove(instance) mHandlersLock.release() mEnabledModules.remove(name) log.logger.info('Module unloaded: %s' % module[MOD_CLASSNAME]) prefs.set(__name__, 'enabled_modules', mEnabledModules)
def onBtnOpen(self, btn): """ Load the levels from a file""" inFile = gui.fileChooser.openFile(self.cfgWindow, _('Load levels')) if inFile is not None: input = open(inFile, 'rt') lines = input.readlines() input.close() lvls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] isInvalid = True if len(lines) == 10: isInvalid = False for i in range(10): elts = lines[i].split() try: if len(elts) == 1: lvls[i] = float(elts[0]) if lvls[i] >= -24 and lvls[i] <= 12: continue except: pass isInvalid = True break if isInvalid: gui.errorMsgBox(self.cfgWindow, _('Could not load the file'), _('The format of the file is incorrect.')) else: self.jumpToTargetLvls(lvls) # Add a 'custom' entry to the presets if needed if self.preset is not None: self.preset = None prefs.set(__name__, 'preset', self.preset) self.combo.handler_block_by_func(self.onPresetChanged) self.comboStore.insert(0, (False, _('Custom'), None)) self.comboStore.insert(1, (True, '', None)) self.combo.set_active(0) self.combo.handler_unblock_by_func(self.onPresetChanged)
def setViewMode(mode, resize): """ Change the view mode to the given one """ lastMode = prefs.get(__name__, 'view-mode', DEFAULT_VIEW_MODE) prefs.set(__name__, 'view-mode', mode) (winWidth, winHeight) = window.get_size() if mode == consts.VIEW_MODE_FULL: paned.get_child1().show() wTree.get_widget('statusbar').show() wTree.get_widget('box-btn-tracklist').show() wTree.get_widget('scrolled-tracklist').show() wTree.get_widget('box-trkinfo').show() if resize: if lastMode != consts.VIEW_MODE_FULL: winWidth = winWidth + paned.get_position() if lastMode == consts.VIEW_MODE_MINI: winHeight = prefs.get(__name__, 'full-win-height', DEFAULT_WIN_HEIGHT) window.resize(winWidth, winHeight) return paned.get_child1().hide() if resize and lastMode == consts.VIEW_MODE_FULL: winWidth = winWidth - paned.get_position() window.resize(winWidth, winHeight) if mode == consts.VIEW_MODE_PLAYLIST: wTree.get_widget('statusbar').show() wTree.get_widget('box-btn-tracklist').hide() wTree.get_widget('scrolled-tracklist').show() wTree.get_widget('box-trkinfo').show() if resize and lastMode == consts.VIEW_MODE_MINI: window.resize(winWidth, prefs.get(__name__, 'full-win-height', DEFAULT_WIN_HEIGHT)) return wTree.get_widget('statusbar').hide() wTree.get_widget('box-btn-tracklist').hide() wTree.get_widget('scrolled-tracklist').hide() if mode == consts.VIEW_MODE_MINI: wTree.get_widget('box-trkinfo').show() else: wTree.get_widget('box-trkinfo').hide() if resize: window.resize(winWidth, 1)
def onBtnOpen(self, btn): """ Load the levels from a file""" inFile = gui.fileChooser.openFile(self.cfgWindow, _('Load levels')) if inFile is not None: input = open(inFile, 'rt') lines = input.readlines() input.close() lvls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] isInvalid = True if len(lines) == 10: isInvalid = False for i in xrange(10): elts = lines[i].split() try: if len(elts) == 1: lvls[i] = float(elts[0]) if lvls[i] >= -24 and lvls[i] <= 12: continue except: pass isInvalid = True break if isInvalid: gui.errorMsgBox(self.cfgWindow, _('Could not load the file'), _('The format of the file is incorrect.')) else: self.jumpToTargetLvls(lvls) # Add a 'custom' entry to the presets if needed if self.preset is not None: self.preset = None prefs.set(__name__, 'preset', self.preset) self.combo.handler_block_by_func(self.onPresetChanged) self.comboStore.insert(0, (False, _('Custom'), None)) self.comboStore.insert(1, (True, '', None)) self.combo.set_active(0) self.combo.handler_unblock_by_func(self.onPresetChanged)
def onChanged(self, combo): """ A new explorer has been selected with the combo box """ currExplorer = self.combo.get_active() if currExplorer == -1: self.notebook.set_current_page(0) else: modName, expName, isHeader = self.store.get(self.store.get_iter(currExplorer), ROW_MODULE, ROW_NAME, ROW_IS_HEADER) if isHeader: if self.currExplorer is not None: self.combo.set_active(self.currExplorer) else: if self.currExplorer != currExplorer: self.currExplorer = currExplorer prefs.set(__name__, 'last-explorer', (modName, expName)) modules.postMsg(consts.MSG_EVT_EXPLORER_CHANGED, {'modName': modName, 'expName': expName}) (pixbuf, widget) = self.explorers[modName][expName] self.notebook.set_current_page(self.widgets[widget])
def realStartup(): """ Perform all the initialization stuff which is not mandatory to display the window This function should be called within the GTK main loop, once the window has been displayed """ import atexit, dbus.mainloop.glib, gui.about, modules, webbrowser def onDelete(win, event): """ Use our own quit sequence, that will itself destroy the window """ window.hide() modules.postQuitMsg() return True def onResize(win, rect): """ Save the new size of the window """ if win.window is not None and not win.window.get_state() & gtk.gdk.WINDOW_STATE_MAXIMIZED: prefs.set(__name__, 'win-width', rect.width) prefs.set(__name__, 'win-height', rect.height) if prefs.get(__name__, 'view-mode', DEFAULT_VIEW_MODE)in (consts.VIEW_MODE_FULL, consts.VIEW_MODE_PLAYLIST): prefs.set(__name__, 'full-win-height', rect.height) def onState(win, evt): """ Save the new state of the window """ prefs.set(__name__, 'win-is-maximized', bool(evt.new_window_state & gtk.gdk.WINDOW_STATE_MAXIMIZED)) def atExit(): """ Final function, called just before exiting the Python interpreter """ prefs.save() log.logger.info('Stopped') # D-Bus dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) # Make sure to perform a few actions before exiting the Python interpreter atexit.register(atExit) signal.signal(signal.SIGTERM, lambda sig, frame: onDelete(window, None)) # GTK handlers window.connect('delete-event', onDelete) window.connect('size-allocate', onResize) window.connect('window-state-event', onState) paned.connect('size-allocate', lambda win, rect: prefs.set(__name__, 'paned-pos', paned.get_position())) wTree.get_widget('menu-mode-mini').connect('activate', onViewMode, consts.VIEW_MODE_MINI) wTree.get_widget('menu-mode-full').connect('activate', onViewMode, consts.VIEW_MODE_FULL) wTree.get_widget('menu-mode-playlist').connect('activate', onViewMode, consts.VIEW_MODE_PLAYLIST) wTree.get_widget('menu-quit').connect('activate', lambda item: onDelete(window, None)) wTree.get_widget('menu-about').connect('activate', lambda item: gui.about.show(window)) wTree.get_widget('menu-help').connect('activate', lambda item: webbrowser.open(consts.urlHelp)) wTree.get_widget('menu-preferences').connect('activate', lambda item: modules.showPreferences()) # Let's go modules.postMsg(consts.MSG_EVT_APP_STARTED)
def unload(name): """ Unload the given module """ mModulesLock.acquire() module = mModules[name] instance = module[MOD_INSTANCE] module[MOD_INSTANCE] = None mModulesLock.release() if instance is not None: mHandlersLock.acquire() instance.postMsg(consts.MSG_EVT_MOD_UNLOADED) for handlers in [ handler for handler in mHandlers.values() if instance in handler ]: handlers.remove(instance) mHandlersLock.release() mEnabledModules.remove(name) log.logger.info('Module unloaded: %s' % module[MOD_CLASSNAME]) prefs.set(__name__, 'enabled_modules', mEnabledModules)
def __storeAuthInfo(id, login, passwd): """ Store the login/password associated with id, either in the Gnome keyring or in the prefs """ try: import gnomekeyring as gk useGK = True except: useGK = False # No Gnome keyring if not useGK: prefs.set(__name__, id + '_login', login) prefs.set(__name__, id + '_passwd', b64encode(passwd)) # Pretty useless, but the user prefers not to see his password as clear text return # From here we can use the Gnome keyring __loadKeyring() try: label = '%s (%s)' % (consts.appName, id) authInfo = '\n'.join((login, passwd)) token = gk.item_create_sync(__keyring, gk.ITEM_GENERIC_SECRET, label, {'appName': consts.appName, 'id': id}, authInfo, True) prefs.set(__name__, id + '_gkToken', token) except: pass
def timerFunc(self): """ Move a bit the scales to their target value """ isFinished = True # Move the scales a bit for i in range(10): currLvl = self.scales[i].get_value() targetLvl = self.targetLvls[i] difference = targetLvl - currLvl if abs(difference) <= 0.25: newLvl = targetLvl else: newLvl = currLvl + (difference / 8.0) isFinished = False self.lvls[i] = newLvl self.scales[i].set_value(newLvl) # Set the equalizer to the new levels modules.postMsg(consts.MSG_CMD_SET_EQZ_LVLS, {'lvls': self.lvls}) if isFinished: self.timer = None prefs.set(__name__, 'levels', self.lvls) # Make sure labels are up to date (sometimes they aren't when we're done with the animation) # Also unblock the handlers for i in range(10): self.scales[i].queue_draw() self.scales[i].handler_unblock_by_func( self.onScaleValueChanged) return False return True
def load_enabled_modules(): # Find modules, instantiate those that are mandatory or that have been previously enabled by the user sys.path.append(mModDir) for file in sorted( os.path.splitext(file)[0] for file in os.listdir(mModDir) if file.endswith('.py') and file not in blacklist): try: pModule = __import__(file) modInfo = getattr(pModule, 'MOD_INFO') # Should it be instantiated? instance = None if modInfo[MODINFO_MANDATORY] or modInfo[ MODINFO_NAME] in mEnabledModules: if len(__checkDeps(modInfo[MODINFO_DEPS])) == 0: log.logger.info('Loading module: %s' % file) instance = getattr(pModule, file)() instance.start() else: log.logger.error( 'Unable to load module %s because of missing dependencies' % file) # Add it to the dictionary mModules[modInfo[MODINFO_NAME]] = [ pModule, file, instance, modInfo ] except: log.logger.error('Unable to load module %s\n\n%s' % (file, traceback.format_exc())) # Remove enabled modules that are no longer available mEnabledModules[:] = [ module for module in mEnabledModules if module in mModules ] prefs.set(__name__, 'enabled_modules', mEnabledModules)
def onResize(win, rect): """ Save the new size of the window """ maximized = win.get_state() & Gdk.WindowState.MAXIMIZED if not maximized: prefs.set(__name__, 'win-width', rect.width) prefs.set(__name__, 'win-height', rect.height) view_mode = prefs.get(__name__, 'view-mode', DEFAULT_VIEW_MODE) if view_mode in (consts.VIEW_MODE_FULL, consts.VIEW_MODE_PLAYLIST): prefs.set(__name__, 'full-win-height', rect.height)
def onBtnOk(self, btn): """ Save configuration """ downloadCovers = self.cfgWin.getWidget( 'chk-downloadCovers').get_active() preferUserCovers = self.cfgWin.getWidget( 'chk-preferUserCovers').get_active() userCoverFilenames = [ word.strip() for word in self.cfgWin.getWidget( 'txt-filenames').get_text().split(',') ] prefs.set(__name__, 'download-covers', downloadCovers) prefs.set(__name__, 'prefer-user-covers', preferUserCovers) prefs.set(__name__, 'user-cover-filenames', userCoverFilenames) self.cfgWin.hide()
def onState(win, event): """ Save the new state of the window """ if event.changed_mask & Gdk.WindowState.MAXIMIZED: maximized = bool(event.new_window_state & Gdk.WindowState.MAXIMIZED) prefs.set(__name__, 'win-is-maximized', maximized)
def onPanedResize(win, rect): prefs.set(__name__, 'paned-pos', paned.get_position())
def onAppQuit(self): """ The application is about to terminate """ prefs.set(__name__, 'show_thumb', self.cover_spot.show_thumb)
def realStartup(window, paned): """ Perform all the initialization stuff which is not mandatory to display the window. This function should be called within the GTK main loop, once the window has been displayed """ # Is the application started for the first time? first_start = prefs.get(__name__, 'first-time', True) logging.debug('First start: {}'.format(first_start)) if first_start: prefs.set(__name__, 'first-time', False) # Enable some modules by default prefs.set('modules', 'enabled_modules', ['Covers', 'Desktop Notification']) import atexit import signal import dbus.mainloop.glib import modules modules.load_enabled_modules() def onDelete(win, event): """ Use our own quit sequence, that will itself destroy the window """ win.hide() modules.postQuitMsg() return True def onResize(win, rect): """ Save the new size of the window """ maximized = win.get_state() & Gdk.WindowState.MAXIMIZED if not maximized: prefs.set(__name__, 'win-width', rect.width) prefs.set(__name__, 'win-height', rect.height) view_mode = prefs.get(__name__, 'view-mode', DEFAULT_VIEW_MODE) if view_mode in (consts.VIEW_MODE_FULL, consts.VIEW_MODE_PLAYLIST): prefs.set(__name__, 'full-win-height', rect.height) def onPanedResize(win, rect): prefs.set(__name__, 'paned-pos', paned.get_position()) def onState(win, event): """ Save the new state of the window """ if event.changed_mask & Gdk.WindowState.MAXIMIZED: maximized = bool(event.new_window_state & Gdk.WindowState.MAXIMIZED) prefs.set(__name__, 'win-is-maximized', maximized) def atExit(): """ Final function, called just before exiting the Python interpreter """ prefs.save() log.logger.info('Stopped') # D-Bus dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) # Register some handlers (Signal SIGKILL cannot be caught) atexit.register(atExit) signal.signal(signal.SIGINT, lambda sig, frame: onDelete(window, None)) signal.signal(signal.SIGTERM, lambda sig, frame: onDelete(window, None)) # GTK handlers window.connect('delete-event', onDelete) window.connect('size-allocate', onResize) window.connect('window-state-event', onState) paned.connect('size-allocate', onPanedResize) # Let's go GObject.idle_add(modules.postMsg, consts.MSG_EVT_APP_STARTED)