Nautilus 如何决定使用哪个图标?

Nautilus 如何决定使用哪个图标?

这是我的 Nautilus 窗口的侧边栏。您可以看到两个不同的图标 - 一个用于 USB 记忆棒,一个用于驱动器。

nautilus 如何确定哪个获得硬盘驱动器图标以及哪个获得闪存驱动器图标?

答案1

总结: Nautilus 用途Gio 的 GDrive、GVolume 和 GVolumeMonitor 接口来获取特定设备对应的图标。

Gio 的 API、驱动器和图标

Gio 有一组类,允许应用程序读取可用的驱动器和卷,以及与它们关联的图标(这是 API 已经处理的事情)。图标作为Gio Icon类型返回,因此应用程序不必特别知道图标的位置,但是始终可以通过名称或完整路径请求图标。您将看到两种类型的图标,“符号”和自定义,“符号”图标是标准的。如果仔细查看,/usr/share/icons他们会发现有很多图标以 结尾-symbolic,存储在多个主题文件夹中(标准 Adwaita、Humanity 和 Oxygen 就是很好的例子),通常是.svg文件。在问题的屏幕截图中,硬盘驱动器的图标是drive-harddisk-symbolicdrive-removable-media-usb。当用户切换桌面主题时,应用程序不必查找图标的完整路径 - 只要drive-harddisk-symbolic主题文件夹中有图标,Gio 就会找到它并返回到应用程序。我怎么知道这一切的?我已经将相同的图标用于我自己的U盘指示灯(尽管我的方法与 Nautilus 不同)。

Nautilus 如何使用 Gio 的 API

通过阅读 Nautilus 源代码,具体来说nautilusgtkplacesview.c代码中,必要部分如下:

  1. Nautilus 添加驱动器和卷(想想分区)。添加驱动器函数,它使用 Gio 的 g_drive_get_volumes (drive)函数获取特定驱动器上的卷,并将该信息传递给 Nautilus 的add_volume() 函数。Gio 的g_volume_monitor_get_volumes()在第 1139 行和复制代码1164 获取可能不与驱动器关联的卷(例如 ftp 或网络共享),但相同的信息将用于add_volume()功能和add_mount()

  2. 查询图标以获取挂载点和卷: 内部add_volume()功能,Gio'sg_volume_get_icon()功能获取类型的图标GIcon。在add_mount()Gio 的g_mount_get_icon()也是 类型GIcon。在这两种情况下,图标与其他信息都组合成 类型的对象。NAUTILUS_TYPE_GTK_PLACES_VIEW_ROW并传递给insert_row()函数

  3. 插入到位置容器中的行:您在示例中展示的 Places 菜单实际上是 Gtk 基本容器类型之一 - Gtk Box。该框内有用于子部分的 ListBox - 这就是为什么所有用户的文件夹、驱动器和卷以及书签都有分隔符。Nautilus 创建一个从 Gtk Box 类型扩展的对象,G_DEFINE_TYPE_WITH_PRIVATE (NautilusGtkPlacesView, nautilus_gtk_places_view, GTK_TYPE_BOX) 。G_DEFINE_TYPE_WITH_PRIVATE 是另一个标准函数,正如您在 Nautilus 的定义中看到的那样,最后一项定义了GTK_TYPE_BOX- 父对象。.c第 50 行NautilusGtkPlacesViewPrivate定义了结构,其中包括指向 ListView 小部件的指针。这就是对象的实际内容。

    现在,insert_row()功能获取该类型的实例(NautilusGtkPlacesView *view),将整个信号束连接到它作为参数接收的行项,并使用gtk_container_add将所有信息(连同图标)插入到 Nautilus Places 对象的 ListBox 小部件中。

冗长的解释,在图表中可能看起来更简单,但这都是用 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()

旁注:Nautilus 也有一个头文件鹦鹉螺图标名称.h定义带NAUTILUS_前缀的常量,例如

#define NAUTILUS_ICON_FILESYSTEM    "drive-harddisk-symbolic"

可能是为了开发人员/代码的一致性,而不是必须依赖查找实际的图标名称。唯一使用该特定定义的地方是get_icon功能,讽刺的是,该功能不用于地点侧栏,而是用于内部路径栏更新函数。想想看,对吧?¯\_(ツ)_/¯


相关内容