web-dev-qa-db-fra.com

Comment Nautilus décide-t-il quelle icône utiliser?

Ceci est la barre latérale de ma fenêtre nautilus. Vous pouvez voir deux icônes différentes - une pour les clés USB et une pour les lecteurs.

Comment Nautilus détermine-t-il celui qui obtient une icône de disque dur et celui qui obtient une clé USB?

6
Tim

TL; DR : Nautilus utilise les interfaces Gio's GDrive, GVolume et GVolumeMonitor pour obtenir des icônes correspondant à un appareil particulier.

API, lecteurs et icônes de Gio

Gio a un ensemble de classes qui permettent aux applications de lire les lecteurs et volumes disponibles, et quelles icônes leur sont associées (et c'est quelque chose que l'API gère déjà). Les icônes sont renvoyées sous la forme Gio Icon, Les applications n'ont donc pas particulièrement besoin de savoir où se trouve l'icône, mais il est toujours possible de demander une icône par nom ou par chemin complet. Il y a deux types d'icônes que vous verrez, les icônes "symboliques" et personnalisées, et les icônes "symboliques" sont en quelque sorte standard. Si l'on regarde /usr/share/icons, Ils trouveront qu'il y a beaucoup d'icônes qui se terminent par -symbolic Dans leur nom, stockées dans plusieurs dossiers thématiques (Adwaita, Humanity et Oxygen standard sont de bons exemples), généralement .svg fichiers. Dans la capture d'écran de la question, l'icône du disque dur est drive-harddisk-symbolic Et drive-removable-media-usb. Lorsque l'utilisateur change de thème de bureau, l'application n'a pas à rechercher le chemin d'accès complet à l'icône - tant qu'il y a une icône drive-harddisk-symbolic Dans le dossier du thème, le Gio le trouvera et retournera à l'application. Comment puis-je savoir tout cela? J'ai utilisé ces mêmes icônes pour moi Disks Indicator (bien que mon approche diffère de ce que fait Nautilus).

Comment Nautilus utilise l'API de Gio

De la lecture du code source Nautilus, en particulier nautilusgtkplacesview.c code, les parties essentielles sont les suivantes:

  1. Nautilus ajoute des lecteurs et des volumes (pensez aux partitions). Il y a la fonction add_drive , qui utilise la fonction g_drive_get_volumes (drive) de Gio pour obtenir des volumes sur un lecteur spécifique, et transmet ces informations à la fonction add_volume() de Nautilus. g_volume_monitor_get_volumes() sur les lignes 1139 et g_volume_monitor_get_mounts () 1164 récupère les volumes qui ne peuvent pas être associés à un lecteur (comme ftp ou partages réseau), mais cette même information va à add_volume() fonction et add_mount() .

  2. Des icônes sont demandées pour les points de montage et les volumes : À l'intérieur de la fonction add_volume(), de Gio g_volume_get_icon() fonction récupère l'icône de type GIcon. À l'intérieur de add_mount() Gio's g_mount_get_icon() également de type GIcon. Dans les deux cas, l'icône et d'autres informations sont combinées en un objet de type NAUTILUS_TYPE_GTK_PLACES_VIEW_ROW et transmises à la fonction insert_row()

  3. Lignes insérées dans le conteneur Places : Le menu Places que vous montrez dans l'exemple est en fait l'un des types de conteneurs Gtk de base - Gtk Box. À l'intérieur de cette boîte, il y a ListBox pour les sous-sections - c'est pourquoi il y a des séparateurs pour tous les dossiers, lecteurs et volumes de l'utilisateur et les signets. Nautilus crée un objet qui s'étend du type Gtk Box, G_DEFINE_TYPE_WITH_PRIVATE (NautilusGtkPlacesView, nautilus_gtk_places_view, GTK_TYPE_BOX) . Le G_DEFINE_TYPE_WITH_PRIVATE est ne autre fonction standard , et comme vous pouvez le voir dans la définition de Nautilus, le dernier élément définit GTK_TYPE_BOX - objet parent. Dans le fichier .c Sur ligne 5 , la structure NautilusGtkPlacesViewPrivate est définie, qui a entre autres un pointeur sur le widget ListView. C'est le contenu réel de l'objet.

    Maintenant, insert_row() fonction prend une instance de ce type (NautilusGtkPlacesView *view), Connecte tout un tas de signaux à l'élément de ligne qu'il a reçu comme argument, et utilise gtk_container_add insère toutes les informations (ainsi que l'icône) dans le widget ListBox de l'objet Nautilus Places.

Une longue explication et semble probablement plus simple dans un diagramme, mais aussi tout est écrit en C. Essayons de faire quelque chose nous-mêmes en Python qui est de loin plus simple et plus facile.

Exemple Python

Voici une fenêtre simple qui utilise l'interface Drive de Gio pour créer des boutons avec des icônes correspondant aux lecteurs connectés. C'est trop simpliste et a besoin d'être poli, et de commentaires en ligne

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()

Une approche plus simple

Bien sûr, de nos jours, vous n'avez pas à réinventer la roue. Gtk fournit PlacesSidebar widget.

#!/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 a également un fichier d'en-tête nautilus-icon-names.h qui définit les constantes avec le préfixe NAUTILUS_, Telles que

#define NAUTILUS_ICON_FILESYSTEM    "drive-harddisk-symbolic"

probablement pour la cohérence développeur/code, au lieu de devoir compter sur la recherche des noms d'icônes réels. Le seul endroit où cette définition particulière est utilisée est dans fonction get_icon , et cette fonction n'est ironiquement pas utilisée pour la barre latérale Lieux mais est utilisée dans la fonction de mise à jour de la barre de chemin) =. Allez comprendre, non? ¯\_(ツ)_/¯


4