是否有Ubuntu Unity的“Places”菜单?

我想知道是否可以在Ubuntu的上层菜单中添加“Places”选项卡,例如CentOS,Debian等。

谢谢

我尝试了几个现有的,但找不到工作的 地方指标。 我发现的那些已经过时,ppa不再维护了。

Modular Places菜单

所以,在一个新写的下面: Ubuntu的位置和文件指示器

在此处输入图像描述 2

ppa版本是模块化版本; 您可以选择菜单中显示的内容:

[ 在此处输入图像描述 ]

在完整版中:

在此处输入图像描述

…或最小的,仅显示最近使用的:

在此处输入图像描述

从ppa安装

sudo add-apt-repository ppa:vlijm/placesfiles sudo apt-get update sudo apt-get install placesfiles 

显示地点菜单,书签和最近使用的文件的简化版本

描述和(初始)代码

剧本

 #!/usr/bin/env python3 import signal import gi gi.require_version('Gtk', '3.0') gi.require_version('AppIndicator3', '0.1') from gi.repository import Gtk, AppIndicator3, GObject import time from threading import Thread import os import subprocess class Indicator(): def __init__(self): currpath = os.path.dirname(os.path.realpath(__file__)) self.home = os.environ["HOME"] self.bmark_file = os.path.join(self.home, ".config/gtk-3.0/bookmarks") self.def_file = os.path.join(self.home, ".config/user-dirs.dirs") self.recdata = os.path.join(self.home, ".local/share/recently-used.xbel") self.n = 10 self.app = 'places' iconpath = os.path.join(currpath, "dir_icon.png") self.indicator = AppIndicator3.Indicator.new( self.app, iconpath, AppIndicator3.IndicatorCategory.OTHER) self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE) self.indicator.set_label("Places", self.app) self.indicator.set_menu(self.create_menu()) # the thread: self.update = Thread(target=self.check_recent) self.update.setDaemon(True) self.update.start() def create_menu(self): # creates the (initial) menu self.menu = Gtk.Menu() # separator initial = Gtk.MenuItem("Fetching list...") menu_sep = Gtk.SeparatorMenuItem() self.menu.append(initial) self.menu.append(menu_sep) # item_quit.show() self.menu.show_all() return self.menu def open_directory(self, *args): index = self.menu.get_children().index(self.menu.get_active()) selection = self.menu_items2[index-2] self.execute(["xdg-open", selection]) def open_file(self, *args): index = self.submenu.get_children().index(self.submenu.get_active()) selection = self.submenu2[index] self.execute(["xdg-open", selection]) def go_special(self, button, target): self.execute(["xdg-open", target]) def connect(self, button): self.execute("nautilus-connect-server") def set_new(self): # update the list, appearing in the menu for i in self.menu.get_children(): self.menu.remove(i) home_mention = Gtk.MenuItem("⌂ Home") home_mention.connect("activate", self.go_special, self.home) self.menu.append(home_mention) # separator menu_sep1 = Gtk.SeparatorMenuItem() self.menu.append(menu_sep1) for app in self.menu_items2: sub = Gtk.MenuItem("⏍ "+app.split("/")[-1]) self.menu.append(sub) sub.connect('activate', self.open_directory) # separator menu_sep2 = Gtk.SeparatorMenuItem() self.menu.append(menu_sep2) # network network = "network:///" network_mention = Gtk.MenuItem("⇄ Network") network_mention.connect("activate", self.go_special, network) self.menu.append(network_mention) connect_mention = Gtk.MenuItem("⮁ Connect to server") connect_mention.connect("activate", self.connect) self.menu.append(connect_mention) # separator menu_sep3 = Gtk.SeparatorMenuItem() self.menu.append(menu_sep3) # computer computer = "computer:///" computer_mention = Gtk.MenuItem("⛁ Computer") computer_mention.connect("activate", self.go_special, computer) self.menu.append(computer_mention) recent_mention = Gtk.MenuItem("⁕ Recent files") self.menu.append(recent_mention) self.submenu = Gtk.Menu() for f in self.submenu2: recent = Gtk.MenuItem(f) recent.connect("activate", self.open_file) self.submenu.append(recent) recent_mention.set_submenu(self.submenu) # separator menu_sep6 = Gtk.SeparatorMenuItem() self.menu.append(menu_sep6) # quit item_quit = Gtk.MenuItem('Quit') item_quit.connect('activate', self.stop) self.menu.append(item_quit) self.menu.show_all() def run_about(self, *args): self.execute("/opt/upfront/code/runabout") def check_recent(self): self.menu_items1 = []; self.submenu1 = [] while True: time.sleep(4) self.menu_items2 = self.get_bookmarks() self.submenu2 = self.get_files() if any([self.menu_items2 != self.menu_items1, self.submenu2 != self.submenu1]): GObject.idle_add( self.set_new, priority=GObject.PRIORITY_DEFAULT ) self.menu_items1 = self.menu_items2 self.submenu1 = self.submenu2 def stop(self, source): Gtk.main_quit() def get_bookmarks(self): loc_bookmarks = [ l.replace("file://", "") for l in open(self.bmark_file).read().splitlines()\ if l.startswith("file://") ] netw_bookmarks = [ l for l in open(self.bmark_file).read().splitlines()\ if l.startswith("smb://") ] defaults = [ os.path.join(self.home, l.replace('"', "").split("$HOME/")[-1]) for l in \ open(self.def_file).read().splitlines() if all\ (["$HOME/" in l, l.startswith("XDG")]) ] return [self.replace_sc(m.split(" ")[0]).rstrip("/") for m in list( set(loc_bookmarks+defaults+netw_bookmarks))] def replace_sc(self, path): for c in [("%23", "#"), ("%5D", "]"), ("%5E", "^"), ("file://", ""), ("%20", " ")]: path = path.replace(c[0], c[1]) return path def execute(self, command): subprocess.Popen(command) def get_files(self): # create the list of recently used files used = [l for l in open(self.recdata) if all([ ' 

如何使用(如果没有从ppa安装)

  1. 将脚本复制到空文件中,将其另存为places_indicator.py
  2. 保存完全命名的图标(右键单击>另存为):

     dir_icon.png 

    在此处输入图像描述

    .. 在与脚本相同的目录中。

  3. 通过以下命令测试脚本:

     python3 /path/to/places_indicator.py 
  4. 如果一切正常,请将其添加到启动应用程序:Dash>启动应用程序>添加。 添加命令:

     /bin/bash -c "sleep 10 && python3 /path/to/places_indicator.py 

关于指标

指标显示:

  1. 主目录
  2. 所有目录(本地书签和smb)中
    • ~/.config/gtk-3.0/bookmarks
    • ~/.config/user-dirs.dirs
  3. 网络
  4. 连接到网络
  5. 电脑
  6. 最近使用过的文件(实际上是10个,可以很容易地改变)

更改/添加/删除的书签会动态更新

2017年2月24日更新 :该指标现在可以选择固定网络链接

介绍

注意:此答案的先前版本可以在编辑历史记录下找到,尽管它不再相关。

下面提出的指标是针对不同的问题,但是既然机会出现了,我决定在这里发布它。 文件指示器是访问用户文件和文件夹的简单指示器。 它允许检查最近使用的文件,为文件和目录添加书签。 特别是,“地点”菜单与此问题特别相关。

在此处输入图像描述

在此处输入图像描述

从截图中可以看出,该指标还支持英语以外的语言环境,因此如果您的系统使用英语以外的其他语言,它将起作用。

更新 :指示器现在还支持启动已固定的.desktop文件。 例如,如果你有firefox.desktop固定,它将启动Firefox。 因此,该指标可以用作程序的快速启动器。 该function在撰写本文时正在进入PPA(11月19日,格林威治标准时间下午7:53,需要大约24小时才能完成),但已经在github以及更新的源代码中。

在此处输入图像描述

获得指标

该指标可从我的个人PPA和GitHub获得 。 使用以下步骤获取它:

 sudo add-apt-repository ppa:1047481448-2/sergkolo sudo apt-get update sudo apt-get install files-indicator 

源代码

 #!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Author: Serg Kolo , contact: 1047481448@qq.com # Date: November 19 , 2016 # Purpose: appindicator for accessing files and folders # Tested on: Ubuntu 16.04 LTS # # # Licensed under The MIT License (MIT). # See included LICENSE file or the notice below. # # Copyright © 2016 Sergiy Kolodyazhnyy # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import gi gi.require_version('AppIndicator3', '0.1') gi.require_version('Notify', '0.7') from gi.repository import GLib as glib from gi.repository import AppIndicator3 as appindicator from gi.repository import Gtk as gtk from gi.repository import Gio from gi.repository import Notify from collections import OrderedDict # from collections import OrderedDict import urllib.parse import subprocess import copy import shutil import dbus import math import json import os class FilesIndicator(object): def __init__(self): self.app = appindicator.Indicator.new( 'files-indicator', "document-open-recent", appindicator.IndicatorCategory.HARDWARE ) self.user_home = os.path.expanduser('~') filename = '.pinned_files.json' self.pinned_list = os.path.join(self.user_home,filename) self.config = os.path.join(self.user_home,'.files_indicator.json') self.max_items = 15 self.name_length = 20 self.read_config() self.app.set_status(appindicator.IndicatorStatus.ACTIVE) self.cached_files = self.get_recent_files() self.make_menu() self.update() def read_config(self,*args): config = {} try: with open(self.config) as f: config = json.load(f) except FileNotFoundError: print('>>> ',self.config,' not found.Creating one') f = open(self.config,'w') config = {'max_items':self.max_items, 'name_length':self.name_length } json.dump(config,f,indent=4) f.close() except json.JSONDecodeError: print(">>> Can't read ",self.pinned_list,',may be corrupt') return None else: self.max_items = config['max_items'] self.name_length = config['name_length'] def add_menu_item(self, menu_obj, item_type, image, label, action, args): """ dynamic function that can add menu items depending on the item type and other arguments""" menu_item, icon = None, None if item_type is gtk.ImageMenuItem and label: menu_item = gtk.ImageMenuItem.new_with_label(label) menu_item.set_always_show_image(True) if '/' in image: icon = gtk.Image.new_from_file(image) else: icon = gtk.Image.new_from_icon_name(image, 48) menu_item.set_image(icon) elif item_type is gtk.ImageMenuItem and not label: menu_item = gtk.ImageMenuItem() menu_item.set_always_show_image(True) if '/' in image: icon = gtk.Image.new_from_file(image) else: icon = gtk.Image.new_from_icon_name(image, 16) menu_item.set_image(icon) elif item_type is gtk.MenuItem: menu_item = gtk.MenuItem(label) elif item_type is gtk.SeparatorMenuItem: menu_item = gtk.SeparatorMenuItem() if action: menu_item.connect('activate', action, *args) menu_obj.append(menu_item) menu_item.show() def get_user_dirs(self,*args): user_dirs = [] for index,val in glib.UserDirectory.__enum_values__.items(): if index == 8: continue dir = glib.get_user_special_dir(index) if dir: user_dirs.append(dir) return user_dirs def get_file_icon(self,*args): if args[-1].endswith('.desktop'): desk_file = Gio.DesktopAppInfo.new_from_filename(args[-1]) icon = desk_file.get_icon() if type(icon) == Gio.ThemedIcon: themed_name = icon.get_names()[0] theme = gtk.IconTheme.get_default() name = theme.lookup_icon(themed_name, 48, 0).get_filename() if type(icon) == Gio.FileIcon: name = icon.get_file().get_uri() icon_url= urllib.parse.unquote(name).replace('file://','') return icon_url file = Gio.File.new_for_path(args[-1]) file_info = file.query_info("standard::*",0) icon_string = file_info.get_icon().to_string() if 'folder-' in icon_string: return icon_string.split()[-2] return icon_string.split()[-1] def get_recent_files(self,*args): manager = gtk.RecentManager.get_default() try: files = OrderedDict() for index,item in enumerate(manager.get_items(),1): uri = item.get_uri() uri_decoded = urllib.parse.unquote(uri) filepath = uri_decoded.replace('file://','') if not os.path.exists(filepath): continue basename = os.path.basename(uri_decoded) files[basename] = filepath if index == self.max_items: break except Exception as e: print(e) return None finally: return files def callback(self,*args): self.update() def update(self,*args): current_files = self.get_recent_files() if current_files != self.cached_files: self.make_menu() self.cached_files = current_files glib.timeout_add_seconds(3,self.callback) def add_submenu(self,top_menu,label): menuitem = gtk.MenuItem(label) submenu = gtk.Menu() menuitem.set_submenu(submenu) top_menu.append(menuitem) menuitem.show() return submenu def make_menu(self): if hasattr(self, 'app_menu'): for item in self.app_menu.get_children(): self.app_menu.remove(item) else: self.app_menu = gtk.Menu() recent = self.add_submenu(self.app_menu,'Recent Files') recent_dict = self.get_recent_files() content = [recent,gtk.ImageMenuItem,'gtk-add', 'Add to Recent Files',self.add_recent,[None] ] self.add_menu_item(*content) content = [recent,gtk.ImageMenuItem,'user-trash', 'Clear recent files list',self.clear_recent,[None] ] self.add_menu_item(*content) content = [recent,gtk.SeparatorMenuItem, None,None, None,[None] ] self.add_menu_item(*content) self.add_menu_item(*content) if not recent_dict: content = [recent,gtk.MenuItem,None, 'No items',None,None ] self.add_menu_item(*content) last = None for i in recent.get_children(): last = i last.set_sensitive(False) else: for name,data in recent_dict.items(): icon = self.get_file_icon(data) content = [recent, gtk.ImageMenuItem, icon, name[:self.name_length], self.open_item, [data] ] self.add_menu_item(*content) # Pinned files bookmarks = self.add_submenu(self.app_menu,'Pinned Files') content = [bookmarks,gtk.ImageMenuItem, 'bookmark_add','Pin a file', self.pin_file,[bookmarks,None] ] self.add_menu_item(*content) content = [bookmarks,gtk.ImageMenuItem, 'remove','Remove item', self.remove_pinned,['files'] ] self.add_menu_item(*content) content = [bookmarks,gtk.ImageMenuItem, 'user-trash','Remove All', self.remove_all_pinned,[None] ] self.add_menu_item(*content) content = [bookmarks,gtk.SeparatorMenuItem, None,None, None,[None] ] self.add_menu_item(*content) self.add_menu_item(*content) pinned_files = self.get_pinned() if (pinned_files and 'files' in pinned_files.keys() and pinned_files['files']): for filepath in pinned_files['files']: icon = self.get_file_icon(filepath) content = [bookmarks,gtk.ImageMenuItem, icon,os.path.basename(filepath), self.open_item,[filepath] ] self.add_menu_item(*content) else: content = [bookmarks,gtk.MenuItem,None, 'No items',None,None ] self.add_menu_item(*content) last = None for i in bookmarks.get_children(): last = i last.set_sensitive(False) places = self.add_submenu(self.app_menu,'Places') content = [places,gtk.ImageMenuItem,'add', 'Pin Directory',self.pin_dir,[None] ] self.add_menu_item(*content) content = [places,gtk.ImageMenuItem, 'remove','Remove Pinned', self.remove_pinned,['dirs'] ] self.add_menu_item(*content) content = [places,gtk.SeparatorMenuItem, None,None, None,[None] ] self.add_menu_item(*content) content = [places,gtk.MenuItem,None, 'Standard Dirs',None,None ] self.add_menu_item(*content) last = None for i in places.get_children(): last = i last.set_sensitive(False) for dir in self.get_user_dirs(): icon = self.get_file_icon(dir) content = [places,gtk.ImageMenuItem,icon, os.path.basename(dir),self.open_item,[dir] ] self.add_menu_item(*content) content = [places,gtk.SeparatorMenuItem, None,None, None,[None] ] self.add_menu_item(*content) content = [places,gtk.MenuItem,None, 'Pinned Dirs',None,None ] self.add_menu_item(*content) last = None for i in places.get_children(): last = i last.set_sensitive(False) if (pinned_files and 'dirs' in pinned_files.keys() and pinned_files['dirs']): for dir in pinned_files['dirs']: icon = self.get_file_icon(dir) print(icon) content = [places,gtk.ImageMenuItem,icon, os.path.basename(dir),self.open_item,[dir] ] self.add_menu_item(*content) else: content = [places,gtk.MenuItem,None, 'No items',None,None ] self.add_menu_item(*content) last = None for i in places.get_children(): last = i last.set_sensitive(False) content = [self.app_menu,gtk.SeparatorMenuItem, None,None, None,[None] ] self.add_menu_item(*content) content = [self.app_menu,gtk.ImageMenuItem,'exit', 'quit',self.quit,[None] ] self.add_menu_item(*content) self.app.set_menu(self.app_menu) def check_directory(self,*args): current_set = set(os.listdir(args[-1])) return current_set - self.cached_set def get_pinned(self,*args): try: with open(self.pinned_list) as f: return json.load(f,object_pairs_hook=OrderedDict) except FileNotFoundError: print('>>> ',self.pinned_list,' not found') return None except json.JSONDecodeError: print(">>> Can't read ",self.pinned_list,',may be corrupt') return None def pin_dir(self,*args): # TODO current_list = self.get_pinned() if not current_list: current_list = OrderedDict() current_list['dirs'] = [] f = open(self.pinned_list,'w') f.write("") f.close() if not args[-1]: cmd = "zenity --file-selection --directory --separator || --multiple" dirs = self.run_cmd(cmd.split()) else: dirs = args[-1] dir_list = [] if not dirs: return None dir_list = dirs.decode().strip().split("||") if not 'dirs' in current_list.keys(): current_list['dirs'] = [] for f in dir_list: #icon = self.get_file_icon(f) current_list['dirs'].append(f) with open(self.pinned_list,'w') as f: json.dump(current_list,f,indent=4) self.make_menu() def pin_file(self,*args): current_list = self.get_pinned() if not current_list: current_list = OrderedDict() current_list['files'] = [] f = open(self.pinned_list,'w') f.write("") f.close() if not args[-1]: cmd = "zenity --file-selection --separator || --multiple " files = self.run_cmd(cmd.split()) else: files = args[-1] file_list = [] if not files: return None file_list = files.decode().strip().split("||") if not 'files' in current_list.keys(): current_list['files'] = [] for f in file_list: #icon = self.get_file_icon(f) current_list['files'].append(f) with open(self.pinned_list,'w') as f: json.dump(current_list,f,indent=4) self.make_menu() def remove_all_pinned(self,*args): try: #os.unlink(self.pinned_list) with open(self.pinned_list) as f: pinned = json.load(f) pinned.pop('files') with open(self.pinned_list,'w') as f: json.dump(pinned,f,indent=4) except: pass finally: self.make_menu() def remove_pinned(self,*args): key = args[-1] pinned = self.get_pinned() if not pinned: return cmd_str = "zenity --forms --add-combo Remove --combo-values" vals = "|".join(pinned[key]) cmd = cmd_str.split() + [vals] item = self.run_cmd(cmd) if item: path = item.decode().strip() index = pinned[key].index(path) pinned[key].pop(index) with open(self.pinned_list,'w') as f: json.dump(pinned,f,indent=4) self.make_menu() def add_recent(self,*args): cmd = "zenity --file-selection --separator || --multiple " files = self.run_cmd(cmd.split()) file_list = [] if not files: return file_list = files.decode().strip().split("||") items = ['file://' + f for f in file_list] for f in items: gtk.RecentManager().get_default().add_item(f) def clear_recent(self,*args): try: gtk.RecentManager.get_default().purge_items() self.make_menu() except: pass def open_item(self,*args): #self.run_cmd(['xdg-open',args[-1]]) if args[-1].endswith('.desktop'): desk_file = Gio.DesktopAppInfo.new_from_filename(args[-1]) return desk_file.launch_uris() return subprocess.Popen(['xdg-open',args[-1]]) def quit(self,*args): gtk.main_quit() def run_cmd(self, cmdlist): """ utility: reusable function for running external commands """ #new_env = dict(os.environ) #new_env['LC_ALL'] = 'C' try: stdout = subprocess.check_output(cmdlist) #env=new_env) except subprocess.CalledProcessError: pass else: if stdout: return stdout def run(self): """ Launches the indicator """ try: gtk.main() except KeyboardInterrupt: pass def quit(self, *args): """ closes indicator """ gtk.main_quit() def main(): """ defines program entry point """ indicator = FilesIndicator() indicator.run() if __name__ == '__main__': try: main() except KeyboardInterrupt: gtk.main_quit() 

配置

该指标通过存储在用户主目录中的两个json文件进行配置。

~/.files_indicator.json控制用户界面,菜单条目的长度和最近文件菜单中的最大数量。

 { "name_length": 30, "max_items": 10 } 

~/.pinned_files.json控制固定文件和文件夹的列表。 每个项目都是一个列表/数组。

 { "dirs": [ "/home/xieerqi/\u56fe\u7247/Wallpapers" ], "files": [ "/home/xieerqi/work_in_progress/videonauth_code.py", "/home/xieerqi/work_in_progress/spin_button.py" ] } 

好吧,我们所做的只是安装Ubuntu-Gnome并在Tweak工具中启用’Places’扩展并获得它。 要说Ubuntu Gnome看起来比Unity好多了

请参阅“Lugares”选项卡