Me gustaría saber si es posible poner una pestaña "Lugares" en el menú superior de Ubuntu, como CentOS, Debian, etc.
Gracias
Me gustaría saber si es posible poner una pestaña "Lugares" en el menú superior de Ubuntu, como CentOS, Debian, etc.
Gracias
Respuestas:
Probé varios existentes, pero no pude encontrar un indicador de lugares de trabajo . Los que encontré estaban anticuados, los ppa ya no se mantenían.
Entonces, debajo de uno recién escrito: Indicador de lugares y archivos para Ubuntu .
La versión ppa es modular ; Puedes elegir qué mostrar en el menú:
[ ]
En la versión completa:
... o el más pequeño, mostrando solo los usados recientemente:
sudo add-apt-repository ppa:vlijm/placesfiles
sudo apt-get update
sudo apt-get install placesfiles
Descripción y código (inicial)
#!/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([
'<bookmark href="file://' in l, not "/tmp" in l, "." in l])]
relevant = [l.split('="') for l in set(used)]
relevant = [[it[1][7:-7], it[-2][:-10]] for it in relevant]
relevant.sort(key=lambda x: x[1])
return [item[0].replace("%20", " ") for item in relevant[::-1][:self.n]]
Indicator()
GObject.threads_init()
signal.signal(signal.SIGINT, signal.SIG_DFL)
Gtk.main()
places_indicator.py
Guarde el icono (clic derecho> guardar como) exactamente llamado:
dir_icon.png
..en uno y el mismo directorio que el script.
Prueba: ejecuta el script con el comando:
python3 /path/to/places_indicator.py
Si todo funciona bien, agréguelo a Aplicaciones de inicio: Tablero> Aplicaciones de inicio> Agregar. Agrega el comando:
/bin/bash -c "sleep 10 && python3 /path/to/places_indicator.py
El indicador muestra:
~/.config/gtk-3.0/bookmarks
~/.config/user-dirs.dirs
Los marcadores cambiantes / agregados / eliminados se actualizan dinámicamente
Actualización 24 de febrero de 2017 : el indicador ahora tiene la opción de fijar enlaces web
NOTA: La versión anterior de esta respuesta se puede encontrar en el historial de edición, aunque ya no es relevante.
El indicador presentado a continuación ha sido diseñado para una pregunta diferente, pero como se presentó la oportunidad, he decidido publicarlo aquí. El indicador de archivos es un indicador simple para acceder a los archivos y carpetas del usuario. Permite verificar archivos usados recientemente, marcar archivos y directorios. En particular, el menú Lugares es específicamente relevante para esta pregunta.
Como puede ver en la captura de pantalla, el indicador también admite configuraciones regionales distintas al inglés, por lo que si su sistema utiliza algo distinto al inglés, funcionará.
Actualización : el indicador ahora también admite el lanzamiento de archivos .desktop que se han anclado. Por ejemplo, si tienes firefox.desktop anclado, iniciará firefox. Por lo tanto, el indicador se puede usar como iniciador rápido para programas. La característica está en camino a PPA en el momento de la escritura (19 de noviembre, 7:53 pm GMT, debería tomar alrededor de 24 horas para procesar), pero ya está en Github, así como aquí, en el código fuente actualizado.
El indicador está disponible en mi PPA personal y en GitHub . Utilice los siguientes pasos para obtenerlo:
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()
El indicador se configura mediante dos archivos json almacenados en el directorio de inicio del usuario.
~/.files_indicator.json
controla la interfaz de usuario, la longitud de las entradas del menú y los números máximos en el menú de archivos recientes.
{
"name_length": 30,
"max_items": 10
}
El ~/.pinned_files.json
controla las listas de archivos y carpetas fijados. Cada elemento es una lista / matriz.
{
"dirs": [
"/home/xieerqi/\u56fe\u7247/Wallpapers"
],
"files": [
"/home/xieerqi/work_in_progress/videonauth_code.py",
"/home/xieerqi/work_in_progress/spin_button.py"
]
}
Bien, chicos, lo que hice fue instalar Ubuntu-Gnome y habilitar la extensión 'Lugares' en la herramienta Tweak y lo obtuve. Tengo que decir que Ubuntu Gnome se ve mucho mejor que Unity