Как Наутилус решает, какую иконку использовать? - proUbuntu
6 голосов
/ 04 января 2017

Это боковая панель моего окна наутилуса. Вы можете видеть два разных значка - один для флешек и один для накопителей.

Как nautilus определяет, кто получает значок жесткого диска, а какой - флэш-диск?

1 Ответ

4 голосов
/ 07 марта 2019

TL; DR : Наутилус использует интерфейсы Gio GDrive, GVolume и GVolumeMonitor для получения значков, соответствующих конкретному устройству.

API, диски и значки Gio

Gio имеет набор классов, которые позволяют приложениям читать доступные диски и тома и какие значки с ними связаны (и это то, что API уже обрабатывает). Значки возвращаются в виде Gio Icon, поэтому приложениям не нужно особенно знать, где находится значок, однако запрос значка по имени или по полному пути всегда возможен. Вы увидите два типа значков: «символические» и пользовательские, и «символические» значки являются стандартными. Если вы посмотрите на /usr/share/icons, то обнаружите, что есть много значков, которые заканчиваются на -symbolic в их названии и хранятся в нескольких папках с темами (например, стандартные Adwaita, Humanity и Oxygen), обычно файлы .svg. На скриншоте в вопросе значок жесткого диска - drive-harddisk-symbolic и drive-removable-media-usb. Когда пользователь переключает тему рабочего стола, приложению не нужно искать полный путь к значку - если в папке темы есть значок drive-harddisk-symbolic, Gio найдет его и вернется в приложение. Откуда я все это знаю? Я использовал те же значки для моего собственного индикатора UDisks (хотя мой подход отличается от того, что делает Наутилус).

Как Наутилус использует API Джио

При чтении исходного кода Nautilus, в частности nautilusgtkplacesview.c кода, основными частями являются следующие:

  1. Наутилус добавляет диски и тома (подумайте о разделах). Есть функция add_drive , которая использует функцию Gio g_drive_get_volumes (drive) для получения томов на конкретном диске и передает эту информацию в функцию add_volume() Nautilus. Gio's g_volume_monitor_get_volumes() в строках 1139 и g_volume_monitor_get_mounts () 1164 выбирает тома, которые могут быть не связаны с диском (например, ftp или сетевые ресурсы), но эта же информация передается add_volume() функция и add_mount().

  2. Значки запрашиваются для точек монтирования и томов : внутри функции add_volume(), функция Gio's g_volume_get_icon() выбирает значок типа GIcon. Внутри add_mount() Gio's g_mount_get_icon() также типа GIcon. В обоих случаях значок вместе с другой информацией объединяются в объект типа NAUTILUS_TYPE_GTK_PLACES_VIEW_ROW и передаются в insert_row() функцию

  3. Строки, вставленные в контейнер 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, что намного проще и проще.

Пример Python

Вот простое окно, которое использует интерфейс Gio Drive для создания кнопок со значками, соответствующими подключенным дискам. Это слишком упрощенно и требует доработки, а также встроенные комментарии

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, но используется внутри функции обновления панели пути . Пойди разберись, верно? ¯\_(ツ)_/¯


Добро пожаловать на сайт proUbuntu, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...