Как Наутилус решает, какую иконку использовать?

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

https://i.s tack.imgur.com/KerHO.png

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

1 ответ

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 (хотя мой подход отличается от того, что делает Nautilus).

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

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

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

  2. Значки запрашиваются для точек монтирования и томов: Внутри add_volume() функция, Гио g_volume_get_icon() функция выбирает значок типа GIcon, внутри add_mount() Гио 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()

Более простой подход

Конечно, в настоящее время вам не нужно изобретать велосипед. ГТК обеспечивает 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()

Примечание: Наутилус также имеет заголовочный файл nautilus-icon-names.h, который определяет константы с NAUTILUS_ префикс, такой как

#define NAUTILUS_ICON_FILESYSTEM    "drive-harddisk-symbolic"

вероятно, для согласованности между разработчиком и кодом, вместо того, чтобы полагаться на поиск реальных имен значков. Единственное место, где это конкретное определение используется в get_icon функция, и эта функция по иронии судьбы не используется для боковой панели Places, но используется внутри функции обновления панели пути. Пойди разберись, верно? ¯\_(ツ)_/¯


Другие вопросы по тегам