Это - боковая панель моего окна наутилуса. Вы видите два различных значка - один для карт с интерфейсом USB и один для дисков.
Как наутилус определяет, который получает значок жесткого диска и который получает флеш-накопитель один?
TL; DR : Наутилус использует интерфейсы Gio GDrive, GVolume и GVolumeMonitor для получения значков, соответствующих конкретному устройству.
В Gio есть набор классов, которые позволяют приложениям читать доступные диски и тома и какие значки с ними связаны (и это то, что API уже обрабатывает). Значки возвращаются в виде Gio Icon
, поэтому приложениям не обязательно знать, где находится значок, однако всегда возможен запрос значка по имени или по полному пути. Вы увидите два типа значков: «символические» и пользовательские, и «символические» значки являются стандартными. Если вы посмотрите /usr/share/icons
, то обнаружите, что есть много значков, которые заканчиваются на -symbolic
в их названии и хранятся в нескольких папках тем (например, стандартные Adwaita, Humanity и Oxygen), обычно файлы .svg
. На скриншоте в вопросе значок жесткого диска обозначен drive-harddisk-symbolic
и drive-removable-media-usb
. Когда пользователь переключает тему рабочего стола, приложению не нужно искать полный путь к значку - если в папке темы есть значок drive-harddisk-symbolic
, Gio найдет его и вернется в приложение. Откуда я все это знаю? Я использовал те же значки для моего собственного индикатора UDisks (хотя мой подход отличается от того, что делает Наутилус).
Из чтения исходного кода Наутилуса, в частности, кода nautilusgtkplacesview.c , важными являются следующие:
Наутилус добавляет диски и тома (думаю, разделы). Есть функция add_drive , которая использует функцию Gio g_drive_get_volumes (drive)
для получения томов на конкретном диске и передает эту информацию в функцию add_volume()
Наутилуса. Gio g_volume_monitor_get_volumes()
в строках 1139 и g_volume_monitor_get_mounts () 1164 выбирает тома, которые могут быть не связаны с диском (например, ftp или сетевые ресурсы), но эта же информация передается в [ 1113] функции и add_mount()
.
Значки запрашиваются для точек монтирования и томов : Внутри функции add_volume()
функция g_volume_get_icon()
Джио выбирает значок типа GIcon
]. Внутри add_mount()
Гио g_mount_get_icon()
также типа GIcon
. В обоих случаях значок вместе с другой информацией объединяются в объект типа NAUTILUS_TYPE_GTK_PLACES_VIEW_ROW
и передаются в функцию insert_row()
Строки, вставленные в Контейнер Places : Меню Places, которое вы показываете в примере, на самом деле является одним из основных типов контейнеров Gtk - Gtk Box. Внутри этого поля есть ListBox для подразделов - вот почему есть разделители для всех пользовательских папок, дисков и томов, а также закладок. Наутилус создает объект, который происходит от типа Gtk Box, G_DEFINE_TYPE_WITH_PRIVATE (NautilusGtkPlacesView, nautilus_gtk_places_view, GTK_TYPE_BOX)
. G_DEFINE_TYPE_WITH_PRIVATE - это другая стандартная функция , и, как видно из определения Наутилуса, последний элемент определяет GTK_TYPE_BOX
- родительский объект. В файле .c
в строке строки 50 определена структура NautilusGtkPlacesViewPrivate
, которая, помимо прочего, имеет указатель на виджет ListView. Это фактическое содержание объекта.
Теперь функция insert_row()
берет экземпляр этого типа (NautilusGtkPlacesView *view
), подключает всю группу сигналов к элементу строки, полученному в качестве аргумента, и использует gtk_container_add
] вставляет всю информацию (вместе со значком) в виджет ListBox объекта Nautilus Places.
Длинное объяснение и, вероятно, выглядит проще на диаграмме, но также это все написано на C. Давайте попробуем сделать что-то сами в Python, что намного проще и проще.
Вот простое окно, которое использует интерфейс Drive Gio для создания кнопок с иконками, соответствующими подключенным дискам. Это слишком упрощенно и требует доработки, а также встроенных комментариев
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gio,Gtk
class drives_window(Gtk.Window):
def __init__(self):
super().__init__(title="Foobar")
self.volume_monitor = Gio.VolumeMonitor.get()
# We'll use Gtk.Box to hold all the buttons corresponding to each drive
# although we haven't connected the buttons to any other function
# so clicking on the does nothing
self.box = Gtk.Box()
for drive in self.volume_monitor.get_connected_drives():
button = Gtk.Button()
button.set_label(drive.get_name())
button.set_always_show_image(True)
icon = drive.get_symbolic_icon()
# buttons need Gtk.Image widget, but .get_symbolic_icon() returns Gio.ThemedIcon
# so we create new Gtk.Image using .new_From_gicon() function
# Gtk.IconSize.BUTTON is a constant
button.set_image(Gtk.Image.new_from_gicon(icon,Gtk.IconSize.BUTTON))
self.box.pack_start(button,True,True,0)
# add the box container to this window
self.add(self.box)
window = drives_window()
window.connect("destroy",Gtk.main_quit)
window.show_all()
Gtk.main()
Конечно, в настоящее время вам не нужно изобретать велосипед. Gtk предоставляет виджет PlacesSidebar
.
#!/usr/bin/env python3
from gi.repository import Gtk,Gio,GLib
w = Gtk.Window()
b1 = Gtk.Box()
p = Gtk.PlacesSidebar()
b1.pack_start(p,True,True,0)
b1.pack_start(Gtk.Button("Hello World"),True,True,0)
b1.pack_start(Gtk.Button("Hello World 2"),True,True,0)
w.add(b1)
w..connect("destroy",Gtk.main_quit)
w.show_all()
Gtk.main()
Sidenote: Наутилус также имеет заголовочный файл nautilus-icon-names.h , который определяет константы с префиксом NAUTILUS_
, например
#define NAUTILUS_ICON_FILESYSTEM "drive-harddisk-symbolic"
, вероятно, для согласованности между разработчиком и кодом, вместо того, чтобы полагаться на поиск реальных имен значков. Единственное место, где используется это конкретное определение, находится в функции get_icon
, и эта функция по иронии судьбы не используется для боковой панели Places, но используется внутри функции обновления панели пути . Пойди разберись, верно? ¯\_(ツ)_/¯