How does Nautilus decide which icon to use?












6















This is the sidebar of my nautilus window. You can see two different icons - one for the USB sticks and one for drives.





How does nautilus determine which gets a hard drive icon and which gets a flash drive one?










share|improve this question























  • This is a very interesting question, especially since I have a flash drive that shows up with a Smart Media icon... (thngs-images.s3.amazonaws.com/archive/012/153/original/…)

    – Android Dev
    Jan 4 '17 at 16:50













  • The 2 8GB Volumes in my image are flash drives plugged in via a USB hub - I assume that's why they appear as HDDs not as flash drives.

    – Tim
    Jan 4 '17 at 16:55











  • @AndroidDev It could have been either a bug or Gio simply couldn't determine the icon for the volume, so it made next best guess for removable media. It could also be something about the drive itself or the filesystem on the drive ( if its got NTFS, likely Gio would treat it as a drive rather than removable device )

    – Sergiy Kolodyazhnyy
    yesterday
















6















This is the sidebar of my nautilus window. You can see two different icons - one for the USB sticks and one for drives.





How does nautilus determine which gets a hard drive icon and which gets a flash drive one?










share|improve this question























  • This is a very interesting question, especially since I have a flash drive that shows up with a Smart Media icon... (thngs-images.s3.amazonaws.com/archive/012/153/original/…)

    – Android Dev
    Jan 4 '17 at 16:50













  • The 2 8GB Volumes in my image are flash drives plugged in via a USB hub - I assume that's why they appear as HDDs not as flash drives.

    – Tim
    Jan 4 '17 at 16:55











  • @AndroidDev It could have been either a bug or Gio simply couldn't determine the icon for the volume, so it made next best guess for removable media. It could also be something about the drive itself or the filesystem on the drive ( if its got NTFS, likely Gio would treat it as a drive rather than removable device )

    – Sergiy Kolodyazhnyy
    yesterday














6












6








6


1






This is the sidebar of my nautilus window. You can see two different icons - one for the USB sticks and one for drives.





How does nautilus determine which gets a hard drive icon and which gets a flash drive one?










share|improve this question














This is the sidebar of my nautilus window. You can see two different icons - one for the USB sticks and one for drives.





How does nautilus determine which gets a hard drive icon and which gets a flash drive one?







nautilus icons






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Jan 4 '17 at 16:49









TimTim

20k1586141




20k1586141













  • This is a very interesting question, especially since I have a flash drive that shows up with a Smart Media icon... (thngs-images.s3.amazonaws.com/archive/012/153/original/…)

    – Android Dev
    Jan 4 '17 at 16:50













  • The 2 8GB Volumes in my image are flash drives plugged in via a USB hub - I assume that's why they appear as HDDs not as flash drives.

    – Tim
    Jan 4 '17 at 16:55











  • @AndroidDev It could have been either a bug or Gio simply couldn't determine the icon for the volume, so it made next best guess for removable media. It could also be something about the drive itself or the filesystem on the drive ( if its got NTFS, likely Gio would treat it as a drive rather than removable device )

    – Sergiy Kolodyazhnyy
    yesterday



















  • This is a very interesting question, especially since I have a flash drive that shows up with a Smart Media icon... (thngs-images.s3.amazonaws.com/archive/012/153/original/…)

    – Android Dev
    Jan 4 '17 at 16:50













  • The 2 8GB Volumes in my image are flash drives plugged in via a USB hub - I assume that's why they appear as HDDs not as flash drives.

    – Tim
    Jan 4 '17 at 16:55











  • @AndroidDev It could have been either a bug or Gio simply couldn't determine the icon for the volume, so it made next best guess for removable media. It could also be something about the drive itself or the filesystem on the drive ( if its got NTFS, likely Gio would treat it as a drive rather than removable device )

    – Sergiy Kolodyazhnyy
    yesterday

















This is a very interesting question, especially since I have a flash drive that shows up with a Smart Media icon... (thngs-images.s3.amazonaws.com/archive/012/153/original/…)

– Android Dev
Jan 4 '17 at 16:50







This is a very interesting question, especially since I have a flash drive that shows up with a Smart Media icon... (thngs-images.s3.amazonaws.com/archive/012/153/original/…)

– Android Dev
Jan 4 '17 at 16:50















The 2 8GB Volumes in my image are flash drives plugged in via a USB hub - I assume that's why they appear as HDDs not as flash drives.

– Tim
Jan 4 '17 at 16:55





The 2 8GB Volumes in my image are flash drives plugged in via a USB hub - I assume that's why they appear as HDDs not as flash drives.

– Tim
Jan 4 '17 at 16:55













@AndroidDev It could have been either a bug or Gio simply couldn't determine the icon for the volume, so it made next best guess for removable media. It could also be something about the drive itself or the filesystem on the drive ( if its got NTFS, likely Gio would treat it as a drive rather than removable device )

– Sergiy Kolodyazhnyy
yesterday





@AndroidDev It could have been either a bug or Gio simply couldn't determine the icon for the volume, so it made next best guess for removable media. It could also be something about the drive itself or the filesystem on the drive ( if its got NTFS, likely Gio would treat it as a drive rather than removable device )

– Sergiy Kolodyazhnyy
yesterday










1 Answer
1






active

oldest

votes


















4














TL;DR: Nautilus uses Gio's GDrive,GVolume, and GVolumeMonitor interfaces to obtain icons corresponding to particular device.



Gio's API, drives and icons



Gio has set of classes which allow applications to read available drives and volumes, and what icons are associated to them (and that's something API already handles). The icons are returned as Gio Icon type, so applications don't particularly have to know where the icon is located, however requesting an icon by name or by full path is always possible. There's two types of icons you will see, "symbolic" and custom, and "symbolic" icons are sort of standard. If one looks through /usr/share/icons they'll find there are lots of icons that end with -symbolic in their name, stored across multiple theme folders (standard Adwaita, Humanity, and Oxygen are good examples) , typically .svg files. In the screenshot in the question, the icon for hard drive is drive-harddisk-symbolic and drive-removable-media-usb. When user switches desktop theme, the application doesn't have to look up full path to the icon - so long as there is drive-harddisk-symbolic icon in the theme folder, the Gio will find it and return to the application. How do I know all this ? I've used those same icons for my own UDisks Indicator (though my approach differs from what Nautilus does).



How Nautilus utilizes Gio's api



From reading Nautilus source code, specifically nautilusgtkplacesview.c code, essential parts are the following:




  1. Nautilus adds drives and volumes (think partitions). There's add_drive function, which uses Gio's g_drive_get_volumes (drive) function to get volumes on specific drive, and passes that information to Nautilus's add_volume() function. Gio's g_volume_monitor_get_volumes() on lines 1139 and g_volume_monitor_get_mounts() 1164 fetches volumes that may not be associated with a drive (such as ftp or network shares), but that same information goes to add_volume() function and add_mount().


  2. Icons are queried for mountpoints and volumes: Inside add_volume() function, Gio's g_volume_get_icon() function fetches the icon of type GIcon. Inside add_mount() Gio's g_mount_get_icon() also of type GIcon. In both cases, icon along with other information are combined into an object of type NAUTILUS_TYPE_GTK_PLACES_VIEW_ROW and passed to insert_row() function



  3. Rows inserted into Places container: The Places menu that you show in the example actually is one of the basic Gtk container types - Gtk Box. Inside that box there's ListBox for subsections - that's why there's separators for all user's folders, drives and volumes, and bookmarks. Nautilus creates an object which extends from Gtk Box type, G_DEFINE_TYPE_WITH_PRIVATE (NautilusGtkPlacesView, nautilus_gtk_places_view, GTK_TYPE_BOX)
    . The G_DEFINE_TYPE_WITH_PRIVATE is another standard function , and as you can see in Nautilus's definition the last item defines GTK_TYPE_BOX - parent object. In the .c file on line 50, NautilusGtkPlacesViewPrivate structure is defined, which among other things has pointer to ListView widget. That's the actual contents of the object.



    Now, insert_row() function takes instance of that type (NautilusGtkPlacesView *view), connects whole bunch of signals to the row item it received as argument, and using gtk_container_add inserts all the information ( along with the icon ) into the ListBox widget of the Nautilus Places object.




Lengthy explanation and probably looks simpler in a diagram, but also that's all written in C. Let's try to make something ourselves in Python which is by far simpler and easier.



Python example



Here's a simple window that utilizes Gio's Drive interface to create buttons with icons corresponding to the attached drives. This is overly simplistic and needs polish, and inline-comments



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


Simpler approach



Of course nowadays you don't have to reinvent the wheel. Gtk provides 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 also has a header file nautilus-icon-names.h which defines constants with NAUTILUS_ prefix, such as



#define NAUTILUS_ICON_FILESYSTEM    "drive-harddisk-symbolic"



probably for developer/code consistency, instead of having to rely on looking up actual icon names. The only place where that particular definition is used is in get_icon function, and that function ironically is not used for Places side bar but is used inside pathbar updating function. Go figure,right ? ¯_(ツ)_/¯











share|improve this answer

























    Your Answer








    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "89"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2faskubuntu.com%2fquestions%2f867997%2fhow-does-nautilus-decide-which-icon-to-use%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    4














    TL;DR: Nautilus uses Gio's GDrive,GVolume, and GVolumeMonitor interfaces to obtain icons corresponding to particular device.



    Gio's API, drives and icons



    Gio has set of classes which allow applications to read available drives and volumes, and what icons are associated to them (and that's something API already handles). The icons are returned as Gio Icon type, so applications don't particularly have to know where the icon is located, however requesting an icon by name or by full path is always possible. There's two types of icons you will see, "symbolic" and custom, and "symbolic" icons are sort of standard. If one looks through /usr/share/icons they'll find there are lots of icons that end with -symbolic in their name, stored across multiple theme folders (standard Adwaita, Humanity, and Oxygen are good examples) , typically .svg files. In the screenshot in the question, the icon for hard drive is drive-harddisk-symbolic and drive-removable-media-usb. When user switches desktop theme, the application doesn't have to look up full path to the icon - so long as there is drive-harddisk-symbolic icon in the theme folder, the Gio will find it and return to the application. How do I know all this ? I've used those same icons for my own UDisks Indicator (though my approach differs from what Nautilus does).



    How Nautilus utilizes Gio's api



    From reading Nautilus source code, specifically nautilusgtkplacesview.c code, essential parts are the following:




    1. Nautilus adds drives and volumes (think partitions). There's add_drive function, which uses Gio's g_drive_get_volumes (drive) function to get volumes on specific drive, and passes that information to Nautilus's add_volume() function. Gio's g_volume_monitor_get_volumes() on lines 1139 and g_volume_monitor_get_mounts() 1164 fetches volumes that may not be associated with a drive (such as ftp or network shares), but that same information goes to add_volume() function and add_mount().


    2. Icons are queried for mountpoints and volumes: Inside add_volume() function, Gio's g_volume_get_icon() function fetches the icon of type GIcon. Inside add_mount() Gio's g_mount_get_icon() also of type GIcon. In both cases, icon along with other information are combined into an object of type NAUTILUS_TYPE_GTK_PLACES_VIEW_ROW and passed to insert_row() function



    3. Rows inserted into Places container: The Places menu that you show in the example actually is one of the basic Gtk container types - Gtk Box. Inside that box there's ListBox for subsections - that's why there's separators for all user's folders, drives and volumes, and bookmarks. Nautilus creates an object which extends from Gtk Box type, G_DEFINE_TYPE_WITH_PRIVATE (NautilusGtkPlacesView, nautilus_gtk_places_view, GTK_TYPE_BOX)
      . The G_DEFINE_TYPE_WITH_PRIVATE is another standard function , and as you can see in Nautilus's definition the last item defines GTK_TYPE_BOX - parent object. In the .c file on line 50, NautilusGtkPlacesViewPrivate structure is defined, which among other things has pointer to ListView widget. That's the actual contents of the object.



      Now, insert_row() function takes instance of that type (NautilusGtkPlacesView *view), connects whole bunch of signals to the row item it received as argument, and using gtk_container_add inserts all the information ( along with the icon ) into the ListBox widget of the Nautilus Places object.




    Lengthy explanation and probably looks simpler in a diagram, but also that's all written in C. Let's try to make something ourselves in Python which is by far simpler and easier.



    Python example



    Here's a simple window that utilizes Gio's Drive interface to create buttons with icons corresponding to the attached drives. This is overly simplistic and needs polish, and inline-comments



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


    Simpler approach



    Of course nowadays you don't have to reinvent the wheel. Gtk provides 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 also has a header file nautilus-icon-names.h which defines constants with NAUTILUS_ prefix, such as



    #define NAUTILUS_ICON_FILESYSTEM    "drive-harddisk-symbolic"



    probably for developer/code consistency, instead of having to rely on looking up actual icon names. The only place where that particular definition is used is in get_icon function, and that function ironically is not used for Places side bar but is used inside pathbar updating function. Go figure,right ? ¯_(ツ)_/¯











    share|improve this answer






























      4














      TL;DR: Nautilus uses Gio's GDrive,GVolume, and GVolumeMonitor interfaces to obtain icons corresponding to particular device.



      Gio's API, drives and icons



      Gio has set of classes which allow applications to read available drives and volumes, and what icons are associated to them (and that's something API already handles). The icons are returned as Gio Icon type, so applications don't particularly have to know where the icon is located, however requesting an icon by name or by full path is always possible. There's two types of icons you will see, "symbolic" and custom, and "symbolic" icons are sort of standard. If one looks through /usr/share/icons they'll find there are lots of icons that end with -symbolic in their name, stored across multiple theme folders (standard Adwaita, Humanity, and Oxygen are good examples) , typically .svg files. In the screenshot in the question, the icon for hard drive is drive-harddisk-symbolic and drive-removable-media-usb. When user switches desktop theme, the application doesn't have to look up full path to the icon - so long as there is drive-harddisk-symbolic icon in the theme folder, the Gio will find it and return to the application. How do I know all this ? I've used those same icons for my own UDisks Indicator (though my approach differs from what Nautilus does).



      How Nautilus utilizes Gio's api



      From reading Nautilus source code, specifically nautilusgtkplacesview.c code, essential parts are the following:




      1. Nautilus adds drives and volumes (think partitions). There's add_drive function, which uses Gio's g_drive_get_volumes (drive) function to get volumes on specific drive, and passes that information to Nautilus's add_volume() function. Gio's g_volume_monitor_get_volumes() on lines 1139 and g_volume_monitor_get_mounts() 1164 fetches volumes that may not be associated with a drive (such as ftp or network shares), but that same information goes to add_volume() function and add_mount().


      2. Icons are queried for mountpoints and volumes: Inside add_volume() function, Gio's g_volume_get_icon() function fetches the icon of type GIcon. Inside add_mount() Gio's g_mount_get_icon() also of type GIcon. In both cases, icon along with other information are combined into an object of type NAUTILUS_TYPE_GTK_PLACES_VIEW_ROW and passed to insert_row() function



      3. Rows inserted into Places container: The Places menu that you show in the example actually is one of the basic Gtk container types - Gtk Box. Inside that box there's ListBox for subsections - that's why there's separators for all user's folders, drives and volumes, and bookmarks. Nautilus creates an object which extends from Gtk Box type, G_DEFINE_TYPE_WITH_PRIVATE (NautilusGtkPlacesView, nautilus_gtk_places_view, GTK_TYPE_BOX)
        . The G_DEFINE_TYPE_WITH_PRIVATE is another standard function , and as you can see in Nautilus's definition the last item defines GTK_TYPE_BOX - parent object. In the .c file on line 50, NautilusGtkPlacesViewPrivate structure is defined, which among other things has pointer to ListView widget. That's the actual contents of the object.



        Now, insert_row() function takes instance of that type (NautilusGtkPlacesView *view), connects whole bunch of signals to the row item it received as argument, and using gtk_container_add inserts all the information ( along with the icon ) into the ListBox widget of the Nautilus Places object.




      Lengthy explanation and probably looks simpler in a diagram, but also that's all written in C. Let's try to make something ourselves in Python which is by far simpler and easier.



      Python example



      Here's a simple window that utilizes Gio's Drive interface to create buttons with icons corresponding to the attached drives. This is overly simplistic and needs polish, and inline-comments



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


      Simpler approach



      Of course nowadays you don't have to reinvent the wheel. Gtk provides 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 also has a header file nautilus-icon-names.h which defines constants with NAUTILUS_ prefix, such as



      #define NAUTILUS_ICON_FILESYSTEM    "drive-harddisk-symbolic"



      probably for developer/code consistency, instead of having to rely on looking up actual icon names. The only place where that particular definition is used is in get_icon function, and that function ironically is not used for Places side bar but is used inside pathbar updating function. Go figure,right ? ¯_(ツ)_/¯











      share|improve this answer




























        4












        4








        4







        TL;DR: Nautilus uses Gio's GDrive,GVolume, and GVolumeMonitor interfaces to obtain icons corresponding to particular device.



        Gio's API, drives and icons



        Gio has set of classes which allow applications to read available drives and volumes, and what icons are associated to them (and that's something API already handles). The icons are returned as Gio Icon type, so applications don't particularly have to know where the icon is located, however requesting an icon by name or by full path is always possible. There's two types of icons you will see, "symbolic" and custom, and "symbolic" icons are sort of standard. If one looks through /usr/share/icons they'll find there are lots of icons that end with -symbolic in their name, stored across multiple theme folders (standard Adwaita, Humanity, and Oxygen are good examples) , typically .svg files. In the screenshot in the question, the icon for hard drive is drive-harddisk-symbolic and drive-removable-media-usb. When user switches desktop theme, the application doesn't have to look up full path to the icon - so long as there is drive-harddisk-symbolic icon in the theme folder, the Gio will find it and return to the application. How do I know all this ? I've used those same icons for my own UDisks Indicator (though my approach differs from what Nautilus does).



        How Nautilus utilizes Gio's api



        From reading Nautilus source code, specifically nautilusgtkplacesview.c code, essential parts are the following:




        1. Nautilus adds drives and volumes (think partitions). There's add_drive function, which uses Gio's g_drive_get_volumes (drive) function to get volumes on specific drive, and passes that information to Nautilus's add_volume() function. Gio's g_volume_monitor_get_volumes() on lines 1139 and g_volume_monitor_get_mounts() 1164 fetches volumes that may not be associated with a drive (such as ftp or network shares), but that same information goes to add_volume() function and add_mount().


        2. Icons are queried for mountpoints and volumes: Inside add_volume() function, Gio's g_volume_get_icon() function fetches the icon of type GIcon. Inside add_mount() Gio's g_mount_get_icon() also of type GIcon. In both cases, icon along with other information are combined into an object of type NAUTILUS_TYPE_GTK_PLACES_VIEW_ROW and passed to insert_row() function



        3. Rows inserted into Places container: The Places menu that you show in the example actually is one of the basic Gtk container types - Gtk Box. Inside that box there's ListBox for subsections - that's why there's separators for all user's folders, drives and volumes, and bookmarks. Nautilus creates an object which extends from Gtk Box type, G_DEFINE_TYPE_WITH_PRIVATE (NautilusGtkPlacesView, nautilus_gtk_places_view, GTK_TYPE_BOX)
          . The G_DEFINE_TYPE_WITH_PRIVATE is another standard function , and as you can see in Nautilus's definition the last item defines GTK_TYPE_BOX - parent object. In the .c file on line 50, NautilusGtkPlacesViewPrivate structure is defined, which among other things has pointer to ListView widget. That's the actual contents of the object.



          Now, insert_row() function takes instance of that type (NautilusGtkPlacesView *view), connects whole bunch of signals to the row item it received as argument, and using gtk_container_add inserts all the information ( along with the icon ) into the ListBox widget of the Nautilus Places object.




        Lengthy explanation and probably looks simpler in a diagram, but also that's all written in C. Let's try to make something ourselves in Python which is by far simpler and easier.



        Python example



        Here's a simple window that utilizes Gio's Drive interface to create buttons with icons corresponding to the attached drives. This is overly simplistic and needs polish, and inline-comments



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


        Simpler approach



        Of course nowadays you don't have to reinvent the wheel. Gtk provides 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 also has a header file nautilus-icon-names.h which defines constants with NAUTILUS_ prefix, such as



        #define NAUTILUS_ICON_FILESYSTEM    "drive-harddisk-symbolic"



        probably for developer/code consistency, instead of having to rely on looking up actual icon names. The only place where that particular definition is used is in get_icon function, and that function ironically is not used for Places side bar but is used inside pathbar updating function. Go figure,right ? ¯_(ツ)_/¯











        share|improve this answer















        TL;DR: Nautilus uses Gio's GDrive,GVolume, and GVolumeMonitor interfaces to obtain icons corresponding to particular device.



        Gio's API, drives and icons



        Gio has set of classes which allow applications to read available drives and volumes, and what icons are associated to them (and that's something API already handles). The icons are returned as Gio Icon type, so applications don't particularly have to know where the icon is located, however requesting an icon by name or by full path is always possible. There's two types of icons you will see, "symbolic" and custom, and "symbolic" icons are sort of standard. If one looks through /usr/share/icons they'll find there are lots of icons that end with -symbolic in their name, stored across multiple theme folders (standard Adwaita, Humanity, and Oxygen are good examples) , typically .svg files. In the screenshot in the question, the icon for hard drive is drive-harddisk-symbolic and drive-removable-media-usb. When user switches desktop theme, the application doesn't have to look up full path to the icon - so long as there is drive-harddisk-symbolic icon in the theme folder, the Gio will find it and return to the application. How do I know all this ? I've used those same icons for my own UDisks Indicator (though my approach differs from what Nautilus does).



        How Nautilus utilizes Gio's api



        From reading Nautilus source code, specifically nautilusgtkplacesview.c code, essential parts are the following:




        1. Nautilus adds drives and volumes (think partitions). There's add_drive function, which uses Gio's g_drive_get_volumes (drive) function to get volumes on specific drive, and passes that information to Nautilus's add_volume() function. Gio's g_volume_monitor_get_volumes() on lines 1139 and g_volume_monitor_get_mounts() 1164 fetches volumes that may not be associated with a drive (such as ftp or network shares), but that same information goes to add_volume() function and add_mount().


        2. Icons are queried for mountpoints and volumes: Inside add_volume() function, Gio's g_volume_get_icon() function fetches the icon of type GIcon. Inside add_mount() Gio's g_mount_get_icon() also of type GIcon. In both cases, icon along with other information are combined into an object of type NAUTILUS_TYPE_GTK_PLACES_VIEW_ROW and passed to insert_row() function



        3. Rows inserted into Places container: The Places menu that you show in the example actually is one of the basic Gtk container types - Gtk Box. Inside that box there's ListBox for subsections - that's why there's separators for all user's folders, drives and volumes, and bookmarks. Nautilus creates an object which extends from Gtk Box type, G_DEFINE_TYPE_WITH_PRIVATE (NautilusGtkPlacesView, nautilus_gtk_places_view, GTK_TYPE_BOX)
          . The G_DEFINE_TYPE_WITH_PRIVATE is another standard function , and as you can see in Nautilus's definition the last item defines GTK_TYPE_BOX - parent object. In the .c file on line 50, NautilusGtkPlacesViewPrivate structure is defined, which among other things has pointer to ListView widget. That's the actual contents of the object.



          Now, insert_row() function takes instance of that type (NautilusGtkPlacesView *view), connects whole bunch of signals to the row item it received as argument, and using gtk_container_add inserts all the information ( along with the icon ) into the ListBox widget of the Nautilus Places object.




        Lengthy explanation and probably looks simpler in a diagram, but also that's all written in C. Let's try to make something ourselves in Python which is by far simpler and easier.



        Python example



        Here's a simple window that utilizes Gio's Drive interface to create buttons with icons corresponding to the attached drives. This is overly simplistic and needs polish, and inline-comments



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


        Simpler approach



        Of course nowadays you don't have to reinvent the wheel. Gtk provides 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 also has a header file nautilus-icon-names.h which defines constants with NAUTILUS_ prefix, such as



        #define NAUTILUS_ICON_FILESYSTEM    "drive-harddisk-symbolic"



        probably for developer/code consistency, instead of having to rely on looking up actual icon names. The only place where that particular definition is used is in get_icon function, and that function ironically is not used for Places side bar but is used inside pathbar updating function. Go figure,right ? ¯_(ツ)_/¯












        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited yesterday

























        answered yesterday









        Sergiy KolodyazhnyySergiy Kolodyazhnyy

        73.8k9154323




        73.8k9154323






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Ask Ubuntu!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2faskubuntu.com%2fquestions%2f867997%2fhow-does-nautilus-decide-which-icon-to-use%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            數位音樂下載

            When can things happen in Etherscan, such as the picture below?

            格利澤436b