[gtk+/places-sidebar: 764/764] Merge branch 'master' into places-sidebar
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/places-sidebar: 764/764] Merge branch 'master' into places-sidebar
- Date: Thu, 14 Feb 2013 02:47:58 +0000 (UTC)
commit 936045e82bc9a3f2b09612e3c22799c45b101c5e
Merge: 04dbec4 e16ade9
Author: Federico Mena Quintero <federico gnome org>
Date: Wed Feb 13 20:15:46 2013 -0600
Merge branch 'master' into places-sidebar
Conflicts:
docs/reference/gtk/gtk-docs.sgml
gtk/gtkfilechooserdefault.c
gtk/org.gtk.Settings.FileChooser.gschema.xml
NEWS | 269 +
build/Makefile.am | 2 +
build/win32/Makefile.am | 2 +
build/win32/vs10/Makefile.am | 2 +
build/win32/vs10/gailutil.vcxproj | 6 +-
build/win32/vs10/gdk-win32.vcxproj | 4 +
build/win32/vs10/gdk.vcxprojin | 4 +
build/win32/vs10/gtk+.props | 105 +-
build/win32/vs10/gtk+.sln | 2 +-
build/win32/vs10/gtk.vcxprojin | 4 +
build/win32/vs10/gtk3-demo.vcxproj | 5 +-
build/win32/vs10/install.vcxproj | 4 +
build/win32/vs10/libgail.vcxprojin | 7 +-
build/win32/vs9/Makefile.am | 2 +
build/win32/vs9/gtk+.vsprops | 54 +-
config.h.win32.in | 17 +-
configure.ac | 95 +-
demos/gtk-demo/Makefile.am | 46 +-
demos/gtk-demo/application.c | 10 +-
demos/gtk-demo/appwindow.c | 60 +-
demos/gtk-demo/assistant.c | 1 -
demos/gtk-demo/builder.c | 8 +-
demos/gtk-demo/changedisplay.c | 1 -
demos/gtk-demo/css_accordion.c | 4 +-
demos/gtk-demo/css_accordion.css | 2 +-
demos/gtk-demo/css_basics.c | 4 +-
demos/gtk-demo/css_basics.css | 2 +-
demos/gtk-demo/css_multiplebgs.c | 4 +-
demos/gtk-demo/css_multiplebgs.css | 4 +-
demos/gtk-demo/css_pixbufs.c | 7 +-
demos/gtk-demo/css_pixbufs.css | 22 +-
demos/gtk-demo/css_shadows.c | 1 +
demos/gtk-demo/css_shadows.css | 4 +-
demos/gtk-demo/demo-common.h | 11 -
demos/gtk-demo/demo.gresource.xml | 109 +-
demos/gtk-demo/demo.ui | 2 +-
demos/gtk-demo/fancy.css | 65 -
demos/gtk-demo/geninclude.pl.in | 21 +-
demos/gtk-demo/gtk-logo-old.png | Bin 0 -> 5895 bytes
demos/gtk-demo/gtk-logo-rgb.gif | Bin 6427 -> 0 bytes
demos/gtk-demo/iconview.c | 179 +-
demos/gtk-demo/iconview_edit.c | 1 -
demos/gtk-demo/images.c | 132 +-
demos/gtk-demo/main.c | 328 +-
demos/gtk-demo/pixbufs.c | 40 +-
demos/gtk-demo/printing.c | 17 +-
demos/gtk-demo/textscroll.c | 1 -
demos/gtk-demo/textview.c | 26 +-
demos/gtk-demo/theming_custom_css.c | 66 -
demos/gtk-demo/theming_style_classes.c | 3 +-
demos/gtk-demo/toolpalette.c | 7 +-
demos/widget-factory/Makefile.am | 2 +
docs/reference/gdk/Makefile.am | 7 +
docs/reference/gdk/gdk3-sections.txt | 4 +
docs/reference/gtk/Makefile.am | 23 +-
docs/reference/gtk/broadway.xml | 41 +-
docs/reference/gtk/broadwayd.xml | 77 +
docs/reference/gtk/building.sgml | 78 +-
docs/reference/gtk/getting_started.xml | 2 +-
docs/reference/gtk/gtk-docs.sgml | 56 +-
docs/reference/gtk/gtk3-sections.txt | 7 +
docs/reference/gtk/migrating-2to3.xml | 49 +
docs/reference/gtk/running.sgml | 15 +-
docs/reference/gtk/x11.sgml | 27 +
docs/tools/widgets.c | 3 +-
examples/Makefile.am | 2 +
examples/bloatpad.c | 2 -
examples/plugman.c | 2 -
examples/sunny.c | 2 -
gdk/Makefile.am | 1 -
gdk/broadway/Makefile.am | 28 +-
gdk/broadway/TODO.broadway | 11 +
gdk/broadway/{broadway.c => broadway-output.c} | 34 +-
gdk/broadway/{broadway.h => broadway-output.h} | 11 +-
gdk/broadway/broadway-protocol.h | 264 +
gdk/broadway/broadway-server.c | 1840 +++
gdk/broadway/broadway-server.h | 82 +
gdk/broadway/broadway.js | 288 +-
gdk/broadway/broadwayd.c | 636 +
gdk/broadway/gdkbroadway-server.c | 695 +
gdk/broadway/gdkbroadway-server.h | 71 +
gdk/broadway/gdkbroadwaycursor.h | 6 +-
gdk/broadway/gdkbroadwaydisplaymanager.h | 6 +-
gdk/broadway/gdkdevice-broadway.c | 109 +-
gdk/broadway/gdkdisplay-broadway.c | 978 +--
gdk/broadway/gdkdisplay-broadway.h | 103 +-
gdk/broadway/gdkeventsource.c | 73 +-
gdk/broadway/gdkprivate-broadway.h | 3 +-
gdk/broadway/gdkwindow-broadway.c | 326 +-
gdk/gdk.c | 2 -
gdk/gdk.symbols | 3 +
gdk/gdkapplaunchcontext.h | 6 +-
gdk/gdkcairo.h | 6 +-
gdk/gdkcolor.h | 6 +-
gdk/gdkcursor.h | 6 +-
gdk/gdkdevice.h | 6 +-
gdk/gdkdevicemanager.h | 6 +-
gdk/gdkdisplay.c | 3 +-
gdk/gdkdisplay.h | 6 +-
gdk/gdkdisplaymanager.h | 6 +-
gdk/gdkdnd.h | 6 +-
gdk/gdkevents.h | 6 +-
gdk/gdkinternals.h | 4 +-
gdk/gdkkeys.h | 6 +-
gdk/gdkkeysyms-update.pl | 2 +-
gdk/gdkmain.h | 6 +-
gdk/gdkpango.h | 6 +-
gdk/gdkpixbuf.h | 6 +-
gdk/gdkproperty.h | 6 +-
gdk/gdkrectangle.h | 6 +-
gdk/gdkrgba.h | 6 +-
gdk/gdkscreen.h | 6 +-
gdk/gdkselection.h | 6 +-
gdk/gdktestutils.h | 6 +-
gdk/gdkthreads.h | 6 +-
gdk/gdktypes.h | 6 +-
gdk/gdkversionmacros.h.in | 10 +
gdk/gdkvisual.h | 6 +-
gdk/gdkwindow.c | 249 +-
gdk/gdkwindow.h | 32 +-
gdk/gdkwindowimpl.h | 1 +
gdk/quartz/GdkQuartzNSWindow.c | 40 +
gdk/quartz/GdkQuartzNSWindow.h | 1 +
gdk/quartz/GdkQuartzView.c | 9 -
gdk/quartz/gdkevents-quartz.c | 137 +-
gdk/quartz/gdkglobals-quartz.c | 11 +-
gdk/quartz/gdkkeys-quartz.c | 2 +-
gdk/quartz/gdkprivate-quartz.h | 1 -
gdk/quartz/gdkquartz.h | 3 +-
gdk/quartz/gdkquartzcursor.h | 6 +-
gdk/quartz/gdkquartzdevice-core.h | 6 +-
gdk/quartz/gdkquartzdevicemanager-core.h | 6 +-
gdk/quartz/gdkquartzdisplay.h | 6 +-
gdk/quartz/gdkquartzdisplaymanager.h | 6 +-
gdk/quartz/gdkquartzdnd.h | 6 +-
gdk/quartz/gdkquartzkeys.h | 6 +-
gdk/quartz/gdkquartzscreen.h | 6 +-
gdk/quartz/gdkquartzutils.h | 6 +-
gdk/quartz/gdkquartzvisual.h | 6 +-
gdk/quartz/gdkquartzwindow.h | 6 +-
gdk/quartz/gdkwindow-quartz.c | 110 +-
gdk/wayland/Makefile.am | 6 +
gdk/wayland/gdkcursor-wayland.c | 54 +-
gdk/wayland/gdkdevice-wayland.c | 682 +-
gdk/wayland/gdkdisplay-wayland.c | 202 +-
gdk/wayland/gdkdisplay-wayland.h | 33 -
gdk/wayland/gdkdisplaymanager-wayland.c | 2 +-
gdk/wayland/gdkeventsource.c | 5 +-
gdk/wayland/gdkkeys-wayland.c | 4 +-
gdk/wayland/gdkprivate-wayland.h | 10 +-
gdk/wayland/gdkscreen-wayland.c | 133 +-
gdk/wayland/gdkwayland.h | 6 +
gdk/wayland/gdkwaylanddevice.h | 54 +
gdk/wayland/gdkwaylanddisplay.h | 53 +
gdk/wayland/gdkwaylandwindow.h | 52 +
gdk/wayland/gdkwindow-wayland.c | 161 +-
gdk/win32/gdkwin32cursor.h | 6 +-
gdk/win32/gdkwin32display.h | 6 +-
gdk/win32/gdkwin32displaymanager.h | 6 +-
gdk/win32/gdkwin32dnd.h | 6 +-
gdk/win32/gdkwin32keys.h | 6 +-
gdk/win32/gdkwin32screen.h | 6 +-
gdk/win32/gdkwin32window.h | 6 +-
gdk/win32/gdkwindow-win32.c | 5 +-
gdk/x11/Makefile.am | 5 -
gdk/x11/checksettings.c | 44 -
gdk/x11/gdkdevicemanager-x11.c | 6 +-
gdk/x11/gdkdevicemanager-xi2.c | 23 +-
gdk/x11/gdkdisplay-x11.c | 5 +-
gdk/x11/gdkscreen-x11.c | 196 +-
gdk/x11/gdkscreen-x11.h | 10 +
gdk/x11/gdksettings.c | 200 +-
gdk/x11/gdkwindow-x11.c | 128 +-
gdk/x11/gdkx11applaunchcontext.h | 6 +-
gdk/x11/gdkx11cursor.h | 6 +-
gdk/x11/gdkx11device.h | 6 +-
gdk/x11/gdkx11devicemanager.h | 6 +-
gdk/x11/gdkx11display.h | 6 +-
gdk/x11/gdkx11displaymanager.h | 6 +-
gdk/x11/gdkx11dnd.h | 6 +-
gdk/x11/gdkx11keys.h | 6 +-
gdk/x11/gdkx11property.h | 6 +-
gdk/x11/gdkx11screen.h | 6 +-
gdk/x11/gdkx11selection.h | 6 +-
gdk/x11/gdkx11utils.h | 6 +-
gdk/x11/gdkx11visual.h | 6 +-
gdk/x11/gdkx11window.h | 6 +-
gdk/x11/xsettings-client.c | 59 +-
gdk/x11/xsettings-common.c | 133 +-
gdk/x11/xsettings-common.h | 16 +-
git.mk | 86 +-
gtk/Makefile.am | 51 +-
gtk/a11y/Makefile.am | 65 +-
gtk/a11y/gailmisc.h | 49 -
gtk/a11y/gailutil.c | 373 -
gtk/a11y/{gail.c => gtkaccessibility.c} | 212 +-
gtk/a11y/{gail.h => gtkaccessibility.h} | 16 +-
gtk/a11y/{gailmisc.c => gtkaccessibilitymisc.c} | 18 +-
gtk/a11y/{gailutil.h => gtkaccessibilitymisc.h} | 27 +-
gtk/a11y/gtkaccessibilityutil.c | 156 +
gtk/a11y/{gailutil.h => gtkaccessibilityutil.h} | 14 +-
gtk/a11y/gtkarrowaccessible.c | 12 +-
gtk/a11y/gtkarrowaccessible.h | 12 +-
gtk/a11y/gtkbooleancellaccessible.c | 28 +-
gtk/a11y/gtkbooleancellaccessible.h | 12 +-
gtk/a11y/gtkboxaccessible.c | 45 -
gtk/a11y/gtkboxaccessible.h | 52 -
gtk/a11y/gtkbuttonaccessible.c | 42 +-
gtk/a11y/gtkbuttonaccessible.h | 12 +-
gtk/a11y/gtkcellaccessible.c | 90 +-
gtk/a11y/gtkcellaccessible.h | 29 +-
gtk/a11y/gtkcellaccessibleparent.c | 49 +-
gtk/a11y/gtkcellaccessibleparent.h | 55 +-
gtk/a11y/gtkcellaccessibleprivate.h | 41 +
gtk/a11y/gtkcheckmenuitemaccessible.c | 16 +-
gtk/a11y/gtkcheckmenuitemaccessible.h | 12 +-
gtk/a11y/gtkcolorswatchaccessible.c | 33 +-
...essible.h => gtkcolorswatchaccessibleprivate.h} | 4 +-
gtk/a11y/gtkcomboboxaccessible.c | 40 +-
gtk/a11y/gtkcomboboxaccessible.h | 12 +-
gtk/a11y/gtkcontaineraccessible.c | 12 +-
gtk/a11y/gtkcontaineraccessible.h | 14 +-
gtk/a11y/gtkcontainercellaccessible.c | 35 +-
gtk/a11y/gtkcontainercellaccessible.h | 24 +-
gtk/a11y/gtkentryaccessible.c | 573 +-
gtk/a11y/gtkentryaccessible.h | 12 +-
gtk/a11y/gtkexpanderaccessible.c | 42 +-
gtk/a11y/gtkexpanderaccessible.h | 12 +-
gtk/a11y/gtkframeaccessible.c | 12 +-
gtk/a11y/gtkframeaccessible.h | 12 +-
gtk/a11y/gtkiconviewaccessible.c | 38 +-
gtk/a11y/gtkiconviewaccessible.h | 16 +-
.../{gailutil.h => gtkiconviewaccessibleprivate.h} | 20 +-
gtk/a11y/gtkimageaccessible.c | 14 +-
gtk/a11y/gtkimageaccessible.h | 12 +-
gtk/a11y/gtkimagecellaccessible.c | 10 +-
gtk/a11y/gtkimagecellaccessible.h | 12 +-
gtk/a11y/gtklabelaccessible.c | 20 +-
gtk/a11y/gtklabelaccessible.h | 12 +-
gtk/a11y/gtklevelbaraccessible.c | 140 +
gtk/a11y/gtklevelbaraccessible.h | 57 +
gtk/a11y/gtklinkbuttonaccessible.c | 10 +-
gtk/a11y/gtklinkbuttonaccessible.h | 12 +-
gtk/a11y/gtklockbuttonaccessible.c | 10 +-
gtk/a11y/gtklockbuttonaccessible.h | 17 +-
...gailutil.h => gtklockbuttonaccessibleprivate.h} | 18 +-
gtk/a11y/gtkmenuaccessible.c | 13 +-
gtk/a11y/gtkmenuaccessible.h | 14 +-
gtk/a11y/gtkmenuitemaccessible.c | 59 +-
gtk/a11y/gtkmenuitemaccessible.h | 12 +-
gtk/a11y/gtkmenushellaccessible.c | 10 +-
gtk/a11y/gtkmenushellaccessible.h | 12 +-
gtk/a11y/gtknotebookaccessible.c | 18 +-
gtk/a11y/gtknotebookaccessible.h | 12 +-
gtk/a11y/gtknotebookpageaccessible.c | 25 +-
gtk/a11y/gtknotebookpageaccessible.h | 18 +-
gtk/a11y/gtkpanedaccessible.c | 10 +-
gtk/a11y/gtkpanedaccessible.h | 12 +-
gtk/a11y/gtkprogressbaraccessible.c | 12 +-
gtk/a11y/gtkprogressbaraccessible.h | 12 +-
gtk/a11y/gtkradiobuttonaccessible.c | 12 +-
gtk/a11y/gtkradiobuttonaccessible.h | 12 +-
gtk/a11y/gtkradiomenuitemaccessible.c | 12 +-
gtk/a11y/gtkradiomenuitemaccessible.h | 12 +-
gtk/a11y/gtkrangeaccessible.c | 108 +-
gtk/a11y/gtkrangeaccessible.h | 12 +-
gtk/a11y/gtkrenderercellaccessible.c | 12 +-
gtk/a11y/gtkrenderercellaccessible.h | 14 +-
gtk/a11y/gtkscaleaccessible.c | 10 +-
gtk/a11y/gtkscaleaccessible.h | 12 +-
gtk/a11y/gtkscalebuttonaccessible.c | 39 +-
gtk/a11y/gtkscalebuttonaccessible.h | 12 +-
gtk/a11y/gtkscrollbaraccessible.c | 91 -
gtk/a11y/gtkscrollbaraccessible.h | 52 -
gtk/a11y/gtkscrolledwindowaccessible.c | 10 +-
gtk/a11y/gtkscrolledwindowaccessible.h | 12 +-
gtk/a11y/gtkspinbuttonaccessible.c | 26 +-
gtk/a11y/gtkspinbuttonaccessible.h | 12 +-
gtk/a11y/gtkspinneraccessible.c | 11 +-
gtk/a11y/gtkspinneraccessible.h | 12 +-
gtk/a11y/gtkstatusbaraccessible.c | 12 +-
gtk/a11y/gtkstatusbaraccessible.h | 16 +-
gtk/a11y/gtkswitchaccessible.c | 39 +-
gtk/a11y/gtkswitchaccessible.h | 12 +-
gtk/a11y/gtktextcellaccessible.c | 25 +-
gtk/a11y/gtktextcellaccessible.h | 12 +-
gtk/a11y/gtktextviewaccessible.c | 16 +-
gtk/a11y/gtktextviewaccessible.h | 15 +-
.../{gailutil.h => gtktextviewaccessibleprivate.h} | 19 +-
gtk/a11y/gtktogglebuttonaccessible.c | 14 +-
gtk/a11y/gtktogglebuttonaccessible.h | 12 +-
gtk/a11y/gtktoplevelaccessible.c | 22 +-
gtk/a11y/gtktoplevelaccessible.h | 12 +-
gtk/a11y/gtktreeviewaccessible.c | 41 +-
gtk/a11y/gtktreeviewaccessible.h | 51 +-
gtk/a11y/gtktreeviewaccessibleprivate.h | 65 +
gtk/a11y/gtkwidgetaccessible.c | 26 +-
gtk/a11y/gtkwidgetaccessible.h | 16 +-
.../{gailutil.h => gtkwidgetaccessibleprivate.h} | 19 +-
gtk/a11y/gtkwindowaccessible.c | 42 +-
gtk/a11y/gtkwindowaccessible.h | 12 +-
gtk/deprecated/gtkcolorsel.h | 6 +-
gtk/deprecated/gtkcolorseldialog.h | 6 +-
gtk/deprecated/gtkfontsel.h | 8 +-
gtk/{ => deprecated}/gtkgradient.c | 42 +-
gtk/{ => deprecated}/gtkgradient.h | 16 +-
gtk/{ => deprecated}/gtkgradientprivate.h | 0
gtk/deprecated/gtkhandlebox.h | 6 +-
gtk/deprecated/gtkhbbox.h | 6 +-
gtk/deprecated/gtkhbox.h | 8 +-
gtk/deprecated/gtkhpaned.h | 6 +-
gtk/deprecated/gtkhscale.h | 6 +-
gtk/deprecated/gtkhscrollbar.h | 6 +-
gtk/deprecated/gtkhseparator.h | 6 +-
gtk/deprecated/gtkhsv.h | 6 +-
gtk/deprecated/gtkrc.h | 6 +-
gtk/deprecated/gtkstyle.h | 8 +-
gtk/deprecated/gtksymboliccolor.c | 359 +
gtk/{ => deprecated}/gtksymboliccolor.h | 16 +-
.../gtksymboliccolorprivate.h} | 19 +-
gtk/deprecated/gtktable.h | 6 +-
gtk/deprecated/gtktearoffmenuitem.h | 6 +-
gtk/deprecated/gtkvbbox.h | 6 +-
gtk/deprecated/gtkvbox.h | 6 +-
gtk/deprecated/gtkvpaned.h | 6 +-
gtk/deprecated/gtkvscale.h | 6 +-
gtk/deprecated/gtkvscrollbar.h | 6 +-
gtk/deprecated/gtkvseparator.h | 6 +-
gtk/gtk-a11y.h | 78 +
gtk/gtk-default.css | 12 +
gtk/gtk-launch.c | 21 +-
gtk/gtk.h | 6 +-
gtk/gtk.symbols | 71 +
gtk/gtkaboutdialog.c | 29 +-
gtk/gtkaboutdialog.h | 6 +-
gtk/gtkaccelgroup.h | 8 +-
gtk/gtkaccellabel.h | 8 +-
gtk/gtkaccelmap.h | 8 +-
gtk/gtkaccelmapprivate.h | 8 +-
gtk/gtkaccessible.h | 6 +-
gtk/gtkaction.h | 6 +-
gtk/gtkactiongroup.h | 6 +-
gtk/gtkactionhelper.c | 2 +-
gtk/gtkactivatable.h | 6 +-
gtk/gtkadjustment.h | 6 +-
gtk/gtkalignment.h | 8 +-
gtk/gtkappchooser.h | 6 +-
gtk/gtkappchooserbutton.c | 6 +-
gtk/gtkappchooserbutton.h | 6 +-
gtk/gtkappchooserdialog.h | 6 +-
gtk/gtkappchooserwidget.h | 6 +-
gtk/gtkapplication.c | 13 +-
gtk/gtkapplication.h | 6 +-
gtk/gtkapplicationwindow.c | 4 +
gtk/gtkarrow.h | 8 +-
gtk/gtkaspectframe.h | 8 +-
gtk/gtkassistant.h | 6 +-
gtk/gtkbbox.h | 6 +-
gtk/gtkbin.c | 156 +-
gtk/gtkbin.h | 8 +-
gtk/gtkbindings.h | 8 +-
gtk/gtkbitmaskprivateimpl.h | 6 +-
gtk/gtkborder.h | 6 +-
gtk/gtkborderimage.c | 14 +-
gtk/gtkborderimageprivate.h | 2 +-
gtk/gtkbox.c | 29 +-
gtk/gtkbox.h | 8 +-
gtk/gtkbuildable.c | 2 +-
gtk/gtkbuildable.h | 6 +-
gtk/gtkbuilder.c | 90 +-
gtk/gtkbuilder.h | 10 +-
gtk/gtkbutton.c | 4 +-
gtk/gtkbutton.h | 8 +-
gtk/gtkcalendar.c | 8 +-
gtk/gtkcalendar.h | 8 +-
gtk/gtkcellarea.h | 6 +-
gtk/gtkcellareabox.h | 6 +-
gtk/gtkcellareaboxcontextprivate.h | 6 +-
gtk/gtkcellareacontext.h | 6 +-
gtk/gtkcelleditable.h | 6 +-
gtk/gtkcelllayout.h | 6 +-
gtk/gtkcellrenderer.h | 6 +-
gtk/gtkcellrendereraccel.c | 4 +-
gtk/gtkcellrendereraccel.h | 6 +-
gtk/gtkcellrenderercombo.c | 2 +-
gtk/gtkcellrenderercombo.h | 6 +-
gtk/gtkcellrendererpixbuf.h | 6 +-
gtk/gtkcellrendererprogress.h | 6 +-
gtk/gtkcellrendererspin.h | 6 +-
gtk/gtkcellrendererspinner.h | 6 +-
gtk/gtkcellrenderertext.c | 16 +-
gtk/gtkcellrenderertext.h | 8 +-
gtk/gtkcellrenderertoggle.h | 6 +-
gtk/gtkcellview.h | 6 +-
gtk/gtkcheckbutton.h | 8 +-
gtk/gtkcheckmenuitem.h | 8 +-
gtk/gtkclipboard-quartz.c | 178 +-
gtk/gtkclipboard.h | 6 +-
gtk/gtkcolorbutton.c | 55 +-
gtk/gtkcolorbutton.h | 8 +-
gtk/gtkcolorchooser.c | 2 +-
gtk/gtkcolorchooser.h | 6 +-
gtk/gtkcolorchooserdialog.h | 6 +-
gtk/gtkcolorchooserwidget.c | 3 +-
gtk/gtkcolorchooserwidget.h | 6 +-
gtk/gtkcoloreditorprivate.h | 6 +-
gtk/gtkcolorplaneprivate.h | 6 +-
gtk/gtkcolorscaleprivate.h | 6 +-
gtk/gtkcolorswatch.c | 6 +-
gtk/gtkcolorswatchprivate.h | 6 +-
gtk/gtkcolorutils.h | 6 +-
gtk/gtkcombobox.c | 37 +-
gtk/gtkcombobox.h | 6 +-
gtk/gtkcomboboxtext.c | 4 +-
gtk/gtkcomboboxtext.h | 6 +-
gtk/gtkcontainer.c | 59 +-
gtk/gtkcontainer.h | 8 +-
gtk/gtkcssarrayvalue.c | 31 +-
gtk/gtkcssbgsizevalue.c | 39 +-
gtk/gtkcsscolorvalue.c | 837 ++
gtk/gtkcsscolorvalueprivate.h | 55 +
gtk/gtkcsscomputedvalues.c | 48 +-
gtk/gtkcsscomputedvaluesprivate.h | 2 +
gtk/gtkcsscustomproperty.c | 13 +
gtk/gtkcssenumvalue.c | 149 +-
gtk/gtkcssenumvalueprivate.h | 5 +
gtk/gtkcssimage.c | 33 +
gtk/gtkcssimagecrossfade.c | 13 +
gtk/gtkcssimagegradient.c | 17 +-
gtk/gtkcssimagegradientprivate.h | 2 +-
gtk/gtkcssimagelinear.c | 33 +-
gtk/gtkcssimageprivate.h | 5 +
gtk/gtkcssimagesurface.c | 163 +
gtk/gtkcssimagesurfaceprivate.h | 56 +
gtk/gtkcssimageurl.c | 179 +-
gtk/gtkcssimageurlprivate.h | 3 +-
gtk/gtkcssimagevalue.c | 2 +-
gtk/gtkcssinheritvalue.c | 4 +-
gtk/gtkcssinitialvalue.c | 43 +
gtk/gtkcssinitialvalueprivate.h | 1 +
gtk/gtkcsslookup.c | 19 -
gtk/gtkcsslookupprivate.h | 20 +-
gtk/gtkcssmatcher.c | 27 +-
gtk/gtkcssmatcherprivate.h | 17 +-
gtk/gtkcssnumbervalue.c | 41 +-
gtk/gtkcssparser.c | 2 +-
gtk/gtkcssprovider.c | 441 +-
gtk/gtkcssproviderprivate.h | 4 +
gtk/gtkcssrgbavalue.c | 1 -
gtk/gtkcssselector.c | 1480 ++-
gtk/gtkcssselectorprivate.h | 23 +-
gtk/gtkcssshadowvalue.c | 8 +-
gtk/gtkcssshorthandpropertyimpl.c | 16 +-
gtk/gtkcssstylefuncs.c | 49 +-
gtk/gtkcssstyleproperty.c | 114 +-
gtk/gtkcssstylepropertyimpl.c | 185 +-
gtk/gtkcssstylepropertyprivate.h | 10 +-
gtk/gtkcsstypesprivate.h | 22 +-
gtk/gtkcssvalue.c | 25 +-
gtk/gtkcustompaperunixdialog.c | 2 +-
gtk/gtkdebug.h | 6 +-
gtk/gtkdialog.h | 8 +-
gtk/gtkdnd-quartz.c | 1 +
gtk/gtkdnd.h | 8 +-
gtk/gtkdrawingarea.c | 3 +-
gtk/gtkdrawingarea.h | 8 +-
gtk/gtkeditable.h | 8 +-
gtk/gtkentry.c | 31 +-
gtk/gtkentry.h | 8 +-
gtk/gtkentrybuffer.h | 6 +-
gtk/gtkentrycompletion.c | 36 +
gtk/gtkentrycompletion.h | 6 +-
gtk/gtkenums.h | 33 +-
gtk/gtkeventbox.c | 6 +-
gtk/gtkeventbox.h | 8 +-
gtk/gtkexpander.c | 10 +-
gtk/gtkexpander.h | 6 +-
gtk/gtkfilechooser.c | 5 +-
gtk/gtkfilechooser.h | 6 +-
gtk/gtkfilechooserbutton.c | 284 +-
gtk/gtkfilechooserbutton.h | 6 +-
gtk/gtkfilechooserdefault.c | 184 +-
gtk/gtkfilechooserdialog.c | 31 +
gtk/gtkfilechooserdialog.h | 6 +-
gtk/gtkfilechooserprivate.h | 26 +-
gtk/gtkfilechooserutils.c | 27 +
gtk/gtkfilechooserutils.h | 2 +
gtk/gtkfilechooserwidget.h | 6 +-
gtk/gtkfilefilter.h | 6 +-
gtk/gtkfilesystemmodel.c | 130 +-
gtk/gtkfilesystemmodel.h | 5 +-
gtk/gtkfixed.c | 2 +-
gtk/gtkfixed.h | 8 +-
gtk/gtkfontbutton.h | 6 +-
gtk/gtkfontchooser.h | 6 +-
gtk/gtkfontchooserdialog.h | 6 +-
gtk/gtkfontchooserwidget.h | 6 +-
gtk/gtkframe.c | 12 +-
gtk/gtkframe.h | 8 +-
gtk/gtkgrid.h | 8 +-
gtk/gtkhsla.c | 203 +
gtk/gtkhslaprivate.h | 51 +
gtk/gtkiconfactory.c | 4 +
gtk/gtkiconfactory.h | 6 +-
gtk/gtkiconhelper.c | 10 +-
gtk/gtkicontheme.c | 700 +-
gtk/gtkicontheme.h | 6 +-
gtk/gtkiconview.c | 146 +-
gtk/gtkiconview.h | 11 +-
gtk/gtkiconviewprivate.h | 1 +
gtk/gtkimage.c | 58 +-
gtk/gtkimage.h | 8 +-
gtk/gtkimagemenuitem.h | 8 +-
gtk/gtkimcontext.h | 8 +-
gtk/gtkimcontextinfo.h | 8 +-
gtk/gtkimcontextsimple.c | 50 +-
gtk/gtkimcontextsimple.h | 6 +-
gtk/gtkimmulticontext.h | 6 +-
gtk/gtkinfobar.h | 6 +-
gtk/gtkinvisible.c | 2 +-
gtk/gtkinvisible.h | 6 +-
gtk/gtklabel.c | 217 +-
gtk/gtklabel.h | 8 +-
gtk/gtklayout.c | 6 +-
gtk/gtklayout.h | 8 +-
gtk/gtklevelbar.c | 4 +
gtk/gtklevelbar.h | 6 +-
gtk/gtklinkbutton.h | 6 +-
gtk/gtkliststore.c | 10 +-
gtk/gtkliststore.h | 6 +-
gtk/gtklockbutton.c | 2 +-
gtk/gtkmain.c | 20 +-
gtk/gtkmain.h | 8 +-
gtk/gtkmenu.c | 156 +-
gtk/gtkmenu.h | 8 +-
gtk/gtkmenubar.c | 81 +-
gtk/gtkmenubar.h | 8 +-
gtk/gtkmenubutton.c | 35 +-
gtk/gtkmenubutton.h | 6 +-
gtk/gtkmenuitem.c | 137 +-
gtk/gtkmenuitem.h | 6 +-
gtk/gtkmenushell.c | 10 +-
gtk/gtkmenushell.h | 8 +-
gtk/gtkmenutoolbutton.h | 6 +-
gtk/gtkmessagedialog.c | 18 +-
gtk/gtkmessagedialog.h | 6 +-
gtk/gtkmisc.c | 2 +-
gtk/gtkmisc.h | 8 +-
gtk/gtkmodelmenu-quartz.c | 1 +
gtk/gtkmodifierstyle.c | 17 +-
gtk/gtkmodules.h | 6 +-
gtk/gtkmountoperation.h | 6 +-
gtk/gtknotebook.c | 82 +-
gtk/gtknotebook.h | 8 +-
gtk/gtknumerableicon.h | 6 +-
gtk/gtkoffscreenwindow.c | 2 +-
gtk/gtkoffscreenwindow.h | 6 +-
gtk/gtkorientable.h | 6 +-
gtk/gtkoverlay.c | 11 +-
gtk/gtkoverlay.h | 6 +-
gtk/gtkpagesetup.h | 8 +-
gtk/gtkpagesetupunixdialog.c | 2 +-
gtk/gtkpagesetupunixdialog.h | 6 +-
gtk/gtkpaned.c | 10 +-
gtk/gtkpaned.h | 6 +-
gtk/gtkpapersize.h | 8 +-
gtk/gtkpathbar.c | 4 +-
gtk/gtkplacessidebar.c | 25 +-
gtk/gtkplug.c | 6 +-
gtk/gtkplug.h | 6 +-
gtk/gtkpressandholdprivate.h | 6 +-
gtk/gtkprintcontext.h | 8 +-
gtk/gtkprinter.h | 6 +-
gtk/gtkprintjob.h | 6 +-
gtk/gtkprintoperation.h | 8 +-
gtk/gtkprintoperationpreview.h | 6 +-
gtk/gtkprintsettings.h | 6 +-
gtk/gtkprintunixdialog.c | 10 +-
gtk/gtkprintunixdialog.h | 6 +-
gtk/gtkprivate.h | 10 +
gtk/gtkprogressbar.c | 104 +-
gtk/gtkprogressbar.h | 6 +-
gtk/gtkradioaction.h | 6 +-
gtk/gtkradiobutton.h | 8 +-
gtk/gtkradiomenuitem.h | 8 +-
gtk/gtkradiotoolbutton.h | 6 +-
gtk/gtkrange.c | 28 +-
gtk/gtkrange.h | 8 +-
gtk/gtkrecentaction.h | 6 +-
gtk/gtkrecentchooser.h | 6 +-
gtk/gtkrecentchooserdefault.c | 9 +-
gtk/gtkrecentchooserdialog.h | 6 +-
gtk/gtkrecentchoosermenu.h | 6 +-
gtk/gtkrecentchooserwidget.h | 6 +-
gtk/gtkrecentfilter.h | 6 +-
gtk/gtkrecentmanager.c | 35 +-
gtk/gtkrecentmanager.h | 6 +-
gtk/gtkroundedbox.c | 4 +-
gtk/gtkscale.c | 33 +-
gtk/gtkscale.h | 8 +-
gtk/gtkscalebutton.h | 6 +-
gtk/gtkscrollable.h | 6 +-
gtk/gtkscrollbar.c | 33 +-
gtk/gtkscrollbar.h | 8 +-
gtk/gtkscrolledwindow.c | 65 +-
gtk/gtkscrolledwindow.h | 7 +-
gtk/gtksearchentry.h | 6 +-
gtk/gtkselection.h | 8 +-
gtk/gtkseparator.h | 8 +-
gtk/gtkseparatormenuitem.h | 8 +-
gtk/gtkseparatortoolitem.c | 4 +-
gtk/gtkseparatortoolitem.h | 6 +-
gtk/gtksettings.c | 522 +-
gtk/gtksettings.h | 6 +-
gtk/gtkshow.h | 6 +-
gtk/gtksizegroup-private.h | 10 +-
gtk/gtksizegroup.c | 322 +-
gtk/gtksizegroup.h | 23 +-
gtk/gtksizerequest.c | 422 +-
gtk/gtksizerequestcache.c | 176 +
gtk/gtksizerequestcacheprivate.h | 84 +
gtk/gtksocket.c | 3 +-
gtk/gtksocket.h | 6 +-
gtk/gtkspinbutton.c | 8 +-
gtk/gtkspinbutton.h | 8 +-
gtk/gtkspinner.h | 6 +-
gtk/gtkstatusbar.h | 6 +-
gtk/gtkstatusicon.c | 311 +-
gtk/gtkstatusicon.h | 6 +-
gtk/gtkstock.h | 8 +-
gtk/gtkstylecascade.c | 55 +-
gtk/gtkstylecontext.c | 256 +-
gtk/gtkstylecontext.h | 19 +-
gtk/gtkstylecontextprivate.h | 14 +-
gtk/gtkstyleproperties.c | 39 +-
gtk/gtkstyleproperties.h | 10 +-
gtk/gtkstylepropertiesprivate.h | 1 -
gtk/gtkstyleprovider.c | 5 +
gtk/gtkstyleprovider.h | 8 +-
gtk/gtkstyleproviderprivate.c | 17 +-
gtk/gtkstyleproviderprivate.h | 9 +-
gtk/gtkswitch.c | 24 +-
gtk/gtkswitch.h | 6 +-
gtk/gtksymboliccolor.c | 1204 --
gtk/gtksymboliccolorprivate.h | 52 -
gtk/gtktestutils.h | 6 +-
gtk/gtktextattributes.h | 8 +-
gtk/gtktextbuffer.h | 6 +-
gtk/gtktextbufferrichtext.h | 6 +-
gtk/gtktextchild.h | 6 +-
gtk/gtktexthandle.c | 91 +-
gtk/gtktextiter.h | 6 +-
gtk/gtktextlayout.c | 20 +-
gtk/gtktextmark.h | 6 +-
gtk/gtktexttag.c | 2 +-
gtk/gtktexttag.h | 8 +-
gtk/gtktexttagtable.h | 6 +-
gtk/gtktextutil.c | 2 +-
gtk/gtktextview.c | 41 +-
gtk/gtktextview.h | 6 +-
gtk/gtkthemingbackground.c | 434 +-
gtk/gtkthemingbackgroundprivate.h | 4 +-
gtk/gtkthemingengine.c | 199 +-
gtk/gtkthemingengine.h | 9 +-
gtk/gtkthemingengineprivate.h | 3 -
gtk/gtktoggleaction.h | 6 +-
gtk/gtktogglebutton.h | 8 +-
gtk/gtktoggletoolbutton.h | 6 +-
gtk/gtktoolbar.c | 37 +-
gtk/gtktoolbar.h | 8 +-
gtk/gtktoolbutton.h | 6 +-
gtk/gtktoolitem.c | 4 +-
gtk/gtktoolitem.h | 6 +-
gtk/gtktoolitemgroup.c | 2 +-
gtk/gtktoolitemgroup.h | 6 +-
gtk/gtktoolpalette.c | 6 +-
gtk/gtktoolpalette.h | 6 +-
gtk/gtktoolshell.h | 8 +-
gtk/gtktooltip.c | 19 +
gtk/gtktooltip.h | 6 +-
gtk/gtktreednd.c | 2 +-
gtk/gtktreednd.h | 6 +-
gtk/gtktreemenu.h | 6 +-
gtk/gtktreemodel.c | 11 +-
gtk/gtktreemodel.h | 15 +-
gtk/gtktreemodelfilter.c | 30 +-
gtk/gtktreemodelfilter.h | 6 +-
gtk/gtktreemodelsort.h | 6 +-
gtk/gtktreeprivate.h | 10 +-
gtk/gtktreeselection.c | 4 +-
gtk/gtktreeselection.h | 6 +-
gtk/gtktreesortable.h | 8 +-
gtk/gtktreestore.h | 6 +-
gtk/gtktreeview.c | 779 +-
gtk/gtktreeview.h | 11 +-
gtk/gtktreeviewcolumn.c | 186 +-
gtk/gtktreeviewcolumn.h | 6 +-
gtk/gtktypes.h | 6 +-
gtk/gtkuimanager.h | 6 +-
gtk/gtkversion.h.in | 14 +-
gtk/gtkviewport.c | 16 +-
gtk/gtkviewport.h | 8 +-
gtk/gtkvolumebutton.h | 6 +-
gtk/gtkwidget.c | 696 +-
gtk/gtkwidget.h | 18 +-
gtk/gtkwidgetpath.h | 6 +-
gtk/gtkwidgetprivate.h | 53 +-
gtk/gtkwin32embedwidget.c | 4 +-
gtk/gtkwin32theme.c | 37 -
gtk/gtkwin32themeprivate.h | 1 -
gtk/gtkwindow.c | 137 +-
gtk/gtkwindow.h | 10 +-
gtk/native/Makefile.am | 16 +
gtk/org.gtk.Settings.ColorChooser.gschema.xml | 2 +-
gtk/org.gtk.Settings.FileChooser.gschema.xml | 7 +-
gtk/tests/Makefile.am | 7 +-
gtk/tests/accessible.c | 2 +
gtk/tests/bitmask.c | 47 +
gtk/tests/builder.c | 101 +-
gtk/tests/filechooser.c | 858 +-
gtk/tests/textiter.c | 20 +-
gtk/updateiconcache.c | 1 -
m4/ax_prog_cc_for_build.m4 | 125 +
modules/input/Makefile.am | 6 +-
modules/input/gtkimcontextime.c | 39 +-
modules/printbackends/cups/gtkprintbackendcups.c | 20 +-
po-properties/Makefile.in.in | 1 +
po-properties/POTFILES.in | 9 +
po-properties/POTFILES.skip | 22 +
po-properties/an.po | 8002 ++++++++++
po-properties/as.po | 2264 ++--
po-properties/bg.po | 1620 +-
po-properties/de.po | 626 +-
po-properties/el.po | 851 +-
po-properties/es.po | 1191 +-
po-properties/gl.po | 1381 +-
po-properties/gu.po | 577 +-
po-properties/he.po | 1817 ++--
po-properties/hu.po | 1688 ++--
po-properties/lt.po | 824 +-
po-properties/lv.po | 1622 +-
po-properties/mr.po | 411 +-
po-properties/nb.po | 4311 +++---
po-properties/pl.po | 1838 ++--
po-properties/pt.po | 2470 ++--
po-properties/pt_BR.po | 3617 +++---
po-properties/sl.po | 3355 +++--
po-properties/sr.po | 1295 +-
po-properties/sr latin po | 1295 +-
po-properties/ta.po | 5169 ++++---
po-properties/ug.po |15744 ++++++++++----------
po-properties/zh_HK.po | 1536 +-
po-properties/zh_TW.po | 1536 +-
po/LINGUAS | 1 +
po/Makefile.in.in | 1 +
po/POTFILES.in | 9 +
po/POTFILES.skip | 22 +
po/an.po | 4817 ++++++
po/ar.po | 585 +-
po/as.po | 496 +-
po/be.po | 2 +-
po/bg.po | 359 +-
po/bn_IN.po | 2 +-
po/br.po | 2 +-
po/ca.po | 2 +-
po/ca valencia po | 2 +-
po/crh.po | 2 +-
po/cs.po | 2 +-
po/da.po | 2 +-
po/de.po | 1171 +-
po/el.po | 2 +-
po/en_GB.po | 311 +-
po/eo.po | 2 +-
po/es.po | 443 +-
po/et.po | 378 +-
po/eu.po | 1459 +-
po/fa.po | 439 +-
po/fi.po | 2 +-
po/fr.po | 2 +-
po/gl.po | 443 +-
po/gu.po | 2 +-
po/he.po | 560 +-
po/hi.po | 2 +-
po/hu.po | 445 +-
po/id.po | 264 +-
po/it.po | 450 +-
po/ja.po | 2 +-
po/kk.po | 889 +-
po/km.po | 2 +-
po/kn.po | 2 +-
po/ko.po | 2 +-
po/ky.po | 2 +-
po/lt.po | 691 +-
po/lv.po | 374 +-
po/ml.po | 2 +-
po/mr.po | 263 +-
po/nb.po | 362 +-
po/nl.po | 766 +-
po/nn.po | 2 +-
po/or.po | 2 +-
po/pa.po | 2 +-
po/pl.po | 427 +-
po/pt.po | 626 +-
po/pt_BR.po | 720 +-
po/ru.po | 2 +-
po/sk.po | 3452 ++---
po/sl.po | 696 +-
po/sr.po | 462 +-
po/sr latin po | 462 +-
po/sv.po | 2 +-
po/ta.po | 2384 ++--
po/te.po | 2 +-
po/th.po | 432 +-
po/ug.po | 2573 ++--
po/uk.po | 2 +-
po/vi.po | 2 +-
po/zh_CN.po | 2 +-
po/zh_HK.po | 440 +-
po/zh_TW.po | 440 +-
tests/Makefile.am | 1 +
tests/a11y/Makefile.am | 6 +
tests/a11y/about.txt | 49 +-
tests/a11y/accessible-name.txt | 1 +
tests/a11y/assistant.txt | 24 +-
tests/a11y/buttons.txt | 29 +-
tests/a11y/buttons.ui | 17 +
tests/a11y/children.c | 112 +-
tests/a11y/colorchooser.txt | 69 +-
tests/a11y/combos.txt | 18 +-
tests/a11y/derive.c | 73 +
tests/a11y/entries.txt | 64 +-
tests/a11y/entries.ui | 8 +
tests/a11y/expander.txt | 1 +
tests/a11y/hello-world.txt | 1 +
tests/a11y/infobar.txt | 2 +-
tests/a11y/link.txt | 1 +
tests/a11y/lockbutton.txt | 1 +
tests/a11y/menu.txt | 18 +
tests/a11y/menus.txt | 7 +
tests/a11y/messagedialog.txt | 21 +-
tests/a11y/mnemonic.txt | 1 +
tests/a11y/notebook.txt | 2 +
tests/a11y/pickers.txt | 15 +-
tests/a11y/placeholder-text.txt | 3 +
tests/a11y/range.txt | 4 -
tests/a11y/scale-drawvalue.txt | 2 -
tests/a11y/value.c | 127 +
tests/css/Makefile.am | 2 +
tests/css/parser/Makefile.am | 4 +
tests/css/parser/at-valid-10.ref.css | 2 +-
tests/css/parser/at-valid-11.ref.css | 2 +-
tests/css/parser/at-valid-12.ref.css | 2 +-
tests/css/parser/at-valid-13.ref.css | 2 +-
tests/css/parser/at-valid-14.ref.css | 2 +-
tests/css/parser/at-valid-16.ref.css | 2 +-
tests/css/parser/background-shorthand.ref.css | 1000 +-
tests/css/parser/comment-detection.css | 11 +
tests/css/parser/comment-detection.ref.css | 7 +
.../parser/css-21-malformed-declarations.ref.css | 14 +-
tests/css/parser/currentcolor-everywhere.css | 8 +-
tests/css/parser/declarations-invalid-02.ref.css | 2 +-
tests/css/parser/declarations-invalid-03.ref.css | 2 +-
tests/css/parser/declarations-invalid-04.ref.css | 2 +-
tests/css/parser/declarations-invalid-05.ref.css | 2 +-
tests/css/parser/declarations-invalid-06.ref.css | 2 +-
tests/css/parser/declarations-invalid-07.ref.css | 2 +-
tests/css/parser/declarations-valid-09.ref.css | 2 +-
tests/css/parser/linear-gradient.ref.css | 28 +-
tests/css/parser/selector.ref.css | 4 +-
tests/css/parser/shadow.ref.css | 84 +-
tests/prop-editor.c | 44 +-
tests/reftests/Makefile.am | 37 +-
tests/reftests/alignment-props.css | 2 +-
tests/reftests/background-image-multiple.css | 12 +-
tests/reftests/background-position.css | 2 +-
tests/reftests/background-repeat.css | 2 +-
tests/reftests/background-size-zero.css | 11 +
tests/reftests/background-size-zero.ref.ui | 12 +
tests/reftests/background-size-zero.ui | 11 +
tests/reftests/background-window-transparent.css | 4 +-
tests/reftests/border-half-pixel.css | 11 +
tests/reftests/border-half-pixel.ref.ui | 17 +
tests/reftests/border-half-pixel.ui | 16 +
tests/reftests/border-image-excess-size.css | 2 +-
tests/reftests/border-image-gradient.css | 6 +-
tests/reftests/border-image-url.css | 2 +-
tests/reftests/border-style.css | 2 +-
tests/reftests/box-expand.css | 2 +-
tests/reftests/box-packing.css | 4 +-
tests/reftests/box-pseudo-classes.css | 6 +-
tests/reftests/css-match-class.css | 2 +-
tests/reftests/css-match-exact.css | 2 +-
.../reftests/css-match-inherit-different-state.css | 2 +-
tests/reftests/css-match-name.css | 2 +-
tests/reftests/css-match-siblings.css | 4 +-
tests/reftests/css-match-subtype.css | 2 +-
tests/reftests/css-match-type.css | 2 +-
tests/reftests/css-multi-state.css | 2 +-
tests/reftests/font-sizes-names.css | 24 +
tests/reftests/font-sizes-names.ref.ui | 183 +
tests/reftests/font-sizes-names.ui | 184 +
tests/reftests/grid-expand.css | 2 +-
tests/reftests/grid-homogeneous.css | 4 +-
tests/reftests/grid-spacing3.css | 4 +-
tests/reftests/label-ellipsize-small.ref.ui | 15 +
tests/reftests/label-ellipsize-small.ui | 16 +
tests/reftests/label-ellipsize-with-big.ref.ui | 17 +
tests/reftests/label-ellipsize-with-big.ui | 17 +
tests/reftests/label-sizing.css | 2 +-
tests/reftests/label-sizing.ref.ui | 6420 +++-----
tests/reftests/label-sizing.ui | 7684 ++++------
.../reftests/label-width-chars-dont-shrink.ref.ui | 51 +
tests/reftests/label-width-chars-dont-shrink.ui | 53 +
tests/reftests/linear-gradient.css | 18 +-
tests/reftests/named-colors.css | 1176 ++
tests/reftests/named-colors.ref.ui | 2264 +++
tests/reftests/named-colors.ui | 2264 +++
tests/reftests/notebook-childproperties.css | 1 +
tests/reftests/nth-child.css | 8 +-
tests/reftests/opacity.css | 17 +
tests/reftests/opacity.ref.ui | 84 +
tests/reftests/opacity.ui | 87 +
tests/reftests/sizegroups-basics.css | 5 +
tests/reftests/sizegroups-basics.ref.ui | 54 +
tests/reftests/sizegroups-basics.ui | 61 +
.../sizegroups-evolution-identity-page.ref.ui | 244 +
.../reftests/sizegroups-evolution-identity-page.ui | 293 +
.../reftests/sizegroups-get-preferred-null.ref.ui | 21 +
tests/reftests/sizegroups-get-preferred-null.ui | 26 +
tests/reftests/treeview-fixed-height.css | 255 +
tests/reftests/treeview-fixed-height.ref.ui | 79 +
tests/reftests/treeview-fixed-height.ui | 80 +
tests/reftests/treeview-headers-hidden.ref.ui | 45 +
tests/reftests/treeview-headers-hidden.ui | 45 +
tests/reftests/window-border-width.ref.ui | 23 +
tests/reftests/window-border-width.ui | 17 +
tests/testappchooser.c | 3 +-
tests/testappchooserbutton.c | 4 +-
tests/testcalendar.c | 5 +-
tests/testfullscreen.c | 74 +
tests/testgeometry.c | 2 +
tests/testgtk.c | 135 +-
tests/testkineticscrolling.c | 2 +-
tests/testnouiprint.c | 2 -
tests/testoverlaystyleclass.c | 3 +-
tests/testtoplevelembed.c | 2 +
tests/testtreeview.c | 11 +-
tests/visuals/Makefile.am | 2 +
948 files changed, 89005 insertions(+), 62459 deletions(-)
---
diff --cc docs/reference/gtk/gtk-docs.sgml
index e469c72,6260fb8..7c2c2a6
--- a/docs/reference/gtk/gtk-docs.sgml
+++ b/docs/reference/gtk/gtk-docs.sgml
@@@ -230,9 -220,6 +220,7 @@@
<xi:include href="xml/gtkfontbutton.xml" />
<xi:include href="xml/gtkfontchooserwidget.xml" />
<xi:include href="xml/gtkfontchooserdialog.xml" />
- <xi:include href="xml/gtkfontsel.xml" />
- <xi:include href="xml/gtkfontseldlg.xml" />
+ <xi:include href="xml/gtkplacessidebar.xml" />
</chapter>
<chapter id="LayoutContainers">
diff --cc gtk/gtkfilechooserdefault.c
index b65047f,45d53b0..d97bf1a
--- a/gtk/gtkfilechooserdefault.c
+++ b/gtk/gtkfilechooserdefault.c
@@@ -3652,16 -6018,17 +3610,19 @@@ settings_load (GtkFileChooserDefault *i
gboolean show_size_column;
gint sort_column;
GtkSortType sort_order;
+ StartupMode startup_mode;
+ gint sidebar_width;
+ GSettings *settings;
- settings_ensure (impl);
+ settings = _gtk_file_chooser_get_settings_for_widget (GTK_WIDGET (impl));
- location_mode = g_settings_get_enum (impl->settings, SETTINGS_KEY_LOCATION_MODE);
- show_hidden = g_settings_get_boolean (impl->settings, SETTINGS_KEY_SHOW_HIDDEN);
- show_size_column = g_settings_get_boolean (impl->settings, SETTINGS_KEY_SHOW_SIZE_COLUMN);
- sort_column = g_settings_get_enum (impl->settings, SETTINGS_KEY_SORT_COLUMN);
- sort_order = g_settings_get_enum (impl->settings, SETTINGS_KEY_SORT_ORDER);
- startup_mode = g_settings_get_enum (impl->settings, SETTINGS_KEY_STARTUP_MODE);
+ location_mode = g_settings_get_enum (settings, SETTINGS_KEY_LOCATION_MODE);
+ show_hidden = g_settings_get_boolean (settings, SETTINGS_KEY_SHOW_HIDDEN);
+ show_size_column = g_settings_get_boolean (settings, SETTINGS_KEY_SHOW_SIZE_COLUMN);
+ sort_column = g_settings_get_enum (settings, SETTINGS_KEY_SORT_COLUMN);
+ sort_order = g_settings_get_enum (settings, SETTINGS_KEY_SORT_ORDER);
+ sidebar_width = g_settings_get_int (settings, SETTINGS_KEY_SIDEBAR_WIDTH);
++ startup_mode = g_settings_get_enum (settings, SETTINGS_KEY_STARTUP_MODE);
location_mode_set (impl, location_mode, TRUE);
@@@ -3672,6 -6039,6 +3633,8 @@@
impl->sort_column = sort_column;
impl->sort_order = sort_order;
++ impl->startup_mode = startup_mode;
++
/* We don't call set_sort_column() here as the models may not have been
* created yet. The individual functions that create and set the models will
* call set_sort_column() themselves.
@@@ -3748,118 -6082,6 +3678,95 @@@ gtk_file_chooser_default_realize (GtkWi
emit_default_size_changed (impl);
}
- static GFile *
- get_file_for_last_folder_opened (GtkFileChooserDefault *impl)
- {
- char *last_folder_uri;
- GFile *file;
-
- settings_ensure (impl);
-
- last_folder_uri = g_settings_get_string (impl->settings, SETTINGS_KEY_LAST_FOLDER_URI);
-
- /* If no last folder is set, we use the user's home directory, since
- * this is the starting point for most documents.
- */
- if (last_folder_uri[0] == '\0')
- file = g_file_new_for_path (g_get_home_dir ());
- else
- file = g_file_new_for_uri (last_folder_uri);
-
- g_free (last_folder_uri);
-
- return file;
- }
-
+/* Changes the current folder to $CWD */
+static void
+switch_to_cwd (GtkFileChooserDefault *impl)
+{
+ char *current_working_dir;
+
+ current_working_dir = g_get_current_dir ();
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (impl), current_working_dir);
+ g_free (current_working_dir);
+}
+
+/* Sets the file chooser to showing Recent Files or $CWD, depending on the
+ * user's settings.
+ */
+static void
+set_startup_mode (GtkFileChooserDefault *impl)
+{
+ switch (impl->startup_mode)
+ {
+ case STARTUP_MODE_RECENT:
+ operation_mode_set (impl, OPERATION_MODE_RECENT);
+ break;
+
+ case STARTUP_MODE_CWD:
+ switch_to_cwd (impl);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static gboolean
+shortcut_exists (GtkFileChooserDefault *impl, GFile *needle)
+{
+ GSList *haystack;
+ GSList *l;
+ gboolean exists;
+
+ exists = FALSE;
+
+ haystack = gtk_places_sidebar_list_shortcuts (GTK_PLACES_SIDEBAR (impl->places_sidebar));
+ for (l = haystack; l; l = l->next)
+ {
+ GFile *hay;
+
+ hay = G_FILE (l->data);
+ if (g_file_equal (hay, needle))
+ {
+ exists = TRUE;
+ break;
+ }
+ }
+ g_slist_free_full (haystack, g_object_unref);
+
+ return exists;
+}
+
+static void
+add_cwd_to_sidebar_if_needed (GtkFileChooserDefault *impl)
+{
+ char *cwd;
+ GFile *cwd_file;
+ GFile *home_file;
+
+ cwd = g_get_current_dir ();
+ cwd_file = g_file_new_for_path (cwd);
+ g_free (cwd);
+
+ if (shortcut_exists (impl, cwd_file))
+ goto out;
+
+ home_file = g_file_new_for_path (g_get_home_dir ());
+
+ /* We only add an item for $CWD if it is different from $HOME. This way,
+ * applications which get launched from a shell in a terminal (by someone who
+ * knows what they are doing) will get an item for $CWD in the places sidebar,
+ * and "normal" applications launched from the desktop shell (whose $CWD is
+ * $HOME) won't get any extra clutter in the sidebar.
+ */
+ if (!g_file_equal (home_file, cwd_file))
+ gtk_places_sidebar_add_shortcut (GTK_PLACES_SIDEBAR (impl->places_sidebar), cwd_file);
+
+ g_object_unref (home_file);
+
+ out:
+ g_object_unref (cwd_file);
+}
+
/* GtkWidget::map method */
static void
gtk_file_chooser_default_map (GtkWidget *widget)
diff --cc gtk/gtkfilechooserprivate.h
index c8d9d9c,96329ad..4d72d77
--- a/gtk/gtkfilechooserprivate.h
+++ b/gtk/gtkfilechooserprivate.h
@@@ -35,6 -34,15 +35,16 @@@
G_BEGIN_DECLS
+ #define SETTINGS_KEY_LOCATION_MODE "location-mode"
+ #define SETTINGS_KEY_SHOW_HIDDEN "show-hidden"
+ #define SETTINGS_KEY_SHOW_SIZE_COLUMN "show-size-column"
+ #define SETTINGS_KEY_SORT_COLUMN "sort-column"
+ #define SETTINGS_KEY_SORT_ORDER "sort-order"
+ #define SETTINGS_KEY_WINDOW_POSITION "window-position"
+ #define SETTINGS_KEY_WINDOW_SIZE "window-size"
+ #define SETTINGS_KEY_SIDEBAR_WIDTH "sidebar-width"
++#define SETTINGS_KEY_STARTUP_MODE "startup-mode"
+
#define GTK_FILE_CHOOSER_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GTK_TYPE_FILE_CHOOSER,
GtkFileChooserIface))
typedef struct _GtkFileChooserIface GtkFileChooserIface;
@@@ -174,7 -164,14 +173,8 @@@ struct _GtkFileChooserDefaul
/* The file browsing widgets */
GtkWidget *browse_widgets_box;
+ GtkWidget *browse_widgets_hpaned;
GtkWidget *browse_header_box;
- GtkWidget *browse_shortcuts_tree_view;
- GtkWidget *browse_shortcuts_add_button;
- GtkWidget *browse_shortcuts_remove_button;
- GtkWidget *browse_shortcuts_popup_menu;
- GtkWidget *browse_shortcuts_popup_menu_remove_item;
- GtkWidget *browse_shortcuts_popup_menu_rename_item;
GtkWidget *browse_files_tree_view;
GtkWidget *browse_files_popup_menu;
GtkWidget *browse_files_popup_menu_add_shortcut_item;
diff --cc gtk/gtkplacessidebar.c
index fb9475b,0000000..64703c5
mode 100644,000000..100644
--- a/gtk/gtkplacessidebar.c
+++ b/gtk/gtkplacessidebar.c
@@@ -1,4285 -1,0 +1,4306 @@@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/*
+ * GtkPlacesSidebar - sidebar widget for places in the filesystem
+ *
+ * This code comes from Nautilus, GNOME's file manager.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Authors : Mr Jamie McCracken (jamiemcc at blueyonder dot co dot uk)
+ * Cosimo Cecchi <cosimoc gnome org>
+ * Federico Mena Quintero <federico gnome org>
+ *
+ */
+
+/* TODO:
+ *
+ * * Fix instances of "#if DO_NOT_COMPILE"
+ *
+ * * Fix instances of "#if 0"
+ *
+ * * Fix FIXMEs
+ *
+ * * Grep for "NULL-GError" and see if they should be taken care of
+ *
+ * * Although we do g_mount_unmount_with_operation(), Nautilus used to do
+ * nautilus_file_operations_unmount_mount_full() to unmount a volume. With
+ * that, Nautilus does the "volume has trash, empty it first?" dance. Cosimo
+ * suggests that this logic should be part of GtkMountOperation, which can
+ * have Unix-specific code for emptying trash.
+ *
+ * * Sync nautilus commit 17a85b78acc78b573c2e1776b348ed348e19adb7
+ *
+ */
+
+#include "config.h"
+
+#include <gio/gio.h>
+
+#include "gdk/gdkkeysyms.h"
+#include "gtkbookmarksmanager.h"
+#include "gtkcelllayout.h"
+#include "gtkcellrenderertext.h"
+#include "gtkcellrendererpixbuf.h"
+#include "gtkfilechooserprivate.h"
+#include "gtkicontheme.h"
+#include "gtkimagemenuitem.h"
+#include "gtkintl.h"
+#include "gtkmain.h"
+#include "gtkmarshalers.h"
+#include "gtkmenuitem.h"
+#include "gtkmountoperation.h"
+#include "gtkplacessidebar.h"
+#include "gtkscrolledwindow.h"
+#include "gtkseparatormenuitem.h"
+#include "gtksettings.h"
+#include "gtkstock.h"
+#include "gtktrashmonitor.h"
+#include "gtktreeselection.h"
+#include "gtktreednd.h"
+#include "gtktypebuiltins.h"
+#include "gtkwindow.h"
+
+/**
+ * SECTION:gtkplacessidebar
+ * @Short_description: Sidebar that displays frequently-used places in the file system
+ * @Title: GtkPlacesSidebar
+ * @See_also: #GtkFileChooser
+ *
+ * #GtkPlacesSidebar is a widget that displays a list of frequently-used places in the
+ * file system: the user's home directory, the user's bookmarks, and volumes and drives.
+ * This widget is used as a sidebar in #GtkFileChooser and may be used by file managers
+ * and similar programs.
+ *
+ * The places sidebar displays drives and volumes, and will automatically mount
+ * or unmount them when the user selects them.
+ *
+ * Applications can hook to various signals in the places sidebar to customize
+ * its behavior. For example, they can add extra commands to the context menu
+ * of the sidebar.
+ *
+ * While bookmarks are completely in control of the user, the places sidebar also
+ * allows individual applications to provide extra shortcut folders that are unique
+ * to each application. For example, a Paint program may want to add a shortcut
+ * for a Clipart folder. You can do this with gtk_places_sidebar_add_shortcut().
+ *
+ * To make use of the places sidebar, an application at least needs to connect
+ * to the #GtkPlacesSidebar::open-location signal. This is emitted when the
+ * user selects in the sidebar a location to open. The application should also
+ * call gtk_places_sidebar_set_location() when it changes the currently-viewed
+ * location.
+ */
+
+#define EJECT_BUTTON_XPAD 6
+#define ICON_CELL_XPAD 6
+
+#define DO_NOT_COMPILE 0
+
+struct _GtkPlacesSidebar {
+ GtkScrolledWindow parent;
+
+ GtkTreeView *tree_view;
+ GtkCellRenderer *eject_icon_cell_renderer;
+ GtkListStore *store;
+ GtkBookmarksManager *bookmarks_manager;
+ GVolumeMonitor *volume_monitor;
+ GtkTrashMonitor *trash_monitor;
+
+ gulong trash_monitor_changed_id;
+
+ gboolean devices_header_added;
+ gboolean bookmarks_header_added;
+
+ /* DnD */
+ GList *drag_list; /* list of GFile */
+ gboolean drag_data_received;
+ int drag_data_info;
+ gboolean drop_occured;
+
+ GtkWidget *popup_menu;
+
+ /* volume mounting - delayed open process */
+ gboolean mounting;
+ GtkPlacesOpenFlags go_to_after_mount_open_flags;
+
+ GSList *shortcuts;
+
+ GDBusProxy *hostnamed_proxy;
+ GCancellable *hostnamed_cancellable;
+ char *hostname;
+
+ GtkPlacesOpenFlags open_flags;
+
+ guint show_desktop : 1;
+};
+
+struct _GtkPlacesSidebarClass {
+ GtkScrolledWindowClass parent;
+
+ void (* open_location) (GtkPlacesSidebar *sidebar,
+ GFile *location,
+ GtkPlacesOpenFlags open_flags);
+ void (* populate_popup) (GtkPlacesSidebar *sidebar,
+ GtkMenu *menu,
+ GFile *selected_item);
+ void (* show_error_message) (GtkPlacesSidebar *sidebar,
+ const char *primary,
+ const char *secondary);
+ void (* drag_action_requested) (GtkPlacesSidebar *sidebar,
+ GdkDragContext *context,
+ GFile *dest_file,
+ GList *source_file_list,
+ int *action);
+ GdkDragAction (* drag_action_ask) (GtkPlacesSidebar *sidebar,
+ GdkDragAction actions);
+ void (* drag_perform_drop) (GtkPlacesSidebar *sidebar,
+ GFile *dest_file,
+ GList *source_file_list,
+ GdkDragAction action);
+};
+
+enum {
+ PLACES_SIDEBAR_COLUMN_ROW_TYPE,
+ PLACES_SIDEBAR_COLUMN_URI,
+ PLACES_SIDEBAR_COLUMN_DRIVE,
+ PLACES_SIDEBAR_COLUMN_VOLUME,
+ PLACES_SIDEBAR_COLUMN_MOUNT,
+ PLACES_SIDEBAR_COLUMN_NAME,
+ PLACES_SIDEBAR_COLUMN_GICON,
+ PLACES_SIDEBAR_COLUMN_INDEX,
+ PLACES_SIDEBAR_COLUMN_EJECT,
+ PLACES_SIDEBAR_COLUMN_NO_EJECT,
+ PLACES_SIDEBAR_COLUMN_BOOKMARK,
+ PLACES_SIDEBAR_COLUMN_TOOLTIP,
+ PLACES_SIDEBAR_COLUMN_SECTION_TYPE,
+ PLACES_SIDEBAR_COLUMN_HEADING_TEXT,
+
+ PLACES_SIDEBAR_COLUMN_COUNT
+};
+
+typedef enum {
+ PLACES_BUILT_IN,
+ PLACES_XDG_DIR,
+ PLACES_MOUNTED_VOLUME,
+ PLACES_BOOKMARK,
+ PLACES_HEADING,
+} PlaceType;
+
+typedef enum {
+ SECTION_DEVICES,
+ SECTION_BOOKMARKS,
+ SECTION_COMPUTER,
+ SECTION_NETWORK,
+} SectionType;
+
+enum {
+ OPEN_LOCATION,
+ POPULATE_POPUP,
+ SHOW_ERROR_MESSAGE,
+ DRAG_ACTION_REQUESTED,
+ DRAG_ACTION_ASK,
+ DRAG_PERFORM_DROP,
+ LAST_SIGNAL,
+};
+
+enum {
+ PROP_LOCATION = 1,
+ PROP_OPEN_FLAGS,
+ PROP_SHOW_DESKTOP,
+ NUM_PROPERTIES,
+};
+
+/* Names for themed icons */
+#define ICON_NAME_HOME "user-home-symbolic"
+#define ICON_NAME_DESKTOP "user-desktop"
+#define ICON_NAME_FILESYSTEM "drive-harddisk-symbolic"
+#define ICON_NAME_EJECT "media-eject-symbolic"
+#define ICON_NAME_NETWORK "network-workgroup-symbolic"
+
+#define ICON_NAME_FOLDER_DESKTOP "user-desktop"
+#define ICON_NAME_FOLDER_DOCUMENTS "folder-documents-symbolic"
+#define ICON_NAME_FOLDER_DOWNLOAD "folder-download-symbolic"
+#define ICON_NAME_FOLDER_MUSIC "folder-music-symbolic"
+#define ICON_NAME_FOLDER_PICTURES "folder-pictures-symbolic"
+#define ICON_NAME_FOLDER_PUBLIC_SHARE "folder-publicshare-symbolic"
+#define ICON_NAME_FOLDER_TEMPLATES "folder-templates-symbolic"
+#define ICON_NAME_FOLDER_VIDEOS "folder-videos-symbolic"
+#define ICON_NAME_FOLDER_SAVED_SEARCH "folder-saved-search-symbolic"
+
+/* Settings keys */
+#define SETTINGS_KEY_STARTUP_MODE "startup-mode"
+
+static guint places_sidebar_signals [LAST_SIGNAL] = { 0 };
+static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
+
+static void open_selected_bookmark (GtkPlacesSidebar *sidebar,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ GtkPlacesOpenFlags open_flags);
+static gboolean eject_or_unmount_bookmark (GtkPlacesSidebar *sidebar,
+ GtkTreePath *path);
+static gboolean eject_or_unmount_selection (GtkPlacesSidebar *sidebar);
+static void check_unmount_and_eject (GMount *mount,
+ GVolume *volume,
+ GDrive *drive,
+ gboolean *show_unmount,
+ gboolean *show_eject);
+
+/* Identifiers for target types */
+enum {
+ GTK_TREE_MODEL_ROW,
+ TEXT_URI_LIST
+};
+
+/* Target types for dragging from the shortcuts list */
+static const GtkTargetEntry dnd_source_targets[] = {
+ { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, GTK_TREE_MODEL_ROW }
+};
+
+/* Target types for dropping into the shortcuts list */
+static const GtkTargetEntry dnd_drop_targets [] = {
+ { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, GTK_TREE_MODEL_ROW },
+ { "text/uri-list", 0, TEXT_URI_LIST }
+};
+
+/* Drag and drop interface declarations */
+typedef struct {
+ GtkListStore parent;
+
+ GtkPlacesSidebar *sidebar;
+} ShortcutsModel;
+
+typedef struct {
+ GtkListStoreClass parent_class;
+} ShortcutsModelClass;
+
+#define SHORTCUTS_MODEL_TYPE (shortcuts_model_get_type ())
+#define SHORTCUTS_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHORTCUTS_MODEL_TYPE, ShortcutsModel))
+
+static GType shortcuts_model_get_type (void);
+static void shortcuts_model_drag_source_iface_init (GtkTreeDragSourceIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (ShortcutsModel,
+ shortcuts_model,
+ GTK_TYPE_LIST_STORE,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
+ shortcuts_model_drag_source_iface_init));
+
+static GtkListStore *shortcuts_model_new (GtkPlacesSidebar *sidebar);
+
+G_DEFINE_TYPE (GtkPlacesSidebar, gtk_places_sidebar, GTK_TYPE_SCROLLED_WINDOW);
+
+static void
+emit_open_location (GtkPlacesSidebar *sidebar, GFile *location, GtkPlacesOpenFlags open_flags)
+{
+ if ((open_flags & sidebar->open_flags) == 0)
+ open_flags = GTK_PLACES_OPEN_NORMAL;
+
+ g_signal_emit (sidebar, places_sidebar_signals[OPEN_LOCATION], 0,
+ location, open_flags);
+}
+
+static void
+emit_populate_popup (GtkPlacesSidebar *sidebar, GtkMenu *menu, GFile *selected_item)
+{
+ g_signal_emit (sidebar, places_sidebar_signals[POPULATE_POPUP], 0,
+ menu, selected_item);
+}
+
+static void
+emit_show_error_message (GtkPlacesSidebar *sidebar, const char *primary, const char *secondary)
+{
+ g_signal_emit (sidebar, places_sidebar_signals[SHOW_ERROR_MESSAGE], 0,
+ primary, secondary);
+}
+
+static void
+emit_drag_action_requested (GtkPlacesSidebar *sidebar,
+ GdkDragContext *context,
+ GFile *dest_file,
+ GList *source_file_list,
+ int *action)
+{
+ g_signal_emit (sidebar, places_sidebar_signals[DRAG_ACTION_REQUESTED], 0,
+ context,
+ dest_file,
+ source_file_list,
+ action);
+}
+
+static GdkDragAction
+emit_drag_action_ask (GtkPlacesSidebar *sidebar,
+ GdkDragAction actions)
+{
+ GdkDragAction ret_action;
+
+ ret_action = 0;
+
+ g_signal_emit (sidebar, places_sidebar_signals[DRAG_ACTION_ASK], 0,
+ actions,
+ &ret_action);
+ return ret_action;
+}
+
+static void
+emit_drag_perform_drop (GtkPlacesSidebar *sidebar,
+ GFile *dest_file,
+ GList *source_file_list,
+ GdkDragAction action)
+{
+ g_signal_emit (sidebar, places_sidebar_signals[DRAG_PERFORM_DROP], 0,
+ dest_file,
+ source_file_list,
+ action);
+}
+
+static gint
+get_icon_size (GtkPlacesSidebar *sidebar)
+{
+ GtkSettings *settings;
+ gint width, height;
+
+ settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (sidebar)));
+
+ if (gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU, &width, &height))
+ return MAX (width, height);
+ else
+ return 16;
+}
+
+static GtkTreeIter
+add_heading (GtkPlacesSidebar *sidebar,
+ SectionType section_type,
+ const gchar *title)
+{
+ GtkTreeIter iter;
+
+ gtk_list_store_append (sidebar->store, &iter);
+ gtk_list_store_set (sidebar->store, &iter,
+ PLACES_SIDEBAR_COLUMN_ROW_TYPE, PLACES_HEADING,
+ PLACES_SIDEBAR_COLUMN_SECTION_TYPE, section_type,
+ PLACES_SIDEBAR_COLUMN_HEADING_TEXT, title,
+ PLACES_SIDEBAR_COLUMN_EJECT, FALSE,
+ PLACES_SIDEBAR_COLUMN_NO_EJECT, TRUE,
+ -1);
+
+ return iter;
+}
+
+static void
+check_heading_for_section (GtkPlacesSidebar *sidebar,
+ SectionType section_type)
+{
+ switch (section_type) {
+ case SECTION_DEVICES:
+ if (!sidebar->devices_header_added) {
+ add_heading (sidebar, SECTION_DEVICES,
+ _("Devices"));
+ sidebar->devices_header_added = TRUE;
+ }
+
+ break;
+ case SECTION_BOOKMARKS:
+ if (!sidebar->bookmarks_header_added) {
+ add_heading (sidebar, SECTION_BOOKMARKS,
+ _("Bookmarks"));
+ sidebar->bookmarks_header_added = TRUE;
+ }
+
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+add_place (GtkPlacesSidebar *sidebar,
+ PlaceType place_type,
+ SectionType section_type,
+ const char *name,
+ GIcon *icon,
+ const char *uri,
+ GDrive *drive,
+ GVolume *volume,
+ GMount *mount,
+ const int index,
+ const char *tooltip)
+{
+ GtkTreeIter iter;
+ gboolean show_eject, show_unmount;
+ gboolean show_eject_button;
+
+ check_heading_for_section (sidebar, section_type);
+
+ check_unmount_and_eject (mount, volume, drive,
+ &show_unmount, &show_eject);
+
+ if (show_unmount || show_eject) {
+ g_assert (place_type != PLACES_BOOKMARK);
+ }
+
+ if (mount == NULL) {
+ show_eject_button = FALSE;
+ } else {
+ show_eject_button = (show_unmount || show_eject);
+ }
+
+ gtk_list_store_append (sidebar->store, &iter);
+ gtk_list_store_set (sidebar->store, &iter,
+ PLACES_SIDEBAR_COLUMN_GICON, icon,
+ PLACES_SIDEBAR_COLUMN_NAME, name,
+ PLACES_SIDEBAR_COLUMN_URI, uri,
+ PLACES_SIDEBAR_COLUMN_DRIVE, drive,
+ PLACES_SIDEBAR_COLUMN_VOLUME, volume,
+ PLACES_SIDEBAR_COLUMN_MOUNT, mount,
+ PLACES_SIDEBAR_COLUMN_ROW_TYPE, place_type,
+ PLACES_SIDEBAR_COLUMN_INDEX, index,
+ PLACES_SIDEBAR_COLUMN_EJECT, show_eject_button,
+ PLACES_SIDEBAR_COLUMN_NO_EJECT, !show_eject_button,
+ PLACES_SIDEBAR_COLUMN_BOOKMARK, place_type != PLACES_BOOKMARK,
+ PLACES_SIDEBAR_COLUMN_TOOLTIP, tooltip,
+ PLACES_SIDEBAR_COLUMN_SECTION_TYPE, section_type,
+ -1);
+}
+
+static GIcon *
+special_directory_get_gicon (GUserDirectory directory)
+{
+#define ICON_CASE(x) \
+ case G_USER_DIRECTORY_ ## x: \
+ return g_themed_icon_new (ICON_NAME_FOLDER_ ## x);
+
+ switch (directory) {
+
+ ICON_CASE (DOCUMENTS);
+ ICON_CASE (DOWNLOAD);
+ ICON_CASE (MUSIC);
+ ICON_CASE (PICTURES);
+ ICON_CASE (PUBLIC_SHARE);
+ ICON_CASE (TEMPLATES);
+ ICON_CASE (VIDEOS);
+
+ default:
+ return g_themed_icon_new ("folder-symbolic");
+ }
+
+#undef ICON_CASE
+}
+
+static gboolean
- recent_is_supported (void)
++recent_files_setting_is_enabled (GtkPlacesSidebar *sidebar)
++{
++ GtkSettings *settings;
++ gboolean enabled;
++
++ if (gtk_widget_has_screen (GTK_WIDGET (sidebar)))
++ settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (sidebar)));
++ else
++ settings = gtk_settings_get_default ();
++
++ g_object_get (settings, "gtk-recent-files-enabled", &enabled, NULL);
++ return enabled;
++}
++
++static gboolean
++recent_scheme_is_supported (void)
+{
+ const char * const *supported;
+ int i;
+
+ supported = g_vfs_get_supported_uri_schemes (g_vfs_get_default ());
+ if (!supported) {
+ return FALSE;
+ }
+
+ for (i = 0; supported[i] != NULL; i++) {
+ if (strcmp ("recent", supported[i]) == 0) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
++static gboolean
++should_show_recent (GtkPlacesSidebar *sidebar)
++{
++ return recent_files_setting_is_enabled (sidebar) && recent_scheme_is_supported ();
++}
++
+static void
+add_special_dirs (GtkPlacesSidebar *sidebar)
+{
+ GList *dirs;
+ int index;
+
+ dirs = NULL;
+ for (index = 0; index < G_USER_N_DIRECTORIES; index++) {
+ const char *path;
+ GFile *root;
+ GIcon *icon;
+ char *name;
+ char *mount_uri;
+ char *tooltip;
+
+ if (!_gtk_bookmarks_manager_get_is_xdg_dir_builtin (index)) {
+ continue;
+ }
+
+ path = g_get_user_special_dir (index);
+
+ /* xdg resets special dirs to the home directory in case
+ * it's not finiding what it expects. We don't want the home
+ * to be added multiple times in that weird configuration.
+ */
+ if (path == NULL
+ || g_strcmp0 (path, g_get_home_dir ()) == 0
+ || g_list_find_custom (dirs, path, (GCompareFunc) g_strcmp0) != NULL) {
+ continue;
+ }
+
+ root = g_file_new_for_path (path);
+
+ name = _gtk_bookmarks_manager_get_bookmark_label (sidebar->bookmarks_manager, root);
+ if (!name) {
+ name = g_file_get_basename (root);
+ }
+
+ icon = special_directory_get_gicon (index);
+ mount_uri = g_file_get_uri (root);
+ tooltip = g_file_get_parse_name (root);
+
+ add_place (sidebar, PLACES_XDG_DIR,
+ SECTION_COMPUTER,
+ name, icon, mount_uri,
+ NULL, NULL, NULL, 0,
+ tooltip);
+ g_free (name);
+ g_object_unref (root);
+ g_object_unref (icon);
+ g_free (mount_uri);
+ g_free (tooltip);
+
+ dirs = g_list_prepend (dirs, (char *)path);
+ }
+
+ g_list_free (dirs);
+}
+
+static char *
+get_home_directory_uri (void)
+{
+ const char *home;
+
+ home = g_get_home_dir ();
+ if (!home)
+ return NULL;
+
+ return g_strconcat ("file://", home, NULL);
+}
+
+static char *
+get_desktop_directory_uri (void)
+{
+ const char *name;
+
+ name = g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP);
+ /* "To disable a directory, point it to the homedir."
+ * See http://freedesktop.org/wiki/Software/xdg-user-dirs
+ **/
+ if (!g_strcmp0 (name, g_get_home_dir ())) {
+ return NULL;
+ } else {
+ return g_strconcat ("file://", name, NULL);
+ }
+}
+
+static void
+add_application_shortcuts (GtkPlacesSidebar *sidebar)
+{
+ GSList *l;
+
+ for (l = sidebar->shortcuts; l; l = l->next) {
+ GFile *file;
+ GFileInfo *info;
+
+ file = G_FILE (l->data);
+
+ /* FIXME: we are getting file info synchronously. We may want to do it async at some point.
*/
+ info = g_file_query_info (file,
+ "standard::display-name,standard::symbolic-icon",
+ G_FILE_QUERY_INFO_NONE,
+ NULL,
+ NULL); /* NULL-GError */
+
+ if (info) {
+ char *uri;
+ char *tooltip;
+ const char *name;
+ GIcon *icon;
+
+ name = g_file_info_get_display_name (info);
+ icon = g_file_info_get_symbolic_icon (info);
+
+ uri = g_file_get_uri (file);
+ tooltip = g_file_get_parse_name (file);
+
+ add_place (sidebar, PLACES_BUILT_IN,
+ SECTION_COMPUTER,
+ name, icon, uri,
+ NULL, NULL, NULL, 0,
+ tooltip);
+
+ g_free (uri);
+ g_free (tooltip);
+
+ g_object_unref (info);
+ }
+ }
+}
+
+static gboolean
+get_selected_iter (GtkPlacesSidebar *sidebar,
+ GtkTreeIter *iter)
+{
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection (sidebar->tree_view);
+
+ return gtk_tree_selection_get_selected (selection, NULL, iter);
+}
+
+static void
+update_places (GtkPlacesSidebar *sidebar)
+{
+ GtkTreeIter iter;
+ GVolumeMonitor *volume_monitor;
+ GList *mounts, *l, *ll;
+ GMount *mount;
+ GList *drives;
+ GDrive *drive;
+ GList *volumes;
+ GVolume *volume;
+ GSList *bookmarks, *sl;
+ int index;
+ char *original_uri, *mount_uri, *name, *identifier;
+ char *home_uri;
+ char *bookmark_name;
+ GIcon *icon;
+ GFile *root;
+ char *tooltip;
+ GList *network_mounts, *network_volumes;
+
+ /* save original selection */
+ if (get_selected_iter (sidebar, &iter)) {
+ gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store),
+ &iter,
+ PLACES_SIDEBAR_COLUMN_URI, &original_uri, -1);
+ } else
+ original_uri = NULL;
+
+ gtk_list_store_clear (sidebar->store);
+
+ sidebar->devices_header_added = FALSE;
+ sidebar->bookmarks_header_added = FALSE;
+
+ network_mounts = network_volumes = NULL;
+ volume_monitor = sidebar->volume_monitor;
+
+ /* add built in bookmarks */
+
+ add_heading (sidebar, SECTION_COMPUTER,
+ _("Places"));
+
- if (recent_is_supported ()) {
++ if (should_show_recent (sidebar)) {
+ mount_uri = "recent:///"; /* No need to strdup */
+ icon = g_themed_icon_new ("document-open-recent-symbolic");
+ add_place (sidebar, PLACES_BUILT_IN,
+ SECTION_COMPUTER,
+ _("Recent"), icon, mount_uri,
+ NULL, NULL, NULL, 0,
+ _("Recent files"));
+ g_object_unref (icon);
+ }
+
+ /* home folder */
+ home_uri = get_home_directory_uri ();
+ icon = g_themed_icon_new (ICON_NAME_HOME);
+ add_place (sidebar, PLACES_BUILT_IN,
+ SECTION_COMPUTER,
+ _("Home"), icon,
+ home_uri, NULL, NULL, NULL, 0,
+ _("Open your personal folder"));
+ g_object_unref (icon);
+ g_free (home_uri);
+
+ if (sidebar->show_desktop) {
+ /* desktop */
+ mount_uri = get_desktop_directory_uri ();
+ icon = g_themed_icon_new (ICON_NAME_DESKTOP);
+ add_place (sidebar, PLACES_BUILT_IN,
+ SECTION_COMPUTER,
+ _("Desktop"), icon,
+ mount_uri, NULL, NULL, NULL, 0,
+ _("Open the contents of your desktop in a folder"));
+ g_object_unref (icon);
+ g_free (mount_uri);
+ }
+
+ /* XDG directories */
+ add_special_dirs (sidebar);
+
+ /* Trash */
+ mount_uri = "trash:///"; /* No need to strdup */
+ icon = _gtk_trash_monitor_get_icon (sidebar->trash_monitor);
+ add_place (sidebar, PLACES_BUILT_IN,
+ SECTION_COMPUTER,
+ _("Trash"), icon, mount_uri,
+ NULL, NULL, NULL, 0,
+ _("Open the trash"));
+ g_object_unref (icon);
+
+ /* Application-side shortcuts */
+ add_application_shortcuts (sidebar);
+
+ /* go through all connected drives */
+ drives = g_volume_monitor_get_connected_drives (volume_monitor);
+
+ for (l = drives; l != NULL; l = l->next) {
+ drive = l->data;
+
+ volumes = g_drive_get_volumes (drive);
+ if (volumes != NULL) {
+ for (ll = volumes; ll != NULL; ll = ll->next) {
+ volume = ll->data;
+ identifier = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_CLASS);
+
+ if (g_strcmp0 (identifier, "network") == 0) {
+ g_free (identifier);
+ network_volumes = g_list_prepend (network_volumes, volume);
+ continue;
+ }
+ g_free (identifier);
+
+ mount = g_volume_get_mount (volume);
+ if (mount != NULL) {
+ /* Show mounted volume in the sidebar */
+ icon = g_mount_get_symbolic_icon (mount);
+ root = g_mount_get_default_location (mount);
+ mount_uri = g_file_get_uri (root);
+ name = g_mount_get_name (mount);
+ tooltip = g_file_get_parse_name (root);
+
+ add_place (sidebar, PLACES_MOUNTED_VOLUME,
+ SECTION_DEVICES,
+ name, icon, mount_uri,
+ drive, volume, mount, 0, tooltip);
+ g_object_unref (root);
+ g_object_unref (mount);
+ g_object_unref (icon);
+ g_free (tooltip);
+ g_free (name);
+ g_free (mount_uri);
+ } else {
+ /* Do show the unmounted volumes in the sidebar;
+ * this is so the user can mount it (in case automounting
+ * is off).
+ *
+ * Also, even if automounting is enabled, this gives a visual
+ * cue that the user should remember to yank out the media if
+ * he just unmounted it.
+ */
+ icon = g_volume_get_symbolic_icon (volume);
+ name = g_volume_get_name (volume);
+ tooltip = g_strdup_printf (_("Mount and open %s"), name);
+
+ add_place (sidebar, PLACES_MOUNTED_VOLUME,
+ SECTION_DEVICES,
+ name, icon, NULL,
+ drive, volume, NULL, 0, tooltip);
+ g_object_unref (icon);
+ g_free (name);
+ g_free (tooltip);
+ }
+ g_object_unref (volume);
+ }
+ g_list_free (volumes);
+ } else {
+ if (g_drive_is_media_removable (drive) && !g_drive_is_media_check_automatic (drive)) {
+ /* If the drive has no mountable volumes and we cannot detect media change..
we
+ * display the drive in the sidebar so the user can manually poll the drive by
+ * right clicking and selecting "Rescan..."
+ *
+ * This is mainly for drives like floppies where media detection doesn't
+ * work.. but it's also for human beings who like to turn off media detection
+ * in the OS to save battery juice.
+ */
+ icon = g_drive_get_symbolic_icon (drive);
+ name = g_drive_get_name (drive);
+ tooltip = g_strdup_printf (_("Mount and open %s"), name);
+
+ add_place (sidebar, PLACES_BUILT_IN,
+ SECTION_DEVICES,
+ name, icon, NULL,
+ drive, NULL, NULL, 0, tooltip);
+ g_object_unref (icon);
+ g_free (tooltip);
+ g_free (name);
+ }
+ }
+ g_object_unref (drive);
+ }
+ g_list_free (drives);
+
+ /* add all volumes that is not associated with a drive */
+ volumes = g_volume_monitor_get_volumes (volume_monitor);
+ for (l = volumes; l != NULL; l = l->next) {
+ volume = l->data;
+ drive = g_volume_get_drive (volume);
+ if (drive != NULL) {
+ g_object_unref (volume);
+ g_object_unref (drive);
+ continue;
+ }
+
+ identifier = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_CLASS);
+
+ if (g_strcmp0 (identifier, "network") == 0) {
+ g_free (identifier);
+ network_volumes = g_list_prepend (network_volumes, volume);
+ continue;
+ }
+ g_free (identifier);
+
+ mount = g_volume_get_mount (volume);
+ if (mount != NULL) {
+ icon = g_mount_get_symbolic_icon (mount);
+ root = g_mount_get_default_location (mount);
+ mount_uri = g_file_get_uri (root);
+ tooltip = g_file_get_parse_name (root);
+ g_object_unref (root);
+ name = g_mount_get_name (mount);
+ add_place (sidebar, PLACES_MOUNTED_VOLUME,
+ SECTION_DEVICES,
+ name, icon, mount_uri,
+ NULL, volume, mount, 0, tooltip);
+ g_object_unref (mount);
+ g_object_unref (icon);
+ g_free (name);
+ g_free (tooltip);
+ g_free (mount_uri);
+ } else {
+ /* see comment above in why we add an icon for an unmounted mountable volume */
+ icon = g_volume_get_symbolic_icon (volume);
+ name = g_volume_get_name (volume);
+ add_place (sidebar, PLACES_MOUNTED_VOLUME,
+ SECTION_DEVICES,
+ name, icon, NULL,
+ NULL, volume, NULL, 0, name);
+ g_object_unref (icon);
+ g_free (name);
+ }
+ g_object_unref (volume);
+ }
+ g_list_free (volumes);
+
+ /* file system root */
+
+ mount_uri = "file:///"; /* No need to strdup */
+ icon = g_themed_icon_new (ICON_NAME_FILESYSTEM);
+ add_place (sidebar, PLACES_BUILT_IN,
+ SECTION_DEVICES,
+ sidebar->hostname, icon,
+ mount_uri, NULL, NULL, NULL, 0,
+ _("Open the contents of the File System"));
+ g_object_unref (icon);
+
+ /* add mounts that has no volume (/etc/mtab mounts, ftp, sftp,...) */
+ mounts = g_volume_monitor_get_mounts (volume_monitor);
+
+ for (l = mounts; l != NULL; l = l->next) {
+ mount = l->data;
+ if (g_mount_is_shadowed (mount)) {
+ g_object_unref (mount);
+ continue;
+ }
+ volume = g_mount_get_volume (mount);
+ if (volume != NULL) {
+ g_object_unref (volume);
+ g_object_unref (mount);
+ continue;
+ }
+ root = g_mount_get_default_location (mount);
+
+ if (!g_file_is_native (root)) {
+ network_mounts = g_list_prepend (network_mounts, mount);
+ g_object_unref (root);
+ continue;
+ }
+
+ icon = g_mount_get_symbolic_icon (mount);
+ mount_uri = g_file_get_uri (root);
+ name = g_mount_get_name (mount);
+ tooltip = g_file_get_parse_name (root);
+ add_place (sidebar, PLACES_MOUNTED_VOLUME,
+ SECTION_COMPUTER,
+ name, icon, mount_uri,
+ NULL, NULL, mount, 0, tooltip);
+ g_object_unref (root);
+ g_object_unref (mount);
+ g_object_unref (icon);
+ g_free (name);
+ g_free (mount_uri);
+ g_free (tooltip);
+ }
+ g_list_free (mounts);
+
+ /* add bookmarks */
+
+ bookmarks = _gtk_bookmarks_manager_list_bookmarks (sidebar->bookmarks_manager);
+
+ for (sl = bookmarks, index = 0; sl; sl = sl->next, index++) {
+ GFileInfo *info;
+
+ root = sl->data;
+
+#if 0
+ /* FIXME: remove this? If we *do* show bookmarks for nonexistent files, the user will
eventually clean them up */
+ if (!nautilus_bookmark_get_exists (bookmark)) {
+ continue;
+ }
+#endif
+
+ if (_gtk_bookmarks_manager_get_is_builtin (sidebar->bookmarks_manager, root)) {
+ continue;
+ }
+
+ /* FIXME: we are getting file info synchronously. We may want to do it async at some point.
*/
+ info = g_file_query_info (root,
+ "standard::display-name,standard::symbolic-icon",
+ G_FILE_QUERY_INFO_NONE,
+ NULL,
+ NULL); /* NULL-GError */
+
+ if (info) {
+ bookmark_name = _gtk_bookmarks_manager_get_bookmark_label
(sidebar->bookmarks_manager, root);
+
+ if (bookmark_name == NULL)
+ bookmark_name = g_strdup (g_file_info_get_display_name (info));
+
+ icon = g_file_info_get_symbolic_icon (info);
+
+ mount_uri = g_file_get_uri (root);
+ tooltip = g_file_get_parse_name (root);
+
+ add_place (sidebar, PLACES_BOOKMARK,
+ SECTION_BOOKMARKS,
+ bookmark_name, icon, mount_uri,
+ NULL, NULL, NULL, index,
+ tooltip);
+
+ g_free (mount_uri);
+ g_free (tooltip);
+ g_free (bookmark_name);
+
+ g_object_unref (info);
+ }
+ }
+
+ g_slist_foreach (bookmarks, (GFunc) g_object_unref, NULL);
+ g_slist_free (bookmarks);
+
+ /* network */
+ add_heading (sidebar, SECTION_NETWORK,
+ _("Network"));
+
+ mount_uri = "network:///"; /* No need to strdup */
+ icon = g_themed_icon_new (ICON_NAME_NETWORK);
+ add_place (sidebar, PLACES_BUILT_IN,
+ SECTION_NETWORK,
+ _("Browse Network"), icon,
+ mount_uri, NULL, NULL, NULL, 0,
+ _("Browse the contents of the network"));
+ g_object_unref (icon);
+
+ network_volumes = g_list_reverse (network_volumes);
+ for (l = network_volumes; l != NULL; l = l->next) {
+ volume = l->data;
+ mount = g_volume_get_mount (volume);
+
+ if (mount != NULL) {
+ network_mounts = g_list_prepend (network_mounts, mount);
+ continue;
+ } else {
+ icon = g_volume_get_symbolic_icon (volume);
+ name = g_volume_get_name (volume);
+ tooltip = g_strdup_printf (_("Mount and open %s"), name);
+
+ add_place (sidebar, PLACES_MOUNTED_VOLUME,
+ SECTION_NETWORK,
+ name, icon, NULL,
+ NULL, volume, NULL, 0, tooltip);
+ g_object_unref (icon);
+ g_free (name);
+ g_free (tooltip);
+ }
+ }
+
+ g_list_free_full (network_volumes, g_object_unref);
+
+ network_mounts = g_list_reverse (network_mounts);
+ for (l = network_mounts; l != NULL; l = l->next) {
+ mount = l->data;
+ root = g_mount_get_default_location (mount);
+ icon = g_mount_get_symbolic_icon (mount);
+ mount_uri = g_file_get_uri (root);
+ name = g_mount_get_name (mount);
+ tooltip = g_file_get_parse_name (root);
+ add_place (sidebar, PLACES_MOUNTED_VOLUME,
+ SECTION_NETWORK,
+ name, icon, mount_uri,
+ NULL, NULL, mount, 0, tooltip);
+ g_object_unref (root);
+ g_object_unref (mount);
+ g_object_unref (icon);
+ g_free (name);
+ g_free (mount_uri);
+ g_free (tooltip);
+ }
+
+ g_list_free_full (network_mounts, g_object_unref);
+
+ /* restore original selection */
+ if (original_uri) {
+ GFile *restore;
+
+ restore = g_file_new_for_uri (original_uri);
+ gtk_places_sidebar_set_location (sidebar, restore);
+ g_object_unref (restore);
+
+ g_free (original_uri);
+ }
+}
+
+static void
+mount_added_callback (GVolumeMonitor *volume_monitor,
+ GMount *mount,
+ GtkPlacesSidebar *sidebar)
+{
+ update_places (sidebar);
+}
+
+static void
+mount_removed_callback (GVolumeMonitor *volume_monitor,
+ GMount *mount,
+ GtkPlacesSidebar *sidebar)
+{
+ update_places (sidebar);
+}
+
+static void
+mount_changed_callback (GVolumeMonitor *volume_monitor,
+ GMount *mount,
+ GtkPlacesSidebar *sidebar)
+{
+ update_places (sidebar);
+}
+
+static void
+volume_added_callback (GVolumeMonitor *volume_monitor,
+ GVolume *volume,
+ GtkPlacesSidebar *sidebar)
+{
+ update_places (sidebar);
+}
+
+static void
+volume_removed_callback (GVolumeMonitor *volume_monitor,
+ GVolume *volume,
+ GtkPlacesSidebar *sidebar)
+{
+ update_places (sidebar);
+}
+
+static void
+volume_changed_callback (GVolumeMonitor *volume_monitor,
+ GVolume *volume,
+ GtkPlacesSidebar *sidebar)
+{
+ update_places (sidebar);
+}
+
+static void
+drive_disconnected_callback (GVolumeMonitor *volume_monitor,
+ GDrive *drive,
+ GtkPlacesSidebar *sidebar)
+{
+ update_places (sidebar);
+}
+
+static void
+drive_connected_callback (GVolumeMonitor *volume_monitor,
+ GDrive *drive,
+ GtkPlacesSidebar *sidebar)
+{
+ update_places (sidebar);
+}
+
+static void
+drive_changed_callback (GVolumeMonitor *volume_monitor,
+ GDrive *drive,
+ GtkPlacesSidebar *sidebar)
+{
+ update_places (sidebar);
+}
+
+static gboolean
+over_eject_button (GtkPlacesSidebar *sidebar,
+ gint x,
+ gint y,
+ GtkTreePath **path)
+{
+ GtkTreeViewColumn *column;
+ int width, x_offset, hseparator;
+ int eject_button_size;
+ gboolean show_eject;
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+
+ *path = NULL;
+ model = gtk_tree_view_get_model (sidebar->tree_view);
+
+ if (gtk_tree_view_get_path_at_pos (sidebar->tree_view,
+ x, y,
+ path, &column, NULL, NULL)) {
+
+ gtk_tree_model_get_iter (model, &iter, *path);
+ gtk_tree_model_get (model, &iter,
+ PLACES_SIDEBAR_COLUMN_EJECT, &show_eject,
+ -1);
+
+ if (!show_eject) {
+ goto out;
+ }
+
+
+ gtk_widget_style_get (GTK_WIDGET (sidebar->tree_view),
+ "horizontal-separator", &hseparator,
+ NULL);
+
+ /* Reload cell attributes for this particular row */
+ gtk_tree_view_column_cell_set_cell_data (column,
+ model, &iter, FALSE, FALSE);
+
+ gtk_tree_view_column_cell_get_position (column,
+ sidebar->eject_icon_cell_renderer,
+ &x_offset, &width);
+
+ eject_button_size = get_icon_size (sidebar);
+
+ /* This is kinda weird, but we have to do it to workaround gtk+ expanding
+ * the eject cell renderer (even thought we told it not to) and we then
+ * had to set it right-aligned */
+ x_offset += width - hseparator - EJECT_BUTTON_XPAD - eject_button_size;
+
+ if (x - x_offset >= 0 &&
+ x - x_offset <= eject_button_size) {
+ return TRUE;
+ }
+ }
+
+ out:
+ if (*path != NULL) {
+ gtk_tree_path_free (*path);
+ *path = NULL;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+clicked_eject_button (GtkPlacesSidebar *sidebar,
+ GtkTreePath **path)
+{
+ GdkEvent *event = gtk_get_current_event ();
+ GdkEventButton *button_event = (GdkEventButton *) event;
+
+ if ((event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) &&
+ over_eject_button (sidebar, button_event->x, button_event->y, path)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+pos_is_into_or_before (GtkTreeViewDropPosition pos)
+{
+ return (pos == GTK_TREE_VIEW_DROP_BEFORE || pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE);
+}
+
+/* Computes the appropriate row and position for dropping */
+static gboolean
+compute_drop_position (GtkTreeView *tree_view,
+ int x,
+ int y,
+ GtkTreePath **path,
+ GtkTreeViewDropPosition *pos,
+ GtkPlacesSidebar *sidebar)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ PlaceType place_type;
+ SectionType section_type;
+ gboolean drop_possible;
+
+ if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
+ x, y,
+ path, pos)) {
+ return FALSE;
+ }
+
+ model = gtk_tree_view_get_model (tree_view);
+
+ gtk_tree_model_get_iter (model, &iter, *path);
+ gtk_tree_model_get (model, &iter,
+ PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type,
+ PLACES_SIDEBAR_COLUMN_SECTION_TYPE, §ion_type,
+ -1);
+
+ drop_possible = TRUE;
+
+ /* Never drop on headings, but special case the bookmarks heading,
+ * so we can drop bookmarks in between it and the first bookmark.
+ */
+ if (place_type == PLACES_HEADING
+ && section_type != SECTION_BOOKMARKS)
+ drop_possible = FALSE;
+
+ /* Dragging a bookmark? */
+ if (sidebar->drag_data_received
+ && sidebar->drag_data_info == GTK_TREE_MODEL_ROW) {
+ /* Don't allow reordering bookmarks into non-bookmark areas */
+ if (section_type != SECTION_BOOKMARKS)
+ drop_possible = FALSE;
+
+ /* Bookmarks can only be reordered. Disallow dropping directly into them; only allow
dropping between them. */
+ if (place_type == PLACES_HEADING) {
+ if (pos_is_into_or_before (*pos))
+ drop_possible = FALSE;
+ else
+ *pos = GTK_TREE_VIEW_DROP_AFTER;
+ } else {
+ if (pos_is_into_or_before (*pos))
+ *pos = GTK_TREE_VIEW_DROP_BEFORE;
+ else
+ *pos = GTK_TREE_VIEW_DROP_AFTER;
+ }
+ } else {
+ /* Dragging a file */
+
+ /* Outside the bookmarks section, URIs can only be dropped
+ * directly into places items. Inside the bookmarks section,
+ * they can be dropped between items (to create new bookmarks)
+ * or in items themselves (to request a move/copy file
+ * operation).
+ */
+ if (section_type != SECTION_BOOKMARKS)
+ *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
+ else {
+ if (place_type == PLACES_HEADING) {
+ if (pos_is_into_or_before (*pos))
+ drop_possible = FALSE;
+ else
+ *pos = GTK_TREE_VIEW_DROP_AFTER;
+ }
+ }
+ }
+
+ if (!drop_possible) {
+ gtk_tree_path_free (*path);
+ *path = NULL;
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+get_drag_data (GtkTreeView *tree_view,
+ GdkDragContext *context,
+ unsigned int time)
+{
+ GdkAtom target;
+
+ target = gtk_drag_dest_find_target (GTK_WIDGET (tree_view),
+ context,
+ NULL);
+
+ if (target == GDK_NONE) {
+ return FALSE;
+ }
+
+ gtk_drag_get_data (GTK_WIDGET (tree_view),
+ context, target, time);
+
+ return TRUE;
+}
+
+static void
+free_drag_data (GtkPlacesSidebar *sidebar)
+{
+ sidebar->drag_data_received = FALSE;
+
+ if (sidebar->drag_list) {
+ g_list_free_full (sidebar->drag_list, g_object_unref);
+ sidebar->drag_list = NULL;
+ }
+}
+
+static const char *
+pos_to_string (GtkTreeViewDropPosition pos)
+{
+ switch (pos) {
+ case GTK_TREE_VIEW_DROP_BEFORE: return "BEFORE";
+ case GTK_TREE_VIEW_DROP_AFTER: return "AFTER";
+ case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE: return "INTO_OR_BEFORE";
+ case GTK_TREE_VIEW_DROP_INTO_OR_AFTER: return "INTO_OR_AFTER";
+ default: return "INVALID";
+ }
+}
+
+static gboolean
+drag_motion_callback (GtkTreeView *tree_view,
+ GdkDragContext *context,
+ int x,
+ int y,
+ unsigned int time,
+ GtkPlacesSidebar *sidebar)
+{
+ GtkTreePath *path;
+ GtkTreeViewDropPosition pos;
+ int action;
+ GtkTreeIter iter;
+ char *uri;
+ gboolean res;
+
+ action = 0;
+
+ if (!sidebar->drag_data_received) {
+ if (!get_drag_data (tree_view, context, time)) {
+ goto out;
+ }
+ }
+
+ path = NULL;
+ res = compute_drop_position (tree_view, x, y, &path, &pos, sidebar);
+
+ if (!res) {
+ goto out;
+ }
+
+ printf ("compute_drop_position(): path %d, pos %s\n", gtk_tree_path_get_indices (path)[0],
pos_to_string (pos));
+
+ if (sidebar->drag_data_received &&
+ sidebar->drag_data_info == GTK_TREE_MODEL_ROW) {
+ /* Dragging bookmarks always moves them to another position in the bookmarks list */
+ action = GDK_ACTION_MOVE;
+ } else {
+ /* URIs are being dragged. See if the caller wants to handle a
+ * file move/copy operation itself, or if we should only try to
+ * create bookmarks out of the dragged URIs.
+ */
+ if (sidebar->drag_list != NULL) {
+ GFile *dest_file;
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (sidebar->store),
+ &iter, path);
+ gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store),
+ &iter,
+ PLACES_SIDEBAR_COLUMN_URI, &uri,
+ -1);
+
+ dest_file = g_file_new_for_uri (uri);
+
+ emit_drag_action_requested (sidebar, context, dest_file, sidebar->drag_list, &action);
+
+ printf ("dragging URIs, dest_file = %s, action_requested = %d\n", uri, action);
+
+ g_object_unref (dest_file);
+ g_free (uri);
+ }
+ }
+
+ out:
+ if (action != 0)
+ gtk_tree_view_set_drag_dest_row (tree_view, path, pos);
+ else
+ gtk_tree_view_set_drag_dest_row (tree_view, NULL, pos);
+
+ if (path != NULL) {
+ gtk_tree_path_free (path);
+ }
+
+ g_signal_stop_emission_by_name (tree_view, "drag-motion");
+
+ gdk_drag_status (context, action, time);
+
+ return TRUE;
+}
+
+static void
+drag_leave_callback (GtkTreeView *tree_view,
+ GdkDragContext *context,
+ unsigned int time,
+ GtkPlacesSidebar *sidebar)
+{
+ free_drag_data (sidebar);
+ gtk_tree_view_set_drag_dest_row (tree_view, NULL, 0);
+ g_signal_stop_emission_by_name (tree_view, "drag-leave");
+}
+
+/* Takes an array of URIs and turns it into a list of GFile */
+static GList *
+build_file_list_from_uris (const char **uris)
+{
+ GList *result;
+ int i;
+
+ result = NULL;
+ for (i = 0; uris[i]; i++) {
+ GFile *file;
+
+ file = g_file_new_for_uri (uris[i]);
+ result = g_list_prepend (result, file);
+ }
+
+ return g_list_reverse (result);
+}
+
+/* Reorders the selected bookmark to the specified position */
+static void
+reorder_bookmarks (GtkPlacesSidebar *sidebar,
+ int new_position)
+{
+ GtkTreeIter iter;
+ char *uri;
+ GFile *file;
+
+ /* Get the selected path */
+ if (!get_selected_iter (sidebar, &iter)) {
+ return;
+ }
+
+ gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
+ PLACES_SIDEBAR_COLUMN_URI, &uri,
+ -1);
+
+ file = g_file_new_for_uri (uri);
+ _gtk_bookmarks_manager_reorder_bookmark (sidebar->bookmarks_manager, file, new_position, NULL); /*
NULL-GError */
+
+ g_object_unref (file);
+ g_free (uri);
+}
+
+/* Creates bookmarks for the specified files at the given position in the bookmarks list */
+static void
+drop_files_as_bookmarks (GtkPlacesSidebar *sidebar,
+ GList *files,
+ int position)
+{
+ GList *l;
+
+ for (l = files; l; l = l->next) {
+ GFile *f = G_FILE (l->data);
+
+ _gtk_bookmarks_manager_insert_bookmark (sidebar->bookmarks_manager, f, position++, NULL); /*
NULL-GError */
+ }
+}
+
+static void
+drag_data_received_callback (GtkWidget *widget,
+ GdkDragContext *context,
+ int x,
+ int y,
+ GtkSelectionData *selection_data,
+ unsigned int info,
+ unsigned int time,
+ GtkPlacesSidebar *sidebar)
+{
+ GtkTreeView *tree_view;
+ GtkTreePath *tree_path;
+ GtkTreeViewDropPosition tree_pos;
+ GtkTreeIter iter;
+ int position;
+ GtkTreeModel *model;
+ PlaceType place_type;
+ SectionType section_type;
+ gboolean success;
+
+ tree_view = GTK_TREE_VIEW (widget);
+
+ if (!sidebar->drag_data_received) {
+ if (gtk_selection_data_get_target (selection_data) != GDK_NONE &&
+ info == TEXT_URI_LIST) {
+ char **uris;
+
+ uris = gtk_selection_data_get_uris (selection_data);
+ sidebar->drag_list = build_file_list_from_uris ((const char **) uris);
+ g_strfreev (uris);
+ } else {
+ sidebar->drag_list = NULL;
+ }
+ sidebar->drag_data_received = TRUE;
+ sidebar->drag_data_info = info;
+ }
+
+ g_signal_stop_emission_by_name (widget, "drag-data-received");
+
+ if (!sidebar->drop_occured) {
+ return;
+ }
+
+ /* Compute position */
+ success = compute_drop_position (tree_view, x, y, &tree_path, &tree_pos, sidebar);
+ if (!success) {
+ goto out;
+ }
+
+ success = FALSE;
+
+ if (sidebar->drag_data_info == GTK_TREE_MODEL_ROW) {
+ /* A bookmark got reordered */
+
+ model = gtk_tree_view_get_model (tree_view);
+
+ if (!gtk_tree_model_get_iter (model, &iter, tree_path)) {
+ goto out;
+ }
+
+ gtk_tree_model_get (model, &iter,
+ PLACES_SIDEBAR_COLUMN_SECTION_TYPE, §ion_type,
+ PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type,
+ PLACES_SIDEBAR_COLUMN_INDEX, &position,
+ -1);
+
+ if (section_type != SECTION_BOOKMARKS) {
+ goto out;
+ }
+
+ if (place_type == PLACES_HEADING)
+ position = 0;
+ else if (tree_pos == GTK_TREE_VIEW_DROP_AFTER)
+ position++;
+
+ reorder_bookmarks (sidebar, position);
+ success = TRUE;
+ } else {
+ /* Dropping URIs! */
+
+ GdkDragAction real_action;
+ char **uris;
+ GList *source_file_list;
+
+ /* file transfer requested */
+ real_action = gdk_drag_context_get_selected_action (context);
+
+ if (real_action == GDK_ACTION_ASK)
+ real_action = emit_drag_action_ask (sidebar, gdk_drag_context_get_actions (context));
+
+ if (real_action > 0) {
+ char *uri;
+ GFile *dest_file;
+ gboolean dropped;
+
+ model = gtk_tree_view_get_model (tree_view);
+
+ gtk_tree_model_get_iter (model, &iter, tree_path);
+ gtk_tree_model_get (model, &iter,
+ PLACES_SIDEBAR_COLUMN_SECTION_TYPE, §ion_type,
+ PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type,
+ PLACES_SIDEBAR_COLUMN_INDEX, &position,
+ -1);
+
+ dropped = FALSE;
+
+ uris = gtk_selection_data_get_uris (selection_data);
+ source_file_list = build_file_list_from_uris ((const char **) uris);
+
+ if (section_type == SECTION_BOOKMARKS) {
+ if (place_type == PLACES_HEADING) {
+ position = 0;
+ tree_pos = GTK_TREE_VIEW_DROP_BEFORE;
+ }
+
+ if (tree_pos == GTK_TREE_VIEW_DROP_AFTER)
+ position++;
+
+ if (tree_pos == GTK_TREE_VIEW_DROP_BEFORE
+ || tree_pos == GTK_TREE_VIEW_DROP_AFTER) {
+ drop_files_as_bookmarks (sidebar, source_file_list, position);
+ success = TRUE;
+ dropped = TRUE;
+ }
+ }
+
+ if (!dropped) {
+ gtk_tree_model_get_iter (model, &iter, tree_path);
+ gtk_tree_model_get (model, &iter,
+ PLACES_SIDEBAR_COLUMN_URI, &uri,
+ -1);
+
+ dest_file = g_file_new_for_uri (uri);
+
+ emit_drag_perform_drop (sidebar, dest_file, source_file_list, real_action);
+ success = TRUE;
+
+ g_object_unref (dest_file);
+ g_free (uri);
+ }
+
+ g_list_free_full (source_file_list, g_object_unref);
+ g_strfreev (uris);
+ }
+ }
+
+out:
+ sidebar->drop_occured = FALSE;
+ free_drag_data (sidebar);
+ gtk_drag_finish (context, success, FALSE, time);
+
+ gtk_tree_path_free (tree_path);
+}
+
+static gboolean
+drag_drop_callback (GtkTreeView *tree_view,
+ GdkDragContext *context,
+ int x,
+ int y,
+ unsigned int time,
+ GtkPlacesSidebar *sidebar)
+{
+ gboolean retval = FALSE;
+ sidebar->drop_occured = TRUE;
+ retval = get_drag_data (tree_view, context, time);
+ g_signal_stop_emission_by_name (tree_view, "drag-drop");
+ return retval;
+}
+
+/* Callback used when the file list's popup menu is detached */
+static void
+bookmarks_popup_menu_detach_cb (GtkWidget *attach_widget,
+ GtkMenu *menu)
+{
+ GtkPlacesSidebar *sidebar;
+
+ sidebar = GTK_PLACES_SIDEBAR (attach_widget);
+
+ sidebar->popup_menu = NULL;
+}
+static void
+check_unmount_and_eject (GMount *mount,
+ GVolume *volume,
+ GDrive *drive,
+ gboolean *show_unmount,
+ gboolean *show_eject)
+{
+ *show_unmount = FALSE;
+ *show_eject = FALSE;
+
+ if (drive != NULL) {
+ *show_eject = g_drive_can_eject (drive);
+ }
+
+ if (volume != NULL) {
+ *show_eject |= g_volume_can_eject (volume);
+ }
+ if (mount != NULL) {
+ *show_eject |= g_mount_can_eject (mount);
+ *show_unmount = g_mount_can_unmount (mount) && !*show_eject;
+ }
+}
+
+static void
+check_visibility (GMount *mount,
+ GVolume *volume,
+ GDrive *drive,
+ gboolean *show_mount,
+ gboolean *show_unmount,
+ gboolean *show_eject,
+ gboolean *show_rescan,
+ gboolean *show_start,
+ gboolean *show_stop)
+{
+ *show_mount = FALSE;
+ *show_rescan = FALSE;
+ *show_start = FALSE;
+ *show_stop = FALSE;
+
+ check_unmount_and_eject (mount, volume, drive, show_unmount, show_eject);
+
+ if (drive != NULL) {
+ if (g_drive_is_media_removable (drive) &&
+ !g_drive_is_media_check_automatic (drive) &&
+ g_drive_can_poll_for_media (drive))
+ *show_rescan = TRUE;
+
+ *show_start = g_drive_can_start (drive) || g_drive_can_start_degraded (drive);
+ *show_stop = g_drive_can_stop (drive);
+
+ if (*show_stop)
+ *show_unmount = FALSE;
+ }
+
+ if (volume != NULL) {
+ if (mount == NULL)
+ *show_mount = g_volume_can_mount (volume);
+ }
+}
+
+typedef struct {
+ PlaceType type;
+ GDrive *drive;
+ GVolume *volume;
+ GMount *mount;
+ char *uri;
+} SelectionInfo;
+
+static void
+get_selection_info (GtkPlacesSidebar *sidebar, SelectionInfo *info)
+{
+ GtkTreeIter iter;
+
+ info->type = PLACES_BUILT_IN;
+ info->drive = NULL;
+ info->volume = NULL;
+ info->mount = NULL;
+ info->uri = NULL;
+
+ if (get_selected_iter (sidebar, &iter)) {
+ gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
+ PLACES_SIDEBAR_COLUMN_ROW_TYPE, &info->type,
+ PLACES_SIDEBAR_COLUMN_DRIVE, &info->drive,
+ PLACES_SIDEBAR_COLUMN_VOLUME, &info->volume,
+ PLACES_SIDEBAR_COLUMN_MOUNT, &info->mount,
+ PLACES_SIDEBAR_COLUMN_URI, &info->uri,
+ -1);
+ }
+}
+
+static void
+free_selection_info (SelectionInfo *info)
+{
+ g_clear_object (&info->drive);
+ g_clear_object (&info->volume);
+ g_clear_object (&info->mount);
+
+ g_clear_pointer (&info->uri, g_free);
+}
+
+typedef struct {
+ GtkWidget *add_shortcut_item;
+ GtkWidget *remove_item;
+ GtkWidget *rename_item;
+ GtkWidget *separator_item;
+ GtkWidget *mount_item;
+ GtkWidget *unmount_item;
+ GtkWidget *eject_item;
+ GtkWidget *rescan_item;
+ GtkWidget *start_item;
+ GtkWidget *stop_item;
+} PopupMenuData;
+
+static void
+check_popup_sensitivity (GtkPlacesSidebar *sidebar, PopupMenuData *data, SelectionInfo *info)
+{
+ gboolean show_mount;
+ gboolean show_unmount;
+ gboolean show_eject;
+ gboolean show_rescan;
+ gboolean show_start;
+ gboolean show_stop;
+
+ gtk_widget_set_visible (data->add_shortcut_item, (info->type == PLACES_MOUNTED_VOLUME));
+
+ gtk_widget_set_sensitive (data->remove_item, (info->type == PLACES_BOOKMARK));
+ gtk_widget_set_sensitive (data->rename_item, (info->type == PLACES_BOOKMARK || info->type ==
PLACES_XDG_DIR));
+
+ check_visibility (info->mount, info->volume, info->drive,
+ &show_mount, &show_unmount, &show_eject, &show_rescan, &show_start, &show_stop);
+
+ gtk_widget_set_visible (data->separator_item, show_mount || show_unmount || show_eject);
+ gtk_widget_set_visible (data->mount_item, show_mount);
+ gtk_widget_set_visible (data->unmount_item, show_unmount);
+ gtk_widget_set_visible (data->eject_item, show_eject);
+ gtk_widget_set_visible (data->rescan_item, show_rescan);
+ gtk_widget_set_visible (data->start_item, show_start);
+ gtk_widget_set_visible (data->stop_item, show_stop);
+
+ /* Adjust start/stop items to reflect the type of the drive */
+ gtk_menu_item_set_label (GTK_MENU_ITEM (data->start_item), _("_Start"));
+ gtk_menu_item_set_label (GTK_MENU_ITEM (data->stop_item), _("_Stop"));
+ if ((show_start || show_stop) && info->drive != NULL) {
+ switch (g_drive_get_start_stop_type (info->drive)) {
+ case G_DRIVE_START_STOP_TYPE_SHUTDOWN:
+ /* start() for type G_DRIVE_START_STOP_TYPE_SHUTDOWN is normally not used */
+ gtk_menu_item_set_label (GTK_MENU_ITEM (data->start_item), _("_Power On"));
+ gtk_menu_item_set_label (GTK_MENU_ITEM (data->stop_item), _("_Safely Remove Drive"));
+ break;
+ case G_DRIVE_START_STOP_TYPE_NETWORK:
+ gtk_menu_item_set_label (GTK_MENU_ITEM (data->start_item), _("_Connect Drive"));
+ gtk_menu_item_set_label (GTK_MENU_ITEM (data->stop_item), _("_Disconnect Drive"));
+ break;
+ case G_DRIVE_START_STOP_TYPE_MULTIDISK:
+ gtk_menu_item_set_label (GTK_MENU_ITEM (data->start_item), _("_Start Multi-disk
Device"));
+ gtk_menu_item_set_label (GTK_MENU_ITEM (data->stop_item), _("_Stop Multi-disk
Device"));
+ break;
+ case G_DRIVE_START_STOP_TYPE_PASSWORD:
+ /* stop() for type G_DRIVE_START_STOP_TYPE_PASSWORD is normally not used */
+ gtk_menu_item_set_label (GTK_MENU_ITEM (data->start_item), _("_Unlock Drive"));
+ gtk_menu_item_set_label (GTK_MENU_ITEM (data->stop_item), _("_Lock Drive"));
+ break;
+
+ default:
+ case G_DRIVE_START_STOP_TYPE_UNKNOWN:
+ /* uses defaults set above */
+ break;
+ }
+ }
+}
+
+static void
+drive_start_from_bookmark_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GtkPlacesSidebar *sidebar;
+ GError *error;
+ char *primary;
+ char *name;
+
+ sidebar = GTK_PLACES_SIDEBAR (user_data);
+
+ error = NULL;
+ if (!g_drive_poll_for_media_finish (G_DRIVE (source_object), res, &error)) {
+ if (error->code != G_IO_ERROR_FAILED_HANDLED) {
+ name = g_drive_get_name (G_DRIVE (source_object));
+ primary = g_strdup_printf (_("Unable to start %s"), name);
+ g_free (name);
+ emit_show_error_message (sidebar, primary, error->message);
+ g_free (primary);
+ }
+ g_error_free (error);
+ }
+}
+
+/* Callback from g_volume_mount() */
+static void
+volume_mount_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+ GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (user_data);
+ GVolume *volume;
+ GError *error;
+ char *primary;
+ char *name;
+ GMount *mount;
+
+ volume = G_VOLUME (source_object);
+
+ error = NULL;
+ if (!g_volume_mount_finish (volume, result, &error)) {
+ if (error->code != G_IO_ERROR_FAILED_HANDLED &&
+ error->code != G_IO_ERROR_ALREADY_MOUNTED) {
+ name = g_volume_get_name (G_VOLUME (source_object));
+ primary = g_strdup_printf (_("Unable to access â%sâ"), name);
+ g_free (name);
+ emit_show_error_message (sidebar, primary, error->message);
+ g_free (primary);
+ }
+ g_error_free (error);
+ }
+
+ sidebar->mounting = FALSE;
+
+ mount = g_volume_get_mount (volume);
+ if (mount != NULL) {
+ GFile *location;
+
+ location = g_mount_get_default_location (mount);
+ emit_open_location (sidebar, location, sidebar->go_to_after_mount_open_flags);
+
+ g_object_unref (G_OBJECT (location));
+ g_object_unref (G_OBJECT (mount));
+ }
+
+ g_object_unref (sidebar);
+}
+
+/* This was nautilus_file_operations_mount_volume_full() */
+static void
+mount_volume (GtkPlacesSidebar *sidebar, GVolume *volume)
+{
+ GMountOperation *mount_op;
+
+ mount_op = gtk_mount_operation_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (sidebar))));
+ g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION);
+
+ g_object_ref (sidebar);
+ g_volume_mount (volume, 0, mount_op, NULL, volume_mount_cb, sidebar);
+}
+
+static void
+open_selected_bookmark (GtkPlacesSidebar *sidebar,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ GtkPlacesOpenFlags open_flags)
+{
+ GFile *location;
+ char *uri;
+
+ if (!iter) {
+ return;
+ }
+
+ gtk_tree_model_get (model, iter, PLACES_SIDEBAR_COLUMN_URI, &uri, -1);
+
+ if (uri != NULL) {
+ location = g_file_new_for_uri (uri);
+ emit_open_location (sidebar, location, open_flags);
+
+ g_object_unref (location);
+ g_free (uri);
+
+ } else {
+ GDrive *drive;
+ GVolume *volume;
+
+ gtk_tree_model_get (model, iter,
+ PLACES_SIDEBAR_COLUMN_DRIVE, &drive,
+ PLACES_SIDEBAR_COLUMN_VOLUME, &volume,
+ -1);
+
+ if (volume != NULL && !sidebar->mounting) {
+ sidebar->mounting = TRUE;
+
+ sidebar->go_to_after_mount_open_flags = open_flags;
+
+ mount_volume (sidebar, volume);
+ } else if (volume == NULL && drive != NULL &&
+ (g_drive_can_start (drive) || g_drive_can_start_degraded (drive))) {
+ GMountOperation *mount_op;
+
+ mount_op = gtk_mount_operation_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET
(sidebar))));
+ g_drive_start (drive, G_DRIVE_START_NONE, mount_op, NULL,
drive_start_from_bookmark_cb, sidebar);
+ g_object_unref (mount_op);
+ }
+
+ g_clear_object (&drive);
+ g_clear_object (&volume);
+ }
+}
+
+static void
+open_shortcut_from_menu (GtkPlacesSidebar *sidebar,
+ GtkPlacesOpenFlags open_flags)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkTreePath *path = NULL;
+
+ model = gtk_tree_view_get_model (sidebar->tree_view);
+ gtk_tree_view_get_cursor (sidebar->tree_view, &path, NULL);
+
+ if (path != NULL && gtk_tree_model_get_iter (model, &iter, path)) {
+ open_selected_bookmark (sidebar, model, &iter, open_flags);
+ }
+
+ gtk_tree_path_free (path);
+}
+
+/* Callback used for the "Open" menu item in the context menu */
+static void
+open_shortcut_cb (GtkMenuItem *item,
+ GtkPlacesSidebar *sidebar)
+{
+ open_shortcut_from_menu (sidebar, GTK_PLACES_OPEN_NORMAL);
+}
+
+/* Callback used for the "Open in new tab" menu item in the context menu */
+static void
+open_shortcut_in_new_tab_cb (GtkMenuItem *item,
+ GtkPlacesSidebar *sidebar)
+{
+ open_shortcut_from_menu (sidebar, GTK_PLACES_OPEN_NEW_TAB);
+}
+
+/* Callback used for the "Open in new window" menu item in the context menu */
+static void
+open_shortcut_in_new_window_cb (GtkMenuItem *item,
+ GtkPlacesSidebar *sidebar)
+{
+ open_shortcut_from_menu (sidebar, GTK_PLACES_OPEN_NEW_WINDOW);
+}
+
+/* Add bookmark for the selected item - just used from mount points */
+static void
+add_shortcut_cb (GtkMenuItem *item,
+ GtkPlacesSidebar *sidebar)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ char *uri;
+ char *name;
+ GFile *location;
+
+ model = gtk_tree_view_get_model (sidebar->tree_view);
+
+ if (get_selected_iter (sidebar, &iter)) {
+ gtk_tree_model_get (model, &iter,
+ PLACES_SIDEBAR_COLUMN_URI, &uri,
+ PLACES_SIDEBAR_COLUMN_NAME, &name,
+ -1);
+
+ if (uri == NULL) {
+ return;
+ }
+
+ location = g_file_new_for_uri (uri);
+ if (_gtk_bookmarks_manager_insert_bookmark (sidebar->bookmarks_manager, location, -1, NULL))
+ _gtk_bookmarks_manager_set_bookmark_label (sidebar->bookmarks_manager, location,
name, NULL);
+
+ g_object_unref (location);
+ g_free (uri);
+ g_free (name);
+ }
+}
+
+/* Rename the selected bookmark */
+static void
+rename_selected_bookmark (GtkPlacesSidebar *sidebar)
+{
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *cell;
+ GList *renderers;
+ PlaceType type;
+
+ if (get_selected_iter (sidebar, &iter)) {
+ gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
+ PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type,
+ -1);
+
+ if (type != PLACES_BOOKMARK && type != PLACES_XDG_DIR) {
+ return;
+ }
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (sidebar->store), &iter);
+ column = gtk_tree_view_get_column (GTK_TREE_VIEW (sidebar->tree_view), 0);
+ renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column));
+ cell = g_list_nth_data (renderers, 6);
+ g_list_free (renderers);
+ g_object_set (cell, "editable", TRUE, NULL);
+ gtk_tree_view_set_cursor_on_cell (GTK_TREE_VIEW (sidebar->tree_view),
+ path, column, cell, TRUE);
+ gtk_tree_path_free (path);
+ }
+}
+
+static void
+rename_shortcut_cb (GtkMenuItem *item,
+ GtkPlacesSidebar *sidebar)
+{
+ rename_selected_bookmark (sidebar);
+}
+
+/* Removes the selected bookmarks */
+static void
+remove_selected_bookmarks (GtkPlacesSidebar *sidebar)
+{
+ GtkTreeIter iter;
+ PlaceType type;
+ char *uri;
+ GFile *file;
+
+ if (!get_selected_iter (sidebar, &iter)) {
+ return;
+ }
+
+ gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
+ PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type,
+ -1);
+
+ if (type != PLACES_BOOKMARK) {
+ return;
+ }
+
+ gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
+ PLACES_SIDEBAR_COLUMN_URI, &uri,
+ -1);
+
+ file = g_file_new_for_uri (uri);
+ _gtk_bookmarks_manager_remove_bookmark (sidebar->bookmarks_manager, file, NULL); /* NULL-GError */
+
+ g_object_unref (file);
+ g_free (uri);
+}
+
+static void
+remove_shortcut_cb (GtkMenuItem *item,
+ GtkPlacesSidebar *sidebar)
+{
+ remove_selected_bookmarks (sidebar);
+}
+
+static void
+mount_shortcut_cb (GtkMenuItem *item,
+ GtkPlacesSidebar *sidebar)
+{
+ GtkTreeIter iter;
+ GVolume *volume;
+
+ if (!get_selected_iter (sidebar, &iter)) {
+ return;
+ }
+
+ gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
+ PLACES_SIDEBAR_COLUMN_VOLUME, &volume,
+ -1);
+
+ if (volume != NULL) {
+ mount_volume (sidebar, volume);
+ g_object_unref (volume);
+ }
+}
+
+/* Callback used from g_mount_unmount_with_operation() */
+static void
+unmount_mount_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (user_data);
+ GMount *mount;
+ GError *error;
+
+ mount = G_MOUNT (source_object);
+
+ error = NULL;
+ if (!g_mount_unmount_with_operation_finish (mount, result, &error)) {
+ if (error->code != G_IO_ERROR_FAILED_HANDLED) {
+ char *name;
+ char *primary;
+
+ name = g_mount_get_name (mount);
+ primary = g_strdup_printf (_("Unable to unmount %s"), name);
+ g_free (name);
+ emit_show_error_message (sidebar, primary, error->message);
+ g_free (primary);
+ }
+
+ g_error_free (error);
+ }
+
+ /* FIXME: we need to switch to a path that is available now - $HOME? */
+
+ g_object_unref (sidebar);
+}
+
+static void
+show_unmount_progress_cb (GMountOperation *op,
+ const gchar *message,
+ gint64 time_left,
+ gint64 bytes_left,
+ gpointer user_data)
+{
+ /* FIXME: These are just libnotify notifications, but GTK+ doesn't do notifications right now.
+ * Should we just call D-Bus directly?
+ */
+#if DO_NOT_COMPILE
+ NautilusApplication *app = NAUTILUS_APPLICATION (g_application_get_default ());
+
+ if (bytes_left == 0) {
+ nautilus_application_notify_unmount_done (app, message);
+ } else {
+ nautilus_application_notify_unmount_show (app, message);
+ }
+#endif
+}
+
+static void
+show_unmount_progress_aborted_cb (GMountOperation *op,
+ gpointer user_data)
+{
+ /* FIXME: These are just libnotify notifications, but GTK+ doesn't do notifications right now.
+ * Should we just call D-Bus directly?
+ */
+#if DO_NOT_COMPILE
+ NautilusApplication *app = NAUTILUS_APPLICATION (g_application_get_default ());
+ nautilus_application_notify_unmount_done (app, NULL);
+#endif
+}
+
+static GMountOperation *
+get_unmount_operation (GtkPlacesSidebar *sidebar)
+{
+ GMountOperation *mount_op;
+
+ mount_op = gtk_mount_operation_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (sidebar))));
+ g_signal_connect (mount_op, "show-unmount-progress",
+ G_CALLBACK (show_unmount_progress_cb), sidebar);
+ g_signal_connect (mount_op, "aborted",
+ G_CALLBACK (show_unmount_progress_aborted_cb), sidebar);
+
+ return mount_op;
+}
+
+static void
+do_unmount (GMount *mount,
+ GtkPlacesSidebar *sidebar)
+{
+ if (mount != NULL) {
+ GMountOperation *mount_op;
+
+ mount_op = get_unmount_operation (sidebar);
+ g_mount_unmount_with_operation (mount,
+ 0,
+ mount_op,
+ NULL,
+ unmount_mount_cb,
+ g_object_ref (sidebar));
+ g_object_unref (mount_op);
+ }
+}
+
+static void
+do_unmount_selection (GtkPlacesSidebar *sidebar)
+{
+ GtkTreeIter iter;
+ GMount *mount;
+
+ if (!get_selected_iter (sidebar, &iter)) {
+ return;
+ }
+
+ gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
+ PLACES_SIDEBAR_COLUMN_MOUNT, &mount,
+ -1);
+
+ if (mount != NULL) {
+ do_unmount (mount, sidebar);
+ g_object_unref (mount);
+ }
+}
+
+static void
+unmount_shortcut_cb (GtkMenuItem *item,
+ GtkPlacesSidebar *sidebar)
+{
+ do_unmount_selection (sidebar);
+}
+
+static void
+drive_eject_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GtkPlacesSidebar *sidebar;
+ GError *error;
+ char *primary;
+ char *name;
+
+ sidebar = user_data;
+
+ error = NULL;
+ if (!g_drive_eject_with_operation_finish (G_DRIVE (source_object), res, &error)) {
+ if (error->code != G_IO_ERROR_FAILED_HANDLED) {
+ name = g_drive_get_name (G_DRIVE (source_object));
+ primary = g_strdup_printf (_("Unable to eject %s"), name);
+ g_free (name);
+ emit_show_error_message (sidebar, primary, error->message);
+ g_free (primary);
+ }
+ g_error_free (error);
+ }
+
+ g_object_unref (sidebar);
+}
+
+static void
+volume_eject_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GtkPlacesSidebar *sidebar;
+ GError *error;
+ char *primary;
+ char *name;
+
+ sidebar = user_data;
+
+ error = NULL;
+ if (!g_volume_eject_with_operation_finish (G_VOLUME (source_object), res, &error)) {
+ if (error->code != G_IO_ERROR_FAILED_HANDLED) {
+ name = g_volume_get_name (G_VOLUME (source_object));
+ primary = g_strdup_printf (_("Unable to eject %s"), name);
+ g_free (name);
+ emit_show_error_message (sidebar, primary, error->message);
+ g_free (primary);
+ }
+ g_error_free (error);
+ }
+
+ g_object_unref (sidebar);
+}
+
+static void
+mount_eject_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GtkPlacesSidebar *sidebar;
+ GError *error;
+ char *primary;
+ char *name;
+
+ sidebar = user_data;
+
+ error = NULL;
+ if (!g_mount_eject_with_operation_finish (G_MOUNT (source_object), res, &error)) {
+ if (error->code != G_IO_ERROR_FAILED_HANDLED) {
+ name = g_mount_get_name (G_MOUNT (source_object));
+ primary = g_strdup_printf (_("Unable to eject %s"), name);
+ g_free (name);
+ emit_show_error_message (sidebar, primary, error->message);
+ g_free (primary);
+ }
+ g_error_free (error);
+ }
+
+ g_object_unref (sidebar);
+}
+
+static void
+do_eject (GMount *mount,
+ GVolume *volume,
+ GDrive *drive,
+ GtkPlacesSidebar *sidebar)
+{
+ GMountOperation *mount_op;
+
+ mount_op = get_unmount_operation (sidebar);
+ if (mount != NULL) {
+ g_mount_eject_with_operation (mount, 0, mount_op, NULL, mount_eject_cb,
+ g_object_ref (sidebar));
+ } else if (volume != NULL) {
+ g_volume_eject_with_operation (volume, 0, mount_op, NULL, volume_eject_cb,
+ g_object_ref (sidebar));
+ } else if (drive != NULL) {
+ g_drive_eject_with_operation (drive, 0, mount_op, NULL, drive_eject_cb,
+ g_object_ref (sidebar));
+ }
+ g_object_unref (mount_op);
+}
+
+static void
+eject_shortcut_cb (GtkMenuItem *item,
+ GtkPlacesSidebar *sidebar)
+{
+ GtkTreeIter iter;
+ GMount *mount;
+ GVolume *volume;
+ GDrive *drive;
+
+ if (!get_selected_iter (sidebar, &iter)) {
+ return;
+ }
+
+ gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
+ PLACES_SIDEBAR_COLUMN_MOUNT, &mount,
+ PLACES_SIDEBAR_COLUMN_VOLUME, &volume,
+ PLACES_SIDEBAR_COLUMN_DRIVE, &drive,
+ -1);
+
+ do_eject (mount, volume, drive, sidebar);
+}
+
+static gboolean
+eject_or_unmount_bookmark (GtkPlacesSidebar *sidebar,
+ GtkTreePath *path)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gboolean can_unmount, can_eject;
+ GMount *mount;
+ GVolume *volume;
+ GDrive *drive;
+ gboolean ret;
+
+ model = GTK_TREE_MODEL (sidebar->store);
+
+ if (!path) {
+ return FALSE;
+ }
+ if (!gtk_tree_model_get_iter (model, &iter, path)) {
+ return FALSE;
+ }
+
+ gtk_tree_model_get (model, &iter,
+ PLACES_SIDEBAR_COLUMN_MOUNT, &mount,
+ PLACES_SIDEBAR_COLUMN_VOLUME, &volume,
+ PLACES_SIDEBAR_COLUMN_DRIVE, &drive,
+ -1);
+
+ ret = FALSE;
+
+ check_unmount_and_eject (mount, volume, drive, &can_unmount, &can_eject);
+ /* if we can eject, it has priority over unmount */
+ if (can_eject) {
+ do_eject (mount, volume, drive, sidebar);
+ ret = TRUE;
+ } else if (can_unmount) {
+ do_unmount (mount, sidebar);
+ ret = TRUE;
+ }
+
+ g_clear_object (&mount);
+ g_clear_object (&volume);
+ g_clear_object (&drive);
+
+ return ret;
+}
+
+static gboolean
+eject_or_unmount_selection (GtkPlacesSidebar *sidebar)
+{
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ gboolean ret;
+
+ if (!get_selected_iter (sidebar, &iter)) {
+ return FALSE;
+ }
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (sidebar->store), &iter);
+ if (path == NULL) {
+ return FALSE;
+ }
+
+ ret = eject_or_unmount_bookmark (sidebar, path);
+
+ gtk_tree_path_free (path);
+
+ return ret;
+}
+
+static void
+drive_poll_for_media_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GtkPlacesSidebar *sidebar;
+ GError *error;
+ char *primary;
+ char *name;
+
+ sidebar = GTK_PLACES_SIDEBAR (user_data);
+
+ error = NULL;
+ if (!g_drive_poll_for_media_finish (G_DRIVE (source_object), res, &error)) {
+ if (error->code != G_IO_ERROR_FAILED_HANDLED) {
+ name = g_drive_get_name (G_DRIVE (source_object));
+ primary = g_strdup_printf (_("Unable to poll %s for media changes"), name);
+ g_free (name);
+ emit_show_error_message (sidebar, primary, error->message);
+ g_free (primary);
+ }
+ g_error_free (error);
+ }
+
+ /* FIXME: drive_stop_cb() gets a reffed sidebar, and unrefs it. Do we need to do the same here? */
+}
+
+static void
+rescan_shortcut_cb (GtkMenuItem *item,
+ GtkPlacesSidebar *sidebar)
+{
+ GtkTreeIter iter;
+ GDrive *drive;
+
+ if (!get_selected_iter (sidebar, &iter)) {
+ return;
+ }
+
+ gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
+ PLACES_SIDEBAR_COLUMN_DRIVE, &drive,
+ -1);
+
+ if (drive != NULL) {
+ g_drive_poll_for_media (drive, NULL, drive_poll_for_media_cb, sidebar);
+ g_object_unref (drive);
+ }
+}
+
+static void
+drive_start_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GtkPlacesSidebar *sidebar;
+ GError *error;
+ char *primary;
+ char *name;
+
+ sidebar = GTK_PLACES_SIDEBAR (user_data);
+
+ error = NULL;
+ if (!g_drive_poll_for_media_finish (G_DRIVE (source_object), res, &error)) {
+ if (error->code != G_IO_ERROR_FAILED_HANDLED) {
+ name = g_drive_get_name (G_DRIVE (source_object));
+ primary = g_strdup_printf (_("Unable to start %s"), name);
+ g_free (name);
+ emit_show_error_message (sidebar, primary, error->message);
+ g_free (primary);
+ }
+ g_error_free (error);
+ }
+
+ /* FIXME: drive_stop_cb() gets a reffed sidebar, and unrefs it. Do we need to do the same here? */
+}
+
+static void
+start_shortcut_cb (GtkMenuItem *item,
+ GtkPlacesSidebar *sidebar)
+{
+ GtkTreeIter iter;
+ GDrive *drive;
+
+ if (!get_selected_iter (sidebar, &iter)) {
+ return;
+ }
+
+ gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
+ PLACES_SIDEBAR_COLUMN_DRIVE, &drive,
+ -1);
+
+ if (drive != NULL) {
+ GMountOperation *mount_op;
+
+ mount_op = gtk_mount_operation_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET
(sidebar))));
+
+ g_drive_start (drive, G_DRIVE_START_NONE, mount_op, NULL, drive_start_cb, sidebar);
+
+ g_object_unref (mount_op);
+ g_object_unref (drive);
+ }
+}
+
+static void
+drive_stop_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GtkPlacesSidebar *sidebar;
+ GError *error;
+ char *primary;
+ char *name;
+
+ sidebar = user_data;
+
+ error = NULL;
+ if (!g_drive_poll_for_media_finish (G_DRIVE (source_object), res, &error)) {
+ if (error->code != G_IO_ERROR_FAILED_HANDLED) {
+ name = g_drive_get_name (G_DRIVE (source_object));
+ primary = g_strdup_printf (_("Unable to stop %s"), name);
+ g_free (name);
+ emit_show_error_message (sidebar, primary, error->message);
+ g_free (primary);
+ }
+ g_error_free (error);
+ }
+
+ g_object_unref (sidebar);
+}
+
+static void
+stop_shortcut_cb (GtkMenuItem *item,
+ GtkPlacesSidebar *sidebar)
+{
+ GtkTreeIter iter;
+ GDrive *drive;
+
+ if (!get_selected_iter (sidebar, &iter)) {
+ return;
+ }
+
+ gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
+ PLACES_SIDEBAR_COLUMN_DRIVE, &drive,
+ -1);
+
+ if (drive != NULL) {
+ GMountOperation *mount_op;
+
+ mount_op = get_unmount_operation (sidebar);
+ g_drive_stop (drive, G_MOUNT_UNMOUNT_NONE, mount_op, NULL, drive_stop_cb,
+ g_object_ref (sidebar));
+
+ g_object_unref (mount_op);
+ g_object_unref (drive);
+ }
+}
+
+static gboolean
+find_prev_or_next_row (GtkPlacesSidebar *sidebar,
+ GtkTreeIter *iter,
+ gboolean go_up)
+{
+ GtkTreeModel *model = GTK_TREE_MODEL (sidebar->store);
+ gboolean res;
+ int place_type;
+
+ if (go_up) {
+ res = gtk_tree_model_iter_previous (model, iter);
+ } else {
+ res = gtk_tree_model_iter_next (model, iter);
+ }
+
+ if (res) {
+ gtk_tree_model_get (model, iter,
+ PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type,
+ -1);
+ if (place_type == PLACES_HEADING) {
+ if (go_up) {
+ res = gtk_tree_model_iter_previous (model, iter);
+ } else {
+ res = gtk_tree_model_iter_next (model, iter);
+ }
+ }
+ }
+
+ return res;
+}
+
+static gboolean
+find_prev_row (GtkPlacesSidebar *sidebar, GtkTreeIter *iter)
+{
+ return find_prev_or_next_row (sidebar, iter, TRUE);
+}
+
+static gboolean
+find_next_row (GtkPlacesSidebar *sidebar, GtkTreeIter *iter)
+{
+ return find_prev_or_next_row (sidebar, iter, FALSE);
+}
+
+static gboolean
+gtk_places_sidebar_focus (GtkWidget *widget,
+ GtkDirectionType direction)
+{
+ GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (widget);
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ gboolean res;
+
+ res = get_selected_iter (sidebar, &iter);
+
+ if (!res) {
+ gtk_tree_model_get_iter_first (GTK_TREE_MODEL (sidebar->store), &iter);
+ res = find_next_row (sidebar, &iter);
+ if (res) {
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (sidebar->store), &iter);
+ gtk_tree_view_set_cursor (sidebar->tree_view, path, NULL, FALSE);
+ gtk_tree_path_free (path);
+ }
+ }
+
+ return GTK_WIDGET_CLASS (gtk_places_sidebar_parent_class)->focus (widget, direction);
+}
+
+/* Handler for GtkWidget::key-press-event on the shortcuts list */
+static gboolean
+bookmarks_key_press_event_cb (GtkWidget *widget,
+ GdkEventKey *event,
+ GtkPlacesSidebar *sidebar)
+{
+ guint modifiers;
+ GtkTreeIter selected_iter;
+ GtkTreePath *path;
+
+ if (!get_selected_iter (sidebar, &selected_iter)) {
+ return FALSE;
+ }
+
+ modifiers = gtk_accelerator_get_default_mod_mask ();
+
+ if ((event->keyval == GDK_KEY_Return ||
+ event->keyval == GDK_KEY_KP_Enter ||
+ event->keyval == GDK_KEY_ISO_Enter ||
+ event->keyval == GDK_KEY_space)) {
+
+ GtkPlacesOpenFlags open_flags = GTK_PLACES_OPEN_NORMAL;
+
+ if ((event->state & modifiers) == GDK_SHIFT_MASK) {
+ open_flags = GTK_PLACES_OPEN_NEW_TAB;
+ } else if ((event->state & modifiers) == GDK_CONTROL_MASK) {
+ open_flags = GTK_PLACES_OPEN_NEW_WINDOW;
+ }
+
+ open_selected_bookmark (sidebar, GTK_TREE_MODEL (sidebar->store),
+ &selected_iter, open_flags);
+
+ return TRUE;
+ }
+
+ if (event->keyval == GDK_KEY_Down &&
+ (event->state & modifiers) == GDK_MOD1_MASK) {
+ return eject_or_unmount_selection (sidebar);
+ }
+
+ if (event->keyval == GDK_KEY_Up) {
+ if (find_prev_row (sidebar, &selected_iter)) {
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (sidebar->store), &selected_iter);
+ gtk_tree_view_set_cursor (sidebar->tree_view, path, NULL, FALSE);
+ gtk_tree_path_free (path);
+ }
+ return TRUE;
+ }
+
+ if (event->keyval == GDK_KEY_Down) {
+ if (find_next_row (sidebar, &selected_iter)) {
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (sidebar->store), &selected_iter);
+ gtk_tree_view_set_cursor (sidebar->tree_view, path, NULL, FALSE);
+ gtk_tree_path_free (path);
+ }
+ return TRUE;
+ }
+
+ if ((event->keyval == GDK_KEY_Delete
+ || event->keyval == GDK_KEY_KP_Delete)
+ && (event->state & modifiers) == 0) {
+ remove_selected_bookmarks (sidebar);
+ return TRUE;
+ }
+
+ if ((event->keyval == GDK_KEY_F2)
+ && (event->state & modifiers) == 0) {
+ rename_selected_bookmark (sidebar);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static GtkMenuItem *
+append_menu_separator (GtkMenu *menu)
+{
+ GtkWidget *menu_item;
+
+ menu_item = gtk_separator_menu_item_new ();
+ gtk_widget_show (menu_item);
+ gtk_menu_shell_insert (GTK_MENU_SHELL (menu), menu_item, -1);
+
+ return GTK_MENU_ITEM (menu_item);
+}
+
+/* Constructs the popup menu for the file list if needed */
+static void
+bookmarks_build_popup_menu (GtkPlacesSidebar *sidebar)
+{
+ PopupMenuData menu_data;
+ GtkWidget *item;
+ SelectionInfo sel_info;
+ GFile *file;
+
+ sidebar->popup_menu = gtk_menu_new ();
+ gtk_menu_attach_to_widget (GTK_MENU (sidebar->popup_menu),
+ GTK_WIDGET (sidebar),
+ bookmarks_popup_menu_detach_cb);
+
+ item = gtk_image_menu_item_new_with_mnemonic (_("_Open"));
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
+ gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU));
+ g_signal_connect (item, "activate",
+ G_CALLBACK (open_shortcut_cb), sidebar);
+ gtk_widget_show (item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
+
+ if (sidebar->open_flags & GTK_PLACES_OPEN_NEW_TAB) {
+ item = gtk_menu_item_new_with_mnemonic (_("Open in New _Tab"));
+ g_signal_connect (item, "activate",
+ G_CALLBACK (open_shortcut_in_new_tab_cb), sidebar);
+ gtk_widget_show (item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
+ }
+
+ if (sidebar->open_flags & GTK_PLACES_OPEN_NEW_WINDOW) {
+ item = gtk_menu_item_new_with_mnemonic (_("Open in New _Window"));
+ g_signal_connect (item, "activate",
+ G_CALLBACK (open_shortcut_in_new_window_cb), sidebar);
+ gtk_widget_show (item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
+ }
+
+ append_menu_separator (GTK_MENU (sidebar->popup_menu));
+
+ item = gtk_menu_item_new_with_mnemonic (_("_Add Bookmark"));
+ menu_data.add_shortcut_item = item;
+ g_signal_connect (item, "activate",
+ G_CALLBACK (add_shortcut_cb), sidebar);
+ gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
+
+ item = gtk_image_menu_item_new_with_label (_("Remove"));
+ menu_data.remove_item = item;
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
+ gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU));
+ g_signal_connect (item, "activate",
+ G_CALLBACK (remove_shortcut_cb), sidebar);
+ gtk_widget_show (item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
+
+ item = gtk_menu_item_new_with_label (_("Renameâ"));
+ menu_data.rename_item = item;
+ g_signal_connect (item, "activate",
+ G_CALLBACK (rename_shortcut_cb), sidebar);
+ gtk_widget_show (item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
+
+ /* Mount/Unmount/Eject menu items */
+
+ menu_data.separator_item = GTK_WIDGET (append_menu_separator (GTK_MENU (sidebar->popup_menu)));
+
+ item = gtk_menu_item_new_with_mnemonic (_("_Mount"));
+ menu_data.mount_item = item;
+ g_signal_connect (item, "activate",
+ G_CALLBACK (mount_shortcut_cb), sidebar);
+ gtk_widget_show (item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
+
+ item = gtk_menu_item_new_with_mnemonic (_("_Unmount"));
+ menu_data.unmount_item = item;
+ g_signal_connect (item, "activate",
+ G_CALLBACK (unmount_shortcut_cb), sidebar);
+ gtk_widget_show (item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
+
+ item = gtk_menu_item_new_with_mnemonic (_("_Eject"));
+ menu_data.eject_item = item;
+ g_signal_connect (item, "activate",
+ G_CALLBACK (eject_shortcut_cb), sidebar);
+ gtk_widget_show (item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
+
+ item = gtk_menu_item_new_with_mnemonic (_("_Detect Media"));
+ menu_data.rescan_item = item;
+ g_signal_connect (item, "activate",
+ G_CALLBACK (rescan_shortcut_cb), sidebar);
+ gtk_widget_show (item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
+
+ item = gtk_menu_item_new_with_mnemonic (_("_Start"));
+ menu_data.start_item = item;
+ g_signal_connect (item, "activate",
+ G_CALLBACK (start_shortcut_cb), sidebar);
+ gtk_widget_show (item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
+
+ item = gtk_menu_item_new_with_mnemonic (_("_Stop"));
+ menu_data.stop_item = item;
+ g_signal_connect (item, "activate",
+ G_CALLBACK (stop_shortcut_cb), sidebar);
+ gtk_widget_show (item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
+
+ /* Update everything! */
+
+ get_selection_info (sidebar, &sel_info);
+
+ check_popup_sensitivity (sidebar, &menu_data, &sel_info);
+
+ /* And let the caller spice things up */
+
+ if (sel_info.uri)
+ file = g_file_new_for_uri (sel_info.uri);
+ else
+ file = NULL;
+
+ emit_populate_popup (sidebar, GTK_MENU (sidebar->popup_menu), file);
+
+ g_object_unref (file);
+
+ free_selection_info (&sel_info);
+}
+
+static void
+bookmarks_popup_menu (GtkPlacesSidebar *sidebar,
+ GdkEventButton *event)
+{
+ int button;
+
+ if (sidebar->popup_menu)
+ gtk_widget_destroy (sidebar->popup_menu);
+
+ bookmarks_build_popup_menu (sidebar);
+
+ /* The event button needs to be 0 if we're popping up this menu from
+ * a button release, else a 2nd click outside the menu with any button
+ * other than the one that invoked the menu will be ignored (instead
+ * of dismissing the menu). This is a subtle fragility of the GTK menu code.
+ */
+ if (event) {
+ if (event->type == GDK_BUTTON_RELEASE)
+ button = 0;
+ else
+ button = event->button;
+ } else {
+ button = 0;
+ }
+
+ gtk_menu_popup (GTK_MENU (sidebar->popup_menu), /* menu */
+ NULL, /* parent_menu_shell */
+ NULL, /* parent_menu_item */
+ NULL, /* popup_position_func */
+ NULL, /* popup_position_user_data */
+ button, /* button */
+ event ? event->time : gtk_get_current_event_time ()); /* activate_time */
+}
+
+/* Callback used for the GtkWidget::popup-menu signal of the shortcuts list */
+static gboolean
+bookmarks_popup_menu_cb (GtkWidget *widget,
+ GtkPlacesSidebar *sidebar)
+{
+ bookmarks_popup_menu (sidebar, NULL);
+ return TRUE;
+}
+
+static gboolean
+bookmarks_button_release_event_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ GtkPlacesSidebar *sidebar)
+{
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ GtkTreeView *tree_view;
+ gboolean ret = FALSE;
+ gboolean res;
+
+ path = NULL;
+
+ if (event->type != GDK_BUTTON_RELEASE) {
+ return TRUE;
+ }
+
+ if (clicked_eject_button (sidebar, &path)) {
+ eject_or_unmount_bookmark (sidebar, path);
+ gtk_tree_path_free (path);
+
+ return FALSE;
+ }
+
+ tree_view = GTK_TREE_VIEW (widget);
+ model = gtk_tree_view_get_model (tree_view);
+
+ if (event->window != gtk_tree_view_get_bin_window (tree_view)) {
+ return FALSE;
+ }
+
+ res = gtk_tree_view_get_path_at_pos (tree_view, (int) event->x, (int) event->y,
+ &path, NULL, NULL, NULL);
+
+ if (!res || path == NULL) {
+ return FALSE;
+ }
+
+ res = gtk_tree_model_get_iter (model, &iter, path);
+ if (!res) {
+ gtk_tree_path_free (path);
+ return FALSE;
+ }
+
+ if (event->button == 1) {
+ open_selected_bookmark (sidebar, model, &iter, 0);
+ } else if (event->button == 2) {
+ GtkPlacesOpenFlags open_flags = GTK_PLACES_OPEN_NORMAL;
+
+ open_flags = ((event->state & GDK_CONTROL_MASK) ?
+ GTK_PLACES_OPEN_NEW_WINDOW :
+ GTK_PLACES_OPEN_NEW_TAB);
+
+ open_selected_bookmark (sidebar, model, &iter, open_flags);
+ ret = TRUE;
+ } else if (event->button == 3) {
+ PlaceType row_type;
+
+ gtk_tree_model_get (model, &iter,
+ PLACES_SIDEBAR_COLUMN_ROW_TYPE, &row_type,
+ -1);
+
+ if (row_type != PLACES_HEADING) {
+ bookmarks_popup_menu (sidebar, event);
+ }
+ }
+
+ gtk_tree_path_free (path);
+
+ return ret;
+}
+
+static void
+bookmarks_edited (GtkCellRenderer *cell,
+ gchar *path_string,
+ gchar *new_text,
+ GtkPlacesSidebar *sidebar)
+{
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ char *uri;
+ GFile *file;
+
+ g_object_set (cell, "editable", FALSE, NULL);
+
+ path = gtk_tree_path_new_from_string (path_string);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (sidebar->store), &iter, path);
+ gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
+ PLACES_SIDEBAR_COLUMN_URI, &uri,
+ -1);
+ gtk_tree_path_free (path);
+
+ file = g_file_new_for_uri (uri);
+ if (!_gtk_bookmarks_manager_has_bookmark (sidebar->bookmarks_manager, file)) {
+ _gtk_bookmarks_manager_insert_bookmark (sidebar->bookmarks_manager, file, -1, NULL);
+ }
+
+ _gtk_bookmarks_manager_set_bookmark_label (sidebar->bookmarks_manager, file, new_text, NULL); /*
NULL-GError */
+
+ g_object_unref (file);
+ g_free (uri);
+}
+
+static void
+bookmarks_editing_canceled (GtkCellRenderer *cell,
+ GtkPlacesSidebar *sidebar)
+{
+ g_object_set (cell, "editable", FALSE, NULL);
+}
+
+static gboolean
+tree_selection_func (GtkTreeSelection *selection,
+ GtkTreeModel *model,
+ GtkTreePath *path,
+ gboolean path_currently_selected,
+ gpointer user_data)
+{
+ GtkTreeIter iter;
+ PlaceType row_type;
+
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter,
+ PLACES_SIDEBAR_COLUMN_ROW_TYPE, &row_type,
+ -1);
+
+ if (row_type == PLACES_HEADING) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+icon_cell_renderer_func (GtkTreeViewColumn *column,
+ GtkCellRenderer *cell,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ PlaceType type;
+
+ gtk_tree_model_get (model, iter,
+ PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type,
+ -1);
+
+ if (type == PLACES_HEADING) {
+ g_object_set (cell,
+ "visible", FALSE,
+ NULL);
+ } else {
+ g_object_set (cell,
+ "visible", TRUE,
+ NULL);
+ }
+}
+
+static void
+padding_cell_renderer_func (GtkTreeViewColumn *column,
+ GtkCellRenderer *cell,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ PlaceType type;
+
+ gtk_tree_model_get (model, iter,
+ PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type,
+ -1);
+
+ if (type == PLACES_HEADING) {
+ g_object_set (cell,
+ "visible", FALSE,
+ "xpad", 0,
+ "ypad", 0,
+ NULL);
+ } else {
+ g_object_set (cell,
+ "visible", TRUE,
+ "xpad", 3,
+ "ypad", 3,
+ NULL);
+ }
+}
+
+static void
+heading_cell_renderer_func (GtkTreeViewColumn *column,
+ GtkCellRenderer *cell,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ PlaceType type;
+
+ gtk_tree_model_get (model, iter,
+ PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type,
+ -1);
+
+ if (type == PLACES_HEADING) {
+ g_object_set (cell,
+ "visible", TRUE,
+ NULL);
+ } else {
+ g_object_set (cell,
+ "visible", FALSE,
+ NULL);
+ }
+}
+
+static gint
+places_sidebar_sort_func (GtkTreeModel *model,
+ GtkTreeIter *iter_a,
+ GtkTreeIter *iter_b,
+ gpointer user_data)
+{
+ SectionType section_type_a, section_type_b;
+ PlaceType place_type_a, place_type_b;
+ gint retval = 0;
+
+ gtk_tree_model_get (model, iter_a,
+ PLACES_SIDEBAR_COLUMN_SECTION_TYPE, §ion_type_a,
+ PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type_a,
+ -1);
+ gtk_tree_model_get (model, iter_b,
+ PLACES_SIDEBAR_COLUMN_SECTION_TYPE, §ion_type_b,
+ PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type_b,
+ -1);
+
+ /* fall back to the default order if we're not in the
+ * XDG part of the computer section.
+ */
+ if ((section_type_a == section_type_b) &&
+ (section_type_a == SECTION_COMPUTER) &&
+ (place_type_a == place_type_b) &&
+ (place_type_a == PLACES_XDG_DIR)) {
+ gchar *name_a, *name_b;
+
+ gtk_tree_model_get (model, iter_a,
+ PLACES_SIDEBAR_COLUMN_NAME, &name_a,
+ -1);
+ gtk_tree_model_get (model, iter_b,
+ PLACES_SIDEBAR_COLUMN_NAME, &name_b,
+ -1);
+
+ retval = g_utf8_collate (name_a, name_b);
+
+ g_free (name_a);
+ g_free (name_b);
+ }
+
+ return retval;
+}
+
+static void
+update_hostname (GtkPlacesSidebar *sidebar)
+{
+ GVariant *variant;
+ gsize len;
+ const gchar *hostname;
+
+ if (sidebar->hostnamed_proxy == NULL)
+ return;
+
+ variant = g_dbus_proxy_get_cached_property (sidebar->hostnamed_proxy,
+ "PrettyHostname");
+ if (variant == NULL) {
+ return;
+ }
+
+ hostname = g_variant_get_string (variant, &len);
+ if (len > 0 &&
+ g_strcmp0 (sidebar->hostname, hostname) != 0) {
+ g_free (sidebar->hostname);
+ sidebar->hostname = g_strdup (hostname);
+ update_places (sidebar);
+ }
+
+ g_variant_unref (variant);
+}
+
+static void
+hostname_proxy_new_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GtkPlacesSidebar *sidebar = user_data;
+ GError *error = NULL;
+
+ sidebar->hostnamed_proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
+ g_clear_object (&sidebar->hostnamed_cancellable);
+
+ if (error != NULL) {
+ g_debug ("Failed to create D-Bus proxy: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ g_signal_connect_swapped (sidebar->hostnamed_proxy,
+ "g-properties-changed",
+ G_CALLBACK (update_hostname),
+ sidebar);
+ update_hostname (sidebar);
+}
+
+static void
+create_volume_monitor (GtkPlacesSidebar *sidebar)
+{
+ g_assert (sidebar->volume_monitor == NULL);
+
+ sidebar->volume_monitor = g_volume_monitor_get ();
+
+ g_signal_connect_object (sidebar->volume_monitor, "volume_added",
+ G_CALLBACK (volume_added_callback), sidebar, 0);
+ g_signal_connect_object (sidebar->volume_monitor, "volume_removed",
+ G_CALLBACK (volume_removed_callback), sidebar, 0);
+ g_signal_connect_object (sidebar->volume_monitor, "volume_changed",
+ G_CALLBACK (volume_changed_callback), sidebar, 0);
+ g_signal_connect_object (sidebar->volume_monitor, "mount_added",
+ G_CALLBACK (mount_added_callback), sidebar, 0);
+ g_signal_connect_object (sidebar->volume_monitor, "mount_removed",
+ G_CALLBACK (mount_removed_callback), sidebar, 0);
+ g_signal_connect_object (sidebar->volume_monitor, "mount_changed",
+ G_CALLBACK (mount_changed_callback), sidebar, 0);
+ g_signal_connect_object (sidebar->volume_monitor, "drive_disconnected",
+ G_CALLBACK (drive_disconnected_callback), sidebar, 0);
+ g_signal_connect_object (sidebar->volume_monitor, "drive_connected",
+ G_CALLBACK (drive_connected_callback), sidebar, 0);
+ g_signal_connect_object (sidebar->volume_monitor, "drive_changed",
+ G_CALLBACK (drive_changed_callback), sidebar, 0);
+}
+
+static void
+bookmarks_changed_cb (gpointer data)
+{
+ GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (data);
+
+ update_places (sidebar);
+}
+
+static gboolean
+tree_view_button_press_callback (GtkWidget *tree_view,
+ GdkEventButton *event,
+ gpointer data)
+{
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+
+ if (event->button == 1 && event->type == GDK_BUTTON_PRESS) {
+ if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (tree_view),
+ event->x, event->y,
+ &path,
+ &column,
+ NULL,
+ NULL)) {
+ gtk_tree_view_row_activated (GTK_TREE_VIEW (tree_view), path, column);
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+tree_view_set_activate_on_single_click (GtkTreeView *tree_view)
+{
+ g_signal_connect (tree_view, "button_press_event",
+ G_CALLBACK (tree_view_button_press_callback),
+ NULL);
+}
+
+static void
+trash_monitor_trash_state_changed_cb (GtkTrashMonitor *monitor,
+ GtkPlacesSidebar *sidebar)
+{
+ update_places (sidebar);
+}
+
+
+static void
+gtk_places_sidebar_init (GtkPlacesSidebar *sidebar)
+{
+ GtkTreeView *tree_view;
+ GtkTreeViewColumn *col;
+ GtkCellRenderer *cell;
+ GtkTreeSelection *selection;
+ GIcon *eject;
+
+ gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (sidebar)),
GTK_STYLE_CLASS_SIDEBAR);
+
+ create_volume_monitor (sidebar);
+
+ sidebar->open_flags = GTK_PLACES_OPEN_NORMAL;
+
+ sidebar->bookmarks_manager = _gtk_bookmarks_manager_new (bookmarks_changed_cb, sidebar);
+
+ sidebar->trash_monitor = _gtk_trash_monitor_get ();
+ sidebar->trash_monitor_changed_id = g_signal_connect (sidebar->trash_monitor, "trash-state-changed",
+ G_CALLBACK
(trash_monitor_trash_state_changed_cb), sidebar);
+
+ sidebar->shortcuts = NULL;
+
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sidebar),
+ GTK_POLICY_NEVER,
+ GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (sidebar), NULL);
+ gtk_scrolled_window_set_vadjustment (GTK_SCROLLED_WINDOW (sidebar), NULL);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sidebar), GTK_SHADOW_IN);
+
+ gtk_style_context_set_junction_sides (gtk_widget_get_style_context (GTK_WIDGET (sidebar)),
+ GTK_JUNCTION_RIGHT | GTK_JUNCTION_LEFT);
+
+ /* tree view */
+ tree_view = GTK_TREE_VIEW (gtk_tree_view_new ());
+ gtk_tree_view_set_headers_visible (tree_view, FALSE);
+
+ col = GTK_TREE_VIEW_COLUMN (gtk_tree_view_column_new ());
+
+ /* initial padding */
+ cell = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (col, cell, FALSE);
+ g_object_set (cell,
+ "xpad", 6,
+ NULL);
+
+ /* headings */
+ cell = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (col, cell, FALSE);
+ gtk_tree_view_column_set_attributes (col, cell,
+ "text", PLACES_SIDEBAR_COLUMN_HEADING_TEXT,
+ NULL);
+ g_object_set (cell,
+ "weight", PANGO_WEIGHT_BOLD,
+ "weight-set", TRUE,
+ "ypad", 6,
+ "xpad", 0,
+ NULL);
+ gtk_tree_view_column_set_cell_data_func (col, cell,
+ heading_cell_renderer_func,
+ sidebar, NULL);
+
+ /* icon padding */
+ cell = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (col, cell, FALSE);
+ gtk_tree_view_column_set_cell_data_func (col, cell,
+ padding_cell_renderer_func,
+ sidebar, NULL);
+
+ /* icon renderer */
+ cell = gtk_cell_renderer_pixbuf_new ();
+ g_object_set (cell, "follow-state", TRUE, NULL);
+ gtk_tree_view_column_pack_start (col, cell, FALSE);
+ gtk_tree_view_column_set_attributes (col, cell,
+ "gicon", PLACES_SIDEBAR_COLUMN_GICON,
+ NULL);
+ gtk_tree_view_column_set_cell_data_func (col, cell,
+ icon_cell_renderer_func,
+ sidebar, NULL);
+
+ /* eject text renderer */
+ cell = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (col, cell, TRUE);
+ gtk_tree_view_column_set_attributes (col, cell,
+ "text", PLACES_SIDEBAR_COLUMN_NAME,
+ "visible", PLACES_SIDEBAR_COLUMN_EJECT,
+ NULL);
+ g_object_set (cell,
+ "ellipsize", PANGO_ELLIPSIZE_END,
+ "ellipsize-set", TRUE,
+ NULL);
+
+ /* eject icon renderer */
+ cell = gtk_cell_renderer_pixbuf_new ();
+ sidebar->eject_icon_cell_renderer = cell;
+ eject = g_themed_icon_new_with_default_fallbacks ("media-eject-symbolic");
+ g_object_set (cell,
+ "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE,
+ "stock-size", GTK_ICON_SIZE_MENU,
+ "xpad", EJECT_BUTTON_XPAD,
+ /* align right, because for some reason gtk+ expands
+ this even though we tell it not to. */
+ "xalign", 1.0,
+ "follow-state", TRUE,
+ "gicon", eject,
+ NULL);
+ gtk_tree_view_column_pack_start (col, cell, FALSE);
+ gtk_tree_view_column_set_attributes (col, cell,
+ "visible", PLACES_SIDEBAR_COLUMN_EJECT,
+ NULL);
+ g_object_unref (eject);
+
+ /* normal text renderer */
+ cell = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (col, cell, TRUE);
+ g_object_set (G_OBJECT (cell), "editable", FALSE, NULL);
+ gtk_tree_view_column_set_attributes (col, cell,
+ "text", PLACES_SIDEBAR_COLUMN_NAME,
+ "visible", PLACES_SIDEBAR_COLUMN_NO_EJECT,
+ "editable-set", PLACES_SIDEBAR_COLUMN_BOOKMARK,
+ NULL);
+ g_object_set (cell,
+ "ellipsize", PANGO_ELLIPSIZE_END,
+ "ellipsize-set", TRUE,
+ NULL);
+
+ g_signal_connect (cell, "edited",
+ G_CALLBACK (bookmarks_edited), sidebar);
+ g_signal_connect (cell, "editing-canceled",
+ G_CALLBACK (bookmarks_editing_canceled), sidebar);
+
+ /* this is required to align the eject buttons to the right */
+ gtk_tree_view_column_set_max_width (GTK_TREE_VIEW_COLUMN (col), 24);
+ gtk_tree_view_append_column (tree_view, col);
+
+ sidebar->store = shortcuts_model_new (sidebar);
+ gtk_tree_view_set_tooltip_column (tree_view, PLACES_SIDEBAR_COLUMN_TOOLTIP);
+
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sidebar->store),
+ PLACES_SIDEBAR_COLUMN_NAME,
+ GTK_SORT_ASCENDING);
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sidebar->store),
+ PLACES_SIDEBAR_COLUMN_NAME,
+ places_sidebar_sort_func,
+ sidebar, NULL);
+
+ gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (sidebar->store));
+ gtk_container_add (GTK_CONTAINER (sidebar), GTK_WIDGET (tree_view));
+ gtk_widget_show (GTK_WIDGET (tree_view));
+ gtk_tree_view_set_enable_search (tree_view, FALSE);
+
+ gtk_widget_show (GTK_WIDGET (sidebar));
+ sidebar->tree_view = tree_view;
+
+ gtk_tree_view_set_search_column (tree_view, PLACES_SIDEBAR_COLUMN_NAME);
+ selection = gtk_tree_view_get_selection (tree_view);
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
+
+ gtk_tree_selection_set_select_function (selection,
+ tree_selection_func,
+ sidebar,
+ NULL);
+
+ gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (tree_view),
+ GDK_BUTTON1_MASK,
+ dnd_source_targets, G_N_ELEMENTS (dnd_source_targets),
+ GDK_ACTION_MOVE);
+ gtk_drag_dest_set (GTK_WIDGET (tree_view),
+ 0,
+ dnd_drop_targets, G_N_ELEMENTS (dnd_drop_targets),
+ GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK);
+
+ g_signal_connect (tree_view, "key-press-event",
+ G_CALLBACK (bookmarks_key_press_event_cb), sidebar);
+
+ g_signal_connect (tree_view, "drag-motion",
+ G_CALLBACK (drag_motion_callback), sidebar);
+ g_signal_connect (tree_view, "drag-leave",
+ G_CALLBACK (drag_leave_callback), sidebar);
+ g_signal_connect (tree_view, "drag-data-received",
+ G_CALLBACK (drag_data_received_callback), sidebar);
+ g_signal_connect (tree_view, "drag-drop",
+ G_CALLBACK (drag_drop_callback), sidebar);
+
+ g_signal_connect (tree_view, "popup-menu",
+ G_CALLBACK (bookmarks_popup_menu_cb), sidebar);
+ g_signal_connect (tree_view, "button-release-event",
+ G_CALLBACK (bookmarks_button_release_event_cb), sidebar);
+
+ tree_view_set_activate_on_single_click (sidebar->tree_view);
+
+ sidebar->hostname = g_strdup (_("Computer"));
+ sidebar->hostnamed_cancellable = g_cancellable_new ();
+ g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES,
+ NULL,
+ "org.freedesktop.hostname1",
+ "/org/freedesktop/hostname1",
+ "org.freedesktop.hostname1",
+ sidebar->hostnamed_cancellable,
+ hostname_proxy_new_cb,
+ sidebar);
+}
+
+static void
+gtk_places_sidebar_set_property (GObject *obj,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (obj);
+
+ switch (property_id) {
+ case PROP_LOCATION:
+ gtk_places_sidebar_set_location (sidebar, g_value_get_object (value));
+ break;
+ case PROP_OPEN_FLAGS:
+ gtk_places_sidebar_set_open_flags (sidebar, g_value_get_flags (value));
+ break;
+ case PROP_SHOW_DESKTOP:
+ gtk_places_sidebar_set_show_desktop (sidebar, g_value_get_boolean (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_places_sidebar_get_property (GObject *obj,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (obj);
+
+ switch (property_id) {
+ case PROP_LOCATION:
+ g_value_take_object (value, gtk_places_sidebar_get_location (sidebar));
+ break;
+ case PROP_OPEN_FLAGS:
+ g_value_set_flags (value, gtk_places_sidebar_get_open_flags (sidebar));
+ break;
+ case PROP_SHOW_DESKTOP:
+ g_value_set_boolean (value, gtk_places_sidebar_get_show_desktop (sidebar));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_places_sidebar_dispose (GObject *object)
+{
+ GtkPlacesSidebar *sidebar;
+
+ sidebar = GTK_PLACES_SIDEBAR (object);
+
+ sidebar->tree_view = NULL;
+
+ free_drag_data (sidebar);
+
+ if (sidebar->bookmarks_manager != NULL) {
+ _gtk_bookmarks_manager_free (sidebar->bookmarks_manager);
+ sidebar->bookmarks_manager = NULL;
+ }
+
+ if (sidebar->popup_menu) {
+ gtk_widget_destroy (sidebar->popup_menu);
+ sidebar->popup_menu = NULL;
+ }
+
+ if (sidebar->trash_monitor) {
+ g_signal_handler_disconnect (sidebar->trash_monitor, sidebar->trash_monitor_changed_id);
+ sidebar->trash_monitor_changed_id = 0;
+ g_clear_object (&sidebar->trash_monitor);
+ }
+
+ g_clear_object (&sidebar->store);
+
+ g_slist_free_full (sidebar->shortcuts, g_object_unref);
+ sidebar->shortcuts = NULL;
+
+ if (sidebar->volume_monitor != NULL) {
+ g_signal_handlers_disconnect_by_func (sidebar->volume_monitor,
+ volume_added_callback, sidebar);
+ g_signal_handlers_disconnect_by_func (sidebar->volume_monitor,
+ volume_removed_callback, sidebar);
+ g_signal_handlers_disconnect_by_func (sidebar->volume_monitor,
+ volume_changed_callback, sidebar);
+ g_signal_handlers_disconnect_by_func (sidebar->volume_monitor,
+ mount_added_callback, sidebar);
+ g_signal_handlers_disconnect_by_func (sidebar->volume_monitor,
+ mount_removed_callback, sidebar);
+ g_signal_handlers_disconnect_by_func (sidebar->volume_monitor,
+ mount_changed_callback, sidebar);
+ g_signal_handlers_disconnect_by_func (sidebar->volume_monitor,
+ drive_disconnected_callback, sidebar);
+ g_signal_handlers_disconnect_by_func (sidebar->volume_monitor,
+ drive_connected_callback, sidebar);
+ g_signal_handlers_disconnect_by_func (sidebar->volume_monitor,
+ drive_changed_callback, sidebar);
+
+ g_clear_object (&sidebar->volume_monitor);
+ }
+
+ if (sidebar->hostnamed_cancellable != NULL) {
+ g_cancellable_cancel (sidebar->hostnamed_cancellable);
+ g_clear_object (&sidebar->hostnamed_cancellable);
+ }
+
+ g_clear_object (&sidebar->hostnamed_proxy);
+ g_free (sidebar->hostname);
+ sidebar->hostname = NULL;
+
+ G_OBJECT_CLASS (gtk_places_sidebar_parent_class)->dispose (object);
+}
+
+static void
+gtk_places_sidebar_class_init (GtkPlacesSidebarClass *class)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = (GObjectClass *) class;
+
+ gobject_class->dispose = gtk_places_sidebar_dispose;
+ gobject_class->set_property = gtk_places_sidebar_set_property;
+ gobject_class->get_property = gtk_places_sidebar_get_property;
+
+ GTK_WIDGET_CLASS (class)->focus = gtk_places_sidebar_focus;
+
+ /**
+ * GtkPlacesSidebar::open-location:
+ * @sidebar: the object which received the signal.
+ * @location: #GFile to which the caller should switch.
+ * @open_flags: a single value from #GtkPlacesOpenFlags specifying how the @location should be opened.
+ *
+ * The places sidebar emits this signal when the user selects a location
+ * in it. The calling application should display the contents of that
+ * location; for example, a file manager should show a list of files in
+ * the specified location.
+ *
+ * Since: 3.8
+ */
+ places_sidebar_signals [OPEN_LOCATION] =
+ g_signal_new (I_("open-location"),
+ G_OBJECT_CLASS_TYPE (gobject_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GtkPlacesSidebarClass, open_location),
+ NULL, NULL,
+ _gtk_marshal_VOID__OBJECT_FLAGS,
+ G_TYPE_NONE, 2,
+ G_TYPE_OBJECT,
+ GTK_TYPE_PLACES_OPEN_FLAGS);
+
+ /**
+ * GtkPlacesSidebar::populate-popup:
+ * @sidebar: the object which received the signal.
+ * @menu: a #GtkMenu.
+ * @selected_item: #GFile with the item to which the menu should refer.
+ *
+ * The places sidebar emits this signal when the user invokes a contextual
+ * menu on one of its items. In the signal handler, the application may
+ * add extra items to the menu as appropriate. For example, a file manager
+ * may want to add a "Properties" command to the menu.
+ *
+ * It is not necessary to store the @selected_item for each menu item;
+ * during their GtkMenuItem::activate callbacks, the application can use
+ * gtk_places_sidebar_get_location() to get the file to which the item
+ * refers.
+ *
+ * The @menu and all its menu items are destroyed after the user
+ * dismisses the menu. The menu is re-created (and thus, this signal is
+ * emitted) every time the user activates the contextual menu.
+ *
+ * Since: 3.8
+ */
+ places_sidebar_signals [POPULATE_POPUP] =
+ g_signal_new (I_("populate-popup"),
+ G_OBJECT_CLASS_TYPE (gobject_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GtkPlacesSidebarClass, populate_popup),
+ NULL, NULL,
+ _gtk_marshal_VOID__OBJECT_OBJECT,
+ G_TYPE_NONE, 2,
+ G_TYPE_OBJECT,
+ G_TYPE_OBJECT);
+
+ /**
+ * GtkPlacesSidebar::show-error-message:
+ * @sidebar: the object which received the signal.
+ * @primary: primary message with a summary of the error to show.
+ * @secondary: secondary message with details of the error to show.
+ *
+ * The places sidebar emits this signal when it needs the calling
+ * application to present an error message. Most of these messages
+ * refer to mounting or unmounting media, for example, when a drive
+ * cannot be started for some reason.
+ *
+ * Since: 3.8
+ */
+ places_sidebar_signals [SHOW_ERROR_MESSAGE] =
+ g_signal_new (I_("show-error-message"),
+ G_OBJECT_CLASS_TYPE (gobject_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GtkPlacesSidebarClass, show_error_message),
+ NULL, NULL,
+ _gtk_marshal_VOID__STRING_STRING,
+ G_TYPE_NONE, 2,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
+
+ /**
+ * GtkPlacesSidebar::drag-action-requested:
+ * @sidebar: the object which received the signal.
+ * @context: #GdkDragContext with information about the drag operation
+ * @dest_file: #GFile with the tentative location that is being hovered for a drop
+ * @source_file_list: (element-type GFile) (transfer none): List of #GFile that are being dragged
+ * @action: Location in which to store the drag action here
+ *
+ * When the user starts a drag-and-drop operation and the sidebar needs
+ * to ask the application for which drag action to perform, then the
+ * sidebar will emit this signal.
+ *
+ * The application can evaluate the @context for customary actions, or
+ * it can check the type of the files indicated by @source_file_list against the
+ * possible actions for the destination @dest_file.
+ */
+ places_sidebar_signals [DRAG_ACTION_REQUESTED] =
+ g_signal_new (I_("drag-action-requested"),
+ G_OBJECT_CLASS_TYPE (gobject_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GtkPlacesSidebarClass, drag_action_requested),
+ NULL, NULL,
+ _gtk_marshal_VOID__OBJECT_OBJECT_POINTER_POINTER,
+ G_TYPE_NONE, 4,
+ GDK_TYPE_DRAG_CONTEXT,
+ G_TYPE_OBJECT,
+ G_TYPE_POINTER, /* FIXME: (GList *) is there something friendlier to language
bindings? */
+ G_TYPE_POINTER /* FIXME: (inout int) is there something friendlier to language
bindings? */);
+
+ /**
+ * GtkPlacesSidebar::drag-action-ask:
+ * @sidebar: the object which received the signal.
+ * @actions: Possible drag actions that need to be asked for.
+ *
+ * The places sidebar emits this signal when it needs to ask the application
+ * to pop up a menu to ask the user for which drag action to perform.
+ *
+ * Return value: the final drag action that the sidebar should pass to the drag side
+ * of the drag-and-drop operation.
+ *
+ * Since: 3.8
+ */
+ places_sidebar_signals [DRAG_ACTION_ASK] =
+ g_signal_new (I_("drag-action-ask"),
+ G_OBJECT_CLASS_TYPE (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkPlacesSidebarClass, drag_action_ask),
+ NULL, NULL,
+ _gtk_marshal_INT__INT,
+ G_TYPE_INT, 1,
+ G_TYPE_INT);
+
+ /**
+ * GtkPlacesSidebar::drag-perform-drop:
+ * @sidebar: the object which received the signal.
+ * @dest_file: Destination #GFile.
+ * @source_file_list: (element-type GFile) (transfer none): #GList of #GFile that got dropped.
+ * @action: Drop action to perform.
+ *
+ * The places sidebar emits this signal when the user completes a
+ * drag-and-drop operation and one of the sidebar's items is the
+ * destination. This item is in the @dest_file, and the
+ * @source_file_list has the list of files that are dropped into it and
+ * which should be copied/moved/etc. based on the specified @action.
+ *
+ * Since: 3.8
+ */
+ places_sidebar_signals [DRAG_PERFORM_DROP] =
+ g_signal_new (I_("drag-perform-drop"),
+ G_OBJECT_CLASS_TYPE (gobject_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GtkPlacesSidebarClass, drag_perform_drop),
+ NULL, NULL,
+ _gtk_marshal_VOID__OBJECT_POINTER_INT,
+ G_TYPE_NONE, 3,
+ G_TYPE_OBJECT,
+ G_TYPE_POINTER, /* FIXME: (GList *) is there something friendlier to language
bindings? */
+ G_TYPE_INT);
+
+ properties[PROP_LOCATION] =
+ g_param_spec_object ("location",
+ P_("Location to select"),
+ P_("The location to highlight in the sidebar"),
+ G_TYPE_FILE,
+ G_PARAM_READWRITE);
+ properties[PROP_OPEN_FLAGS] =
+ g_param_spec_flags ("open-flags",
+ P_("The open modes supported for this widget"),
+ P_("The set of open modes supported for this widget"),
+ GTK_TYPE_PLACES_OPEN_FLAGS,
+ GTK_PLACES_OPEN_NORMAL,
+ G_PARAM_READWRITE);
+ properties[PROP_SHOW_DESKTOP] =
+ g_param_spec_boolean ("show-desktop",
+ P_("Whether to show desktop"),
+ P_("Whether the sidebar includes a builtin shortcut to the desktop
folder"),
+ FALSE,
+ G_PARAM_READWRITE);
+
+ g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
+}
+
+/**
+ * gtk_places_sidebar_new:
+ *
+ * Creates a new #GtkPlacesSidebar widget. The application should connect
+ * to at least the #GtkPlacesSidebar::open-location signal to be notified
+ * when the user makes a selection in the sidebar.
+ */
+GtkWidget *
+gtk_places_sidebar_new (void)
+{
+ return GTK_WIDGET (g_object_new (gtk_places_sidebar_get_type (), NULL));
+}
+
+
+
+/* Drag and drop interfaces */
+
+/* GtkTreeDragSource::row_draggable implementation for the shortcuts model */
+static gboolean
+shortcuts_model_row_draggable (GtkTreeDragSource *drag_source,
+ GtkTreePath *path)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ PlaceType place_type;
+ SectionType section_type;
+
+ model = GTK_TREE_MODEL (drag_source);
+
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter,
+ PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type,
+ PLACES_SIDEBAR_COLUMN_SECTION_TYPE, §ion_type,
+ -1);
+
+ if (place_type != PLACES_HEADING && section_type == SECTION_BOOKMARKS)
+ return TRUE;
+
+ return FALSE;
+}
+
+/* Fill the GtkTreeDragSourceIface vtable */
+static void
+shortcuts_model_class_init (ShortcutsModelClass *klass)
+{
+}
+
+static void
+shortcuts_model_init (ShortcutsModel *model)
+{
+ model->sidebar = NULL;
+}
+
+static void
+shortcuts_model_drag_source_iface_init (GtkTreeDragSourceIface *iface)
+{
+ iface->row_draggable = shortcuts_model_row_draggable;
+}
+
+static GtkListStore *
+shortcuts_model_new (GtkPlacesSidebar *sidebar)
+{
+ ShortcutsModel *model;
+ GType model_types[PLACES_SIDEBAR_COLUMN_COUNT] = {
+ G_TYPE_INT,
+ G_TYPE_STRING,
+ G_TYPE_DRIVE,
+ G_TYPE_VOLUME,
+ G_TYPE_MOUNT,
+ G_TYPE_STRING,
+ G_TYPE_ICON,
+ G_TYPE_INT,
+ G_TYPE_BOOLEAN,
+ G_TYPE_BOOLEAN,
+ G_TYPE_BOOLEAN,
+ G_TYPE_STRING,
+ G_TYPE_INT,
+ G_TYPE_STRING
+ };
+
+ model = g_object_new (shortcuts_model_get_type (), NULL);
+ model->sidebar = sidebar;
+
+ gtk_list_store_set_column_types (GTK_LIST_STORE (model),
+ PLACES_SIDEBAR_COLUMN_COUNT,
+ model_types);
+
+ return GTK_LIST_STORE (model);
+}
+
+
+
+/* Public methods for GtkPlacesSidebar */
+
+/**
+ * gtk_places_sidebar_set_open_flags:
+ * @sidebar: a places sidebar
+ * @flags: Bitmask of modes in which the calling application can open locations
+ *
+ * Sets the way in which the calling application can open new locations from
+ * the places sidebar. For example, some applications only open locations
+ * "directly" into their main view, while others may support opening locations
+ * in a new notebook tab or a new window.
+ *
+ * This function is used to tell the places @sidebar about the ways in which the
+ * application can open new locations, so that the sidebar can display (or not)
+ * the "Open in new tab" and "Open in new window" menu items as appropriate.
+ *
+ * When the #GtkPlacesSidebar::open-location signal is emitted, its flags
+ * argument will be set to one of the @flags that was passed in
+ * gtk_places_sidebar_set_open_flags().
+ *
+ * Passing 0 for @flags will cause #GTK_PLACES_OPEN_NORMAL to always be sent
+ * to callbacks for the "open-location" signal.
+ *
+ * Since: 3.8
+ */
+void
+gtk_places_sidebar_set_open_flags (GtkPlacesSidebar *sidebar, GtkPlacesOpenFlags flags)
+{
+ g_return_if_fail (GTK_IS_PLACES_SIDEBAR (sidebar));
+
+ if (sidebar->open_flags != flags) {
+ sidebar->open_flags = flags;
+ g_object_notify_by_pspec (G_OBJECT (sidebar), properties[PROP_OPEN_FLAGS]);
+ }
+}
+
+GtkPlacesOpenFlags
+gtk_places_sidebar_get_open_flags (GtkPlacesSidebar *sidebar)
+{
+ g_return_val_if_fail (GTK_IS_PLACES_SIDEBAR (sidebar), 0);
+
+ return sidebar->open_flags;
+}
+
+/**
+ * gtk_places_sidebar_set_location:
+ * @sidebar: a places sidebar
+ * @location: (allow-none): location to select, or #NULL for no current path
+ *
+ * Sets the location that is being shown in the widgets surrounding the
+ * @sidebar, for example, in a folder view in a file manager. In turn, the
+ * @sidebar will highlight that location if it is being shown in the list of
+ * places, or it will unhighlight everything if the @location is not among the
+ * places in the list.
+ *
+ * Since: 3.8
+ */
+void
+gtk_places_sidebar_set_location (GtkPlacesSidebar *sidebar, GFile *location)
+{
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+ gboolean valid;
+ char *iter_uri;
+ char *uri;
+
+ g_return_if_fail (GTK_IS_PLACES_SIDEBAR (sidebar));
+
+ selection = gtk_tree_view_get_selection (sidebar->tree_view);
+ gtk_tree_selection_unselect_all (selection);
+
+ if (location == NULL)
+ goto out;
+
+ uri = g_file_get_uri (location);
+
+ valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (sidebar->store), &iter);
+ while (valid) {
+ gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
+ PLACES_SIDEBAR_COLUMN_URI, &iter_uri,
+ -1);
+ if (iter_uri != NULL) {
+ if (strcmp (iter_uri, uri) == 0) {
+ g_free (iter_uri);
+ gtk_tree_selection_select_iter (selection, &iter);
+ break;
+ }
+ g_free (iter_uri);
+ }
+ valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (sidebar->store), &iter);
+ }
+
+ g_free (uri);
+
+ out:
+ g_object_notify_by_pspec (G_OBJECT (sidebar), properties[PROP_LOCATION]);
+}
+
+/**
+ * gtk_places_sidebar_get_location:
+ * @sidebar: a places sidebar
+ *
+ * Gets the currently-selected location in the @sidebar. This can be #NULL when
+ * nothing is selected, for example, when gtk_places_sidebar_set_location() has
+ * been called with a location that is not among the sidebar's list of places to
+ * show.
+ *
+ * You can use this function to get the selection in the @sidebar. Also, if you
+ * connect to the #GtkPlacesSidebar::popup-menu signal, you can use this
+ * function to get the location that is being referred to during the callbacks
+ * for your menu items.
+ *
+ * Returns: (transfer full): a GFile with the selected location, or #NULL if nothing is visually
+ * selected.
+ *
+ * Since: 3.8
+ */
+GFile *
+gtk_places_sidebar_get_location (GtkPlacesSidebar *sidebar)
+{
+ GtkTreeIter iter;
+ GFile *file;
+
+ g_return_val_if_fail (sidebar != NULL, NULL);
+
+ file = NULL;
+
+ if (get_selected_iter (sidebar, &iter)) {
+ char *uri;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
+ PLACES_SIDEBAR_COLUMN_URI, &uri,
+ -1);
+
+ file = g_file_new_for_uri (uri);
+ g_free (uri);
+ }
+
+ return file;
+}
+
+/**
+ * gtk_places_sidebar_set_show_desktop:
+ * @sidebar: a places sidebar
+ * @show_desktop: whether to show an item for the Desktop folder
+ *
+ * Sets whether the @sidebar should show an item for the Desktop folder; this is off by default.
+ * An application may want to turn this on if the desktop environment actually supports the
+ * notion of a desktop.
+ *
+ * Since: 3.8
+ */
+void
+gtk_places_sidebar_set_show_desktop (GtkPlacesSidebar *sidebar, gboolean show_desktop)
+{
+ g_return_if_fail (GTK_IS_PLACES_SIDEBAR (sidebar));
+
+ show_desktop = !!show_desktop;
+ if (sidebar->show_desktop != show_desktop) {
+ sidebar->show_desktop = show_desktop;
+ update_places (sidebar);
+ g_object_notify_by_pspec (G_OBJECT (sidebar), properties[PROP_SHOW_DESKTOP]);
+ }
+}
+
+/**
+ * gtk_places_sidebar_get_show_desktop:
+ * @sidebar: a places sidebar
+ *
+ * Returns the value previously set with gtk_places_sidebar_set_show_desktop()
+ *
+ * Return value: %TRUE if the sidebar will display a builtin shortcut to the desktop folder.
+ *
+ * Since: 3.8
+ */
+gboolean
+gtk_places_sidebar_get_show_desktop (GtkPlacesSidebar *sidebar)
+{
+ g_return_val_if_fail (GTK_IS_PLACES_SIDEBAR (sidebar), FALSE);
+
+ return sidebar->show_desktop;
+}
+
+static GSList *
+find_shortcut_link (GtkPlacesSidebar *sidebar, GFile *location)
+{
+ GSList *l;
+
+ for (l = sidebar->shortcuts; l; l = l->next) {
+ GFile *shortcut;
+
+ shortcut = G_FILE (l->data);
+ if (g_file_equal (shortcut, location))
+ return l;
+ }
+
+ return NULL;
+}
+
+/**
+ * gtk_places_sidebar_add_shortcut:
+ * @sidebar: a places sidebar
+ * @location: location to add as an application-specific shortcut
+ *
+ * Applications may want to present some folders in the places sidebar if
+ * they could be immediately useful to users. For example, a drawing
+ * program could add a "/usr/share/clipart" location when the sidebar is
+ * being used in an "Insert Clipart" dialog box.
+ *
+ * This function adds the specified @location to a special place for immutable
+ * shortcuts. The shortcuts are application-specific; they are not shared
+ * across applications, and they are not persistent. If this function
+ * is called multiple times with different locations, then they are added
+ * to the sidebar's list in the same order as the function is called.
+ *
+ * Since: 3.8
+ */
+void
+gtk_places_sidebar_add_shortcut (GtkPlacesSidebar *sidebar, GFile *location)
+{
+ g_return_if_fail (GTK_IS_PLACES_SIDEBAR (sidebar));
+ g_return_if_fail (G_IS_FILE (location));
+
+ g_object_ref (location);
+ sidebar->shortcuts = g_slist_append (sidebar->shortcuts, location);
+
+ update_places (sidebar);
+}
+
+/**
+ * gtk_places_sidebar_remove_shortcut:
+ * @sidebar: a places sidebar
+ * @location: location to remove
+ *
+ * Removes an application-specific shortcut that has been previously been
+ * inserted with gtk_places_sidebar_add_shortcut(). If the @location is not a
+ * shortcut in the sidebar, then nothing is done.
+ *
+ * Since: 3.8
+ */
+void
+gtk_places_sidebar_remove_shortcut (GtkPlacesSidebar *sidebar, GFile *location)
+{
+ GSList *link;
+ GFile *shortcut;
+
+ g_return_if_fail (GTK_IS_PLACES_SIDEBAR (sidebar));
+ g_return_if_fail (G_IS_FILE (location));
+
+ link = find_shortcut_link (sidebar, location);
+ if (!link)
+ return;
+
+ shortcut = G_FILE (link->data);
+ g_object_unref (shortcut);
+
+ sidebar->shortcuts = g_slist_delete_link (sidebar->shortcuts, link);
+ update_places (sidebar);
+}
+
+/**
+ * gtk_places_sidebar_list_shortcuts:
+ * @sidebar: a places sidebar
+ *
+ * Return value: (element-type GFile) (transfer full): A #GSList of #GFile of the locations
+ * that have been added as application-specific shortcuts with gtk_places_sidebar_add_shortcut().
+ * To free this list, you can use
+ * |[
+ * g_slist_free_full (list, (GDestroyNotify) g_object_unref);
+ * ]|
+ *
+ * Since: 3.8
+ */
+GSList *
+gtk_places_sidebar_list_shortcuts (GtkPlacesSidebar *sidebar)
+{
+ g_return_val_if_fail (GTK_IS_PLACES_SIDEBAR (sidebar), FALSE);
+
+ return g_slist_copy_deep (sidebar->shortcuts, (GCopyFunc) g_object_ref, NULL);
+}
+
+/**
+ * gtk_places_sidebar_get_nth_bookmark:
+ * @sidebar: a places sidebar
+ * @n: index of the bookmark to query
+ *
+ * This function queries the bookmarks added by the user to the places sidebar,
+ * and returns one of them. This function is used by #GtkFileChooser to implement
+ * the "Alt-1", "Alt-2", etc. shortcuts, which activate the cooresponding bookmark.
+ *
+ * Return value: (transfer full): The bookmark specified by the index @n, or
+ * #NULL if no such index exist. Note that the indices start at 0, even though
+ * the file chooser starts them with the keyboard shortcut "Alt-1".
+ *
+ * Since: 3.8
+ */
+GFile *
+gtk_places_sidebar_get_nth_bookmark (GtkPlacesSidebar *sidebar, int n)
+{
+ GtkTreeIter iter;
+ int k;
+ GFile *file;
+
+ g_return_val_if_fail (GTK_IS_PLACES_SIDEBAR (sidebar), NULL);
+
+ file = NULL;
+
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (sidebar->store), &iter)) {
+ k = 0;
+
+ do {
+ PlaceType place_type;
+ char *uri;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
+ PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type,
+ PLACES_SIDEBAR_COLUMN_URI, &uri,
+ -1);
+
+ if (place_type == PLACES_BOOKMARK) {
+ if (k == n) {
+ file = g_file_new_for_uri (uri);
+ g_free (uri);
+ break;
+ }
+
+ g_free (uri);
+ k++;
+ }
+ } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (sidebar->store), &iter));
+ }
+
+ return file;
+}
diff --cc gtk/org.gtk.Settings.FileChooser.gschema.xml
index 5bef095,d7d8705..f2424e5
--- a/gtk/org.gtk.Settings.FileChooser.gschema.xml
+++ b/gtk/org.gtk.Settings.FileChooser.gschema.xml
@@@ -33,12 -33,7 +33,12 @@@
<value nick='descending' value='1'/>
</enum>
+ <enum id='org.gtk.Settings.FileChooser.StartupMode'>
+ <value nick='recent' value='0'/>
+ <value nick='cwd' value='1'/>
+ </enum>
+
- <schema id='org.gtk.Settings.FileChooser'>
+ <schema id='org.gtk.Settings.FileChooser' path='/org/gtk/settings/file-chooser/'>
<key name='last-folder-uri' type='s'>
<default>""</default>
</key>
@@@ -66,9 -63,9 +68,12 @@@
<key name='window-size' type='(ii)'>
<default>(-1, -1)</default>
</key>
+ <key name='startup-mode' enum='org.gtk.Settings.FileChooser.StartupMode'>
+ <default>'recent'</default>
+ </key>
+ <key name='sidebar-width' type='i'>
+ <default>148</default>
+ </key>
</schema>
</schemalist>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]