def load_desktop_entry_with_dropins(filename, dropins): desktop_entry = DesktopEntry(filename) for dropin in dropins: dropin_entry = DesktopEntry(dropin) for group_name, group in dropin_entry.content.items(): desktop_entry.content.setdefault(group_name, {}).update(group) return desktop_entry
def enabled_toggled(self, cell, path, model): iter = model.get_iter((int(path), )) active = model.get_value(iter, COLUMN_ACTIVE) path = model.get_value(iter, COLUMN_PATH) if self.is_defaultitem(path): shutil.copy(path, self.userdir) path = os.path.join(self.userdir, os.path.basename(path)) desktopentry = DesktopEntry(path) desktopentry.set("X-GNOME-Autostart-enabled", "false") desktopentry.write() model.set(iter, COLUMN_PATH, path) else: if active: desktopentry = DesktopEntry(path) desktopentry.set("X-GNOME-Autostart-enabled", "false") desktopentry.write() else: if self.is_in_systemdir(path): os.remove(path) path = os.path.join(self.get_systemdir(path), os.path.basename(path)) model.set(iter, COLUMN_PATH, path) else: desktopentry = DesktopEntry(path) desktopentry.set("X-GNOME-Autostart-enabled", "true") desktopentry.set("Hidden", "false") desktopentry.write() active = not active model.set(iter, COLUMN_ACTIVE, active)
def from_dotdesktop(cls, app_def: Path, distro: WSLDistro) -> Optional[WSLApp]: """ Return a WSLApp from a .desktop file. Args: app_def: .desktop file path """ de = DesktopEntry(app_def) name = de.getName() generic_name = de.getGenericName() cmd = de.getExec() gui = not de.getTerminal() icon = de.getIcon() if name: return cls(name, generic_name, cmd, gui, icon) else: # This is a symlink linux_path = str(app_def)[str(app_def).index(r"\\wsl$") + 7:] linux_path = linux_path[linux_path.index("\\"):].replace("\\", "/") # Turn symlink target into Windows Path symlink = distro.get_cmd_output(f"readlink -f -e '{linux_path}'") app_def = distro._unc_path_from_cmd(symlink) de = DesktopEntry(app_def) name = de.getName() generic_name = de.getGenericName() cmd = de.getExec() gui = not de.getTerminal() icon = de.getIcon() if name: return cls(name, generic_name, cmd, gui, icon) return None
def main(argv): args = parse_args(argv[1:]) if args.list_dirs: for directory in xdg_data_dirs: print(os.path.join(directory, "applications")) elif args.list_files: for directory in xdg_data_dirs: path = os.path.join(directory, "applications") try: for entry in os.listdir(path): if entry.endswith(".desktop"): if args.verbose: filename = os.path.join(path, entry) desktop = DesktopEntry(filename) print("{:70} {:40} {:40}".format( filename, desktop.getName(), desktop.getExec())) else: print(os.path.join(path, entry)) except FileNotFoundError: pass else: filename = get_desktop_file(args.DESKTOP) print(filename) desktop = DesktopEntry(filename) print("Name: {}".format(desktop.getName())) print("Exec: {}".format(desktop.getExec())) print("TryExec: {}".format(desktop.getTryExec())) print("Mime-Types: {}".format(desktop.getMimeTypes()))
def on_edit_item(self, widget, treeview): model, iter = treeview.get_selection().get_selected() if iter: path = model.get_value(iter, COLUMN_PATH) if path[1:4] == "etc": shutil.copy(path, treeview.userdir) path = os.path.join(treeview.userdir, os.path.basename(path)) dialog = AutoStartDialog(DesktopEntry(path), widget.get_toplevel()) if dialog.run() == gtk.RESPONSE_OK: name = dialog.pm_name.get_text() cmd = dialog.pm_cmd.get_text() if not name: ErrorDialog( _("The name of the startup program cannot be empty") ).launch() elif not cmd: ErrorDialog( _("Text field was empty (or contained only whitespace)" )).launch() else: desktopentry = DesktopEntry(path) desktopentry.set("Name", name, locale=True) desktopentry.set("Exec", cmd) desktopentry.set("Comment", dialog.pm_comment.get_text(), locale=True) desktopentry.write() treeview.update_items( all=self.show_all_button.get_active(), comment=self.show_comment_button.get_active()) dialog.destroy() return dialog.destroy()
def get_autostart(self): if os.path.exists(self.autostart_desktop): desktop_entry = DesktopEntry(self.autostart_desktop) return not desktop_entry.getHidden() elif os.path.exists(self.sys_autostart_desktop): desktop_entry = DesktopEntry(self.sys_autostart_desktop) return not desktop_entry.getHidden() else: return False
def get_desktop_entry(desktop_file): if os.path.isabs(desktop_file): return DesktopEntry(desktop_file) else: filename = get_desktop_file(desktop_file) if filename is not None: return DesktopEntry(filename) else: return None
def desktop(self, dest=None): ''' Returns desktop file object which may be written to disk. ''' if dest: self.desktop_file = DesktopEntry(dest) else: self.desktop_file = DesktopEntry() self.desktop_file.addGroup('Desktop Entry') self.desktop_file.set('Version', '1.0') self._update_desktop() return self.desktop_file
def on_drag_data_received(self, widget, context, x, y, selection, target, timestamp, box): droppeduris = selection.get_uris() # url-unquote the list, strip file:// schemes, handle .desktop-s pathlist = [] app = None for uri in droppeduris: scheme, _, path, _, _ = urlsplit(uri) if scheme != "file": pathlist.append(uri) else: filename = url2pathname(path) desktopentry = DesktopEntry() try: desktopentry.parse(filename) except xdg.Exceptions.ParsingError: pathlist.append(filename) continue if desktopentry.getType() == 'Link': pathlist.append(desktopentry.getURL()) if desktopentry.getType() == 'Application': app = desktopentry.getExec() if app and len(droppeduris) == 1: text = app else: text = str.join("", (shell_quote(path) + " " for path in pathlist)) box.terminal.feed_child(text) return True
def test_invalid_unicode(self): test_file = os.path.join(self.tmpdir, "gnome-alsamixer.desktop") with io.open(test_file, "w", encoding='latin-1') as f: f.write(resources.gnome_alsamixer_desktop) # Just check this doesn't throw a UnicodeError. DesktopEntry(test_file)
def test_basic(self): entry = DesktopEntry(self.test_file) assert entry.hasKey("Categories") assert not entry.hasKey("TryExec") assert entry.hasGroup("Desktop Action Window") assert not entry.hasGroup("Desktop Action Door")
def __new__(cls, desk): desk = DesktopEntry(str(a)) name = desk.getName() icon = getIconPath(desk.getIcon()) exe = shlex.split(re.sub('%[fFuUdDnNickvm]', '', desk.getExec())) launch = partial(QProcess.startDetached, exe[0], exe[1:]) return super().__new__(cls, name, icon, launch)
def _extract_desktop_entry(self, app): '''Get DesktopEntry for desktop file and verify it''' d = self.manifest['hooks'][app]['desktop'] fn = os.path.join(self.unpack_dir, d) bn = os.path.basename(fn) if not os.path.exists(fn): error("Could not find '%s'" % bn) fh = open_file_read(fn) contents = "" for line in fh.readlines(): contents += line fh.close() try: de = DesktopEntry(fn) except xdgParsingError as e: error("desktop file unparseable: %s (%s):\n%s" % (bn, str(e), contents)) try: de.parse(fn) except Exception as e: error("desktop file unparseable: %s (%s):\n%s" % (bn, str(e), contents)) return de, fn
def _create_autostarter(self): autostart_file = self._get_autostart_file_path() autostart_dir = os.path.dirname(autostart_file) if not os.path.isdir(autostart_dir): # create autostart dir try: os.mkdir(autostart_dir) except DirectoryCreationError as e: print("Creation of autostart dir failed, please make it yourself: {}".format(autostart_dir)) raise e if not os.path.isfile(autostart_file): # create autostart entry starter_item = DesktopEntry(autostart_file) starter_item.set('Name', 'f.lux indicator applet') # Use the user's shell to start 'fluxgui', in case # 'fluxgui' is not installed on a standard system path. We # use 'sh' to start the users '/etc/passwd' shell via # '$SHELL', so that this will still work if the user # changes their shell after the # 'autostart/fluxgui.desktop' file is created. # # See PR #89 for an alternative approach: # # https://github.com/xflux-gui/fluxgui/pull/89 # # The escaping of the 'Exec' field is described in # # https://developer.gnome.org/desktop-entry-spec/#exec-variables. starter_item.set('Exec', r'sh -c "\\"\\$SHELL\\" -c fluxgui"') starter_item.set('Icon', 'fluxgui') starter_item.set('X-GNOME-Autostart-enabled', 'true') starter_item.write() self.autostart = True
def init(self, info, progress): """ If needed, perform long initialisation tasks here. info is a dictionary with useful information. Currently it contains the following values: "values": a dict mapping index mnemonics to index numbers The progress indicator can be used to report progress. """ # Read the value indexes we will use values = info['values'] self.val_popcon = values.get("app-popcon", -1) self.indexers = [Indexer(lang, self.val_popcon, progress) for lang in [None] + list(self.langs)] self.entries = {} progress.begin("Reading .desktop files from %s" % APPINSTALLDIR) for f in os.listdir(APPINSTALLDIR): if f[0] == '.' or not f.endswith(".desktop"): continue entry = DesktopEntry(os.path.join(APPINSTALLDIR, f)) pkg = entry.get("X-AppInstall-Package") self.entries.setdefault(pkg, []).append((f, entry)) progress.end()
def _find_pdf_viewers(self): pdf_viewers = {} if platform.system() == "Linux": # Find all .desktop files for search_path in [ "/usr/share/applications", "/usr/local/share/applications", os.path.expanduser("~/.local/share/applications"), ]: try: for filename in os.listdir(search_path): full_filename = os.path.join(search_path, filename) if os.path.splitext(filename)[1] == ".desktop": # See which ones can open PDFs desktop_entry = DesktopEntry(full_filename) if ("application/pdf" in desktop_entry.getMimeTypes() and desktop_entry.getName() != "dangerzone"): pdf_viewers[desktop_entry.getName( )] = desktop_entry.getExec() except FileNotFoundError: pass return pdf_viewers
def parse_to_entries(file_name): if file_name.endswith('.menu'): return xdg.Menu.parse(file_name) else: result = DesktopEntry() result.parse(file_name) return result
def fetchMore(self, parent): # print("RecollQuery.fetchMore:") num_to_fetch = min(self.pagelen, self.totres - len(self.searchResults)) titem = [] for count in range(num_to_fetch): try: item = self.query.fetchone() url = str(item['url'][7:]) if url.endswith("desktop"): desktop = DesktopEntry() try: desktop.parse(url) except (ParsingError, DuplicateGroupError, DuplicateKeyError) as e: print(e) if desktop.getNoDisplay(): continue if len(desktop.getOnlyShowIn()) != 0: continue titem.append(item) except: break self.beginInsertRows(QtCore.QModelIndex(), len(self.searchResults), len(self.searchResults) + len(titem) - 1) self.searchResults.extend(titem) self.endInsertRows()
def get_or_create_desktop_file(): desktop = lookup_desktop_file('uroute.desktop') if desktop is None: path = os.path.join( xdg.BaseDirectory.xdg_data_home, 'applications', 'uroute.desktop', ) desktop = DesktopEntry(path) desktop.set('Version', '1.0') desktop.set('Name', 'Uroute') desktop.set('Comment', 'URL router.') desktop.set('Exec', 'uroute %U') desktop.set('StartupNotify', 'true') desktop.set('Terminal', 'false') desktop.set('Categories', 'Network;WebBrowser;') desktop.set( 'MimeType', ';'.join(( 'text/html', 'text/xml', 'application/xhtml_xml', 'application/xhtml+xml', 'image/webp', 'video/webp', 'x-scheme-handler/http', 'x-scheme-handler/https', 'x-scheme-handler/ftp', '' # End with a ; ))) desktop.write(trusted=True) log.debug('Created Uroute desktop entry at %s', path) return desktop
def desktop(self): ''' Returns desktop file object which may be written to disk. ''' self.desktop_file = DesktopEntry() self.desktop_file.addGroup('Desktop Entry') if self.type == TargetType.URL: self.desktop_file.set('Type', 'Link') else: self.desktop_file.set('Type', 'Application') self.desktop_file.set('Version', '1.0') self.desktop_file.set('Name', self.name) if self.type == TargetType.URL: self.desktop_file.set('URL', self.path) else: self.desktop_file.set('Terminal', 'false') self.desktop_file.set('Exec', '{} {}'.format(self.path, self.arguments)) if self.icon: self.desktop_file.set('Icon', self.icon) return self.desktop_file
def test_present(self): with io.open(self.test_file, "w", encoding='utf-8') as f: f.write(resources.python_desktop) entry = DesktopEntry(self.test_file) res = entry.findTryExec() assert res, repr(res)
def parse(desktop_file, debug_enabled): """ Returns a dict if the .desktop entry should be included in the dmenu, or none if not applicable """ application = DesktopEntry(desktop_file) if debug_enabled: eprint('PARSED: ' + desktop_file) if application.getHidden(): if debug_enabled: eprint('HIDDEN: ' + desktop_file) return None if application.getNoDisplay(): if debug_enabled: eprint('NODISPLAY: ' + desktop_file) return None executable = application.getTryExec() if not executable: executable = application.getExec() if not executable: if debug_enabled: eprint('NO EXECUTABLE: ' + desktop_file) return None return { application.getName(): [part for part in executable.split(' ') if not part.startswith('%')] }
def test_absent(self): with io.open(self.test_file, "w", encoding='utf-8') as f: f.write(resources.unicode_desktop) entry = DesktopEntry(self.test_file) res = entry.findTryExec() assert res is None, repr(res)
def launch_desktop(self, request, handler, desktop): entry = DesktopEntry() entry.parse(desktop) exec_ = entry.getExec() self.launch( request, handler, '/bin/bash -c "%s"' % exec_.replace('"', '\\"')) # Is it really necessary to call bash ?
def add_applications(self): """ Populates the self.objects.list ListBox with the applications in SEARCH_PATH. """ for path in SEARCH_PATH: if not os.path.exists(path): continue for application in os.listdir(path): # Add the application, if we can try: entry = DesktopEntry(os.path.join(path, application)) if not "KDE" in entry.getOnlyShowIn( ) and not application in self.desktop_list: # While excluding only KDE is not ideal, we do so # to have consistency with vera's AutostartManager. # This check is obviously a FIXME. row = ApplicationRow(application, entry) # Connect the changed signal row.connect("changed", self.on_row_changed) # Connect the requests_edit signal row.connect("requests_edit", self.on_row_requests_edit) GObject.idle_add(self.objects.list.insert, row, -1) self.desktop_list.append(application) except: print("Unable to show informations for %s." % application)
def on_add_item(self, widget, treeview): dialog = AutoStartDialog(parent=widget.get_toplevel()) if dialog.run() == gtk.RESPONSE_OK: name = dialog.pm_name.get_text() cmd = dialog.pm_cmd.get_text() if not name: ErrorDialog( _("The name of the startup program cannot be empty") ).launch() elif not cmd: ErrorDialog( _("Text field was empty (or contained only whitespace)") ).launch() else: path = os.path.join(treeview.userdir, os.path.basename(cmd) + ".desktop") desktopentry = DesktopEntry(path) desktopentry.set("Name", dialog.pm_name.get_text()) desktopentry.set("Exec", dialog.pm_cmd.get_text()) desktopentry.set("Comment", dialog.pm_comment.get_text()) desktopentry.set("Type", "Application") desktopentry.set("Version", "1.0") desktopentry.set("X-GNOME-Autostart-enabled", "true") desktopentry.write() treeview.update_items( all=self.show_all_button.get_active(), comment=self.show_comment_button.get_active()) dialog.destroy() return dialog.destroy()
def load_desktop_sessions(): xsessions_dir = "%s/share/xsessions" % sys.prefix if not os.path.exists(xsessions_dir) or not os.path.isdir(xsessions_dir): return {} xsessions = {} with IconLoadingContext(): from xdg.DesktopEntry import DesktopEntry for f in os.listdir(xsessions_dir): filename = os.path.join(xsessions_dir, f) de = DesktopEntry(filename) try: entry = load_xdg_entry(de) if not entry: continue name = de.getName() if not entry.get("IconData"): names = get_icon_names_for_session(name.lower()) v = find_icon(*names) if v: entry["IconData"] = v[0] entry["IconType"] = v[1] xsessions[name] = entry except Exception as e: log("load_desktop_sessions(%s)", remove_icons, exc_info=True) log.error("Error loading desktop entry '%s':", filename) log.error(" %s", e) return xsessions
def provide(self): from fnmatch import fnmatch from xdg.DesktopEntry import DesktopEntry items = [] for app_directory in map(os.path.expanduser, self.app_directories): for root, dirs, files in os.walk(app_directory): for filename in files: if fnmatch(filename, "*.desktop"): app_entry = DesktopEntry(os.path.join(root, filename)) icon_theme = Gtk.IconTheme.get_default() if app_entry.getNoDisplay(): continue if app_entry.getIcon() == "": icon = Gtk.IconTheme.load_icon(icon_theme, "image-missing", self.icon_size, 0) elif "/" in app_entry.getIcon(): try: unscaled_icon = GdkPixbuf.Pixbuf.new_from_file(app_entry.getIcon()) icon = unscaled_icon.scale_simple(self.icon_size, self.icon_size, GdkPixbuf.InterpType.BILINEAR) except: icon = Gtk.IconTheme.load_icon(icon_theme, "image-missing", self.icon_size, 0) else: try: unscaled_icon = Gtk.IconTheme.load_icon(icon_theme, app_entry.getIcon(), self.icon_size, 0) icon = unscaled_icon.scale_simple(self.icon_size, self.icon_size, GdkPixbuf.InterpType.BILINEAR) except: icon = Gtk.IconTheme.load_icon(icon_theme, "image-missing", self.icon_size, 0) words = app_entry.getName().split() # words.append(app_entry.getExec()) command = self.escape_command(app_entry.getExec()) if app_entry.getTerminal(): command = "%s '%s'" % (self.terminal_emulator_command, command) item = { "indexer": self, "name": app_entry.getName(), "description": app_entry.getComment(), "icon": icon, "command": command, "words": words, } items.append(item) items.sort(key=lambda i: i["name"]) return items
def getPrograms(): return { desktop.getName(): desktop for desktop in (DesktopEntry(dfile) for dfile in itertools.chain( *(glob(os.path.join(path, '*.desktop')) for path in BaseDirectory.load_data_paths('applications')))) if not desktop.getHidden() }
def add_startup(self) -> None: """Creates the auto-start entry if the user wants one.""" entry = DesktopEntry() entry.addGroup(DesktopEntry.defaultGroup) entry.set("Type", "Application") entry.set("Name", State.current.my_name) entry.set("Exec", "{0} \"{1}\"".format(State.current.python, State.current.my_path)) entry.write(self.__auto_start_entry)