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

Tim*_*Tim 6 icons nautilus

这是我的鹦鹉螺窗口的侧边栏。您可以看到两种不同的图标 - 一种用于 U 盘,一种用于驱动器。

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

Ser*_*nyy 4

TL;DR:Nautilus 使用Gio 的 GDrive、GVolume 和 GVolumeMonitor 接口来获取与特定设备相对应的图标。

\n\n

Gio 的 API、驱动器和图标

\n\n

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

\n\n

Nautilus 如何使用 Gio 的 api

\n\n

通过阅读Nautilus源代码,特别是nautilusgtkplacesview.c代码,基本部分如下:

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

  2. \n
  3. 查询图标的安装点和卷:在add_volume()函数内部,Gio 的g_volume_get_icon()函数获取类型的图标GIconadd_mount()Gio内部g_mount_get_icon()也属于 类型GIcon。在这两种情况下,图标与其他信息一起组合成类型的对象NAUTILUS_TYPE_GTK_PLACES_VIEW_ROW并传递给insert_row()函数

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

    \n\n

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

  6. \n
\n\n

冗长的解释,可能在图表中看起来更简单,但这些都是用 C 编写的。让我们尝试用 Python 自己做一些东西,它迄今为止更简单、更容易。

\n\n

Python示例

\n\n

这是一个简单的窗口,它利用 Gio 的驱动器界面来创建带有与所连接驱动器相对应的图标的按钮。这过于简单化,需要完善和内嵌注释

\n\n
import gi\ngi.require_version(\'Gtk\', \'3.0\')\nfrom gi.repository import Gio,Gtk\n\nclass drives_window(Gtk.Window):\n    def __init__(self):\n        super().__init__(title="Foobar")\n        self.volume_monitor = Gio.VolumeMonitor.get()\n        # We\'ll use Gtk.Box to hold all the buttons corresponding to each drive\n        # although we haven\'t connected the buttons to any other function\n        # so clicking on the does nothing\n        self.box = Gtk.Box()\n        for drive in self.volume_monitor.get_connected_drives():\n            button = Gtk.Button()\n            button.set_label(drive.get_name())  \n            button.set_always_show_image(True)\n            icon = drive.get_symbolic_icon()\n            # buttons need Gtk.Image widget, but .get_symbolic_icon() returns Gio.ThemedIcon\n            # so we create new Gtk.Image using .new_From_gicon() function\n            # Gtk.IconSize.BUTTON is a constant\n            button.set_image(Gtk.Image.new_from_gicon(icon,Gtk.IconSize.BUTTON))\n            self.box.pack_start(button,True,True,0)\n        # add the box container to this window\n        self.add(self.box)\n\nwindow = drives_window()\nwindow.connect("destroy",Gtk.main_quit)\nwindow.show_all()\nGtk.main()\n
Run Code Online (Sandbox Code Playgroud)\n\n

更简单的方法

\n\n

当然,如今您不必重新发明轮子。GTk提供了PlacesSidebarwidget。

\n\n
#!/usr/bin/env python3\nfrom gi.repository import Gtk,Gio,GLib\n\nw = Gtk.Window()\nb1 = Gtk.Box()\np = Gtk.PlacesSidebar()\nb1.pack_start(p,True,True,0)\nb1.pack_start(Gtk.Button("Hello World"),True,True,0)\nb1.pack_start(Gtk.Button("Hello World 2"),True,True,0)\n\nw.add(b1)\nw..connect("destroy",Gtk.main_quit)\nw.show_all()\n\nGtk.main()\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

旁注:Nautilus 还有一个头文件nautilus-icon-names.h,它定义了带有前缀的常量NAUTILUS_,例如

\n\n
#define NAUTILUS_ICON_FILESYSTEM    "drive-harddisk-symbolic"\n
Run Code Online (Sandbox Code Playgroud)\n\n

\n可能是为了开发人员/代码的一致性,而不必依赖于查找实际的图标名称。使用该特定定义的唯一地方是在get_icon函数中,具有讽刺意味的是,该函数不用于 Places 侧栏,而是在路径栏更新函数中使用。想想看,对吧?\xc2\xaf\\_(\xe3\x83\x84)_/\xc2\xaf

\n\n

\n\n


\n