How does Nautilus decide which icon to use?
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
add a comment |
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
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
add a comment |
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
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
nautilus icons
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
add a comment |
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
add a comment |
1 Answer
1
active
oldest
votes
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:
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'sadd_volume()
function. Gio'sg_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 toadd_volume()
function andadd_mount()
.Icons are queried for mountpoints and volumes: Inside
add_volume()
function, Gio'sg_volume_get_icon()
function fetches the icon of typeGIcon
. Insideadd_mount()
Gio'sg_mount_get_icon()
also of typeGIcon
. In both cases, icon along with other information are combined into an object of typeNAUTILUS_TYPE_GTK_PLACES_VIEW_ROW
and passed toinsert_row()
function
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 usinggtk_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 ? ¯_(ツ)_/¯
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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:
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'sadd_volume()
function. Gio'sg_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 toadd_volume()
function andadd_mount()
.Icons are queried for mountpoints and volumes: Inside
add_volume()
function, Gio'sg_volume_get_icon()
function fetches the icon of typeGIcon
. Insideadd_mount()
Gio'sg_mount_get_icon()
also of typeGIcon
. In both cases, icon along with other information are combined into an object of typeNAUTILUS_TYPE_GTK_PLACES_VIEW_ROW
and passed toinsert_row()
function
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 usinggtk_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 ? ¯_(ツ)_/¯
add a comment |
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:
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'sadd_volume()
function. Gio'sg_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 toadd_volume()
function andadd_mount()
.Icons are queried for mountpoints and volumes: Inside
add_volume()
function, Gio'sg_volume_get_icon()
function fetches the icon of typeGIcon
. Insideadd_mount()
Gio'sg_mount_get_icon()
also of typeGIcon
. In both cases, icon along with other information are combined into an object of typeNAUTILUS_TYPE_GTK_PLACES_VIEW_ROW
and passed toinsert_row()
function
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 usinggtk_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 ? ¯_(ツ)_/¯
add a comment |
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:
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'sadd_volume()
function. Gio'sg_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 toadd_volume()
function andadd_mount()
.Icons are queried for mountpoints and volumes: Inside
add_volume()
function, Gio'sg_volume_get_icon()
function fetches the icon of typeGIcon
. Insideadd_mount()
Gio'sg_mount_get_icon()
also of typeGIcon
. In both cases, icon along with other information are combined into an object of typeNAUTILUS_TYPE_GTK_PLACES_VIEW_ROW
and passed toinsert_row()
function
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 usinggtk_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 ? ¯_(ツ)_/¯
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:
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'sadd_volume()
function. Gio'sg_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 toadd_volume()
function andadd_mount()
.Icons are queried for mountpoints and volumes: Inside
add_volume()
function, Gio'sg_volume_get_icon()
function fetches the icon of typeGIcon
. Insideadd_mount()
Gio'sg_mount_get_icon()
also of typeGIcon
. In both cases, icon along with other information are combined into an object of typeNAUTILUS_TYPE_GTK_PLACES_VIEW_ROW
and passed toinsert_row()
function
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 usinggtk_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 ? ¯_(ツ)_/¯
edited yesterday
answered yesterday
Sergiy KolodyazhnyySergiy Kolodyazhnyy
73.8k9154323
73.8k9154323
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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