1
0
mirror of https://gitlab.gnome.org/GNOME/nautilus synced 2024-06-28 14:35:28 +00:00

Compare commits

...

139 Commits

Author SHA1 Message Date
Automeris naranja
ce573608d8 window: Stop setting a minimum window width
Adw(Application)Window now has a minimum size[1]. However,
the default-height, which is 200, which isn't sufficient
for Nautilus[2], so only remove default-width.

[1] 7a705c7959
2024-06-23 22:34:13 -03:00
Martin
58450f8f22 Update Slovenian translation 2024-06-23 13:13:23 +00:00
Alexandre Franke
4fd70e94a0 progress-info: harmonize spelling 2024-06-22 09:54:06 +00:00
Khalid Abu Shawarib
054ad3f049 asan: Add adw_init to suppressed functions 2024-06-21 14:21:34 +00:00
Khalid Abu Shawarib
a926372a7c gtk/placessidebar: Fix leaks
The "start-icon" property is already set with the property bind between
the bookmark and the row in the same function, and the GIcon reference
generated by calling `nautilus_bookmark_get_symbolic_icon()` is not
dropped.
2024-06-21 10:08:02 +00:00
Khalid Abu Shawarib
dcbd17359b gtk/placessidebar: Connect row object to popover map/unmap
nautilus-bookmark-list is sending changed signals in the same callstack
where the rename button is pressed, which is before the popover is
unmapped. And thus is causing the sidebar to rebuild the rows, destroying
the row before the unmap callback is called on the row.

Change the binding of the signal to the lifetime of the row instead of
binding it to the sidebar.

This fixes a crash when renaming bookmarks.
2024-06-21 10:08:02 +00:00
Khalid Abu Shawarib
8ba056abd1 gtk/placessidebar: Disconnect bookmarks signal after the sidebar is gone
This was a small oversight in [1] that causes crashes when trying to
drag and drop new bookmarks after opening a new window and closing
the old one.

[1] 26480b7017
2024-06-21 10:08:02 +00:00
Милош Поповић
d196abfe47 Update Serbian translation 2024-06-19 22:47:07 +00:00
António Fernandes
744d8599ed placessidebar: Open location directly
Instead of sending a signal for NautilusWindow to open the requested
location, send it directly. This will make it easy to reuse the sidebar
in the upcoming FileChooser dialog.

Part of https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3431
2024-06-15 15:36:31 +00:00
António Fernandes
5e8615e36d window: Erase wrong comment and workaround
The commit[0] which introduced this comment aimed to fix a bug which was
caused by double-clicking a folder on the view.[1]

This change was ineffective as per later comments on that bug report,
which is not surprising because the change was wrong: this code path was
(and still is) used only for changing locations using the pathbar and
sidebar. The bug happening with double-click on the view is uses another
code path, in mime-actions.c, which has later been patched[2].

So, let's remove the wrong FIXME comment and effectively revert [0],
which, as expected, doesn't introduce any bug in my testing.

[0] 49c03251ee
[1] https://bugzilla.gnome.org/show_bug.cgi?id=756499
[2] 755c771058
2024-06-15 15:36:31 +00:00
António Fernandes
a1e5c2b494 placessidebar: Reuse NautilusOpenFlags
This enum serves the same purpose. Translating between them is useless.

This prepares to drop the ::open-location signal.
2024-06-15 15:36:31 +00:00
António Fernandes
402ae03e0b placessidebar: Show error messages directly
Instead of relying on NautilusWindow. This will allow the sidebar to
show error messages when reused in the upcoming FileChooser dialog.

Part of https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3431
2024-06-15 15:36:31 +00:00
António Fernandes
d4a066da31 placessidebar: Get location directly from slot
Instead of having NautilusWindow relay the change, have the sidebar
talking directly with the window slot.

This prepares the sidebar to be reused in the upcoming FileChooser
dialog which is not going to be a NautilusWindow.

Part of https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3431
2024-06-15 15:36:31 +00:00
António Fernandes
ccf81c1b0d placessidebar: Drop ::show-starred-location
The public GtkPlacesSidebar in GTK3 couldn't make assumptions about a
place that was private to nautilus, so it would emit a specific signal
instead of regular ::open-location.

Now that it's all nautilus-internal, there is no reason not to use the
regular ::open-location signal. This way NautilusWindow doesn't have
to handle the special signal, which makes the upcoming FileChooser
implementation simpler.

Part of https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3431
2024-06-15 15:36:31 +00:00
António Fernandes
24d4307b61 placessidebar: Drop now-unused row type 2024-06-15 15:36:31 +00:00
António Fernandes
6636a22ffd placessidebar: Update enum symbol
Around the 3.0 release, the sidebar featured section headers and there
was a section whose header was "Computer".

We still carry that name in an enum symbol. It makes no sense nowadays
if you don't know the history. So, let's rename it to the name by
which it is informally called in current design mockups.
2024-06-15 15:36:31 +00:00
António Fernandes
5c2f55663a placessidebar: Reorganize places
The sidebar has got too many unremovable places at the top, which leave
little space for other potentially more relevant places before they
overflow out of view by scrolling.

A set of special user directories (DOCUMENTS, MUSIC, PICTURES, VIDEOS,
and DOWNLOAD) are found near the top, and cannot be removed, even if
people don't need quick access to all of them.

Bookmarks (i.e. custom locations added to the sidebar by the users) are
always at the bottom, which means they are the first to go out of view.
This is made worse by internal storage units being back to the sidebar.

To fix these issues, let's reorganize the places:

  - reduce the number of default sidebar locations by turning the
special user directories into regular bookmarks[0] that people can
reorder or remove from the sidebar.
  - show bookmarks before mounts; this allows special user locations to
remain close to their previous position, keep important bookmarks from
being scrolled out of view, and instead overflow excess mounts/devices.

While at it, reposition the Home to the first place, as it is the first
location shown when launching the app.

Part of: https://gitlab.gnome.org/GNOME/nautilus/-/issues/3012

[0] This assumes a default set of bookmarks including these directories
    is created by xdg-user-dirs-update-gtk on first login. Ensuring it
    is installed, running on startup, and working correctly is a system
    integration and quality assurance task for vendors/administrators.
2024-06-15 15:36:31 +00:00
António Fernandes
f5cacef579 window-slot: Stop ignoring NOT_SUPPORTED errors
We use some application-internal URIs without a corresponging GVFS
backend. If we let NautilusVfsFile handle the file info requests when
loading these locations, we get a G_IO_ERROR_NOT_SUPPORTED error, as
should be expected.

Nowadays, none of our internal URI schemes go through NautilusVfsFile:

  * `x-nautilus-search://*/` URIs lead to the creation of instances of
    the `NautilusSearchDirectoryFile` subclass;
  * `x-network-view:///` and `starred:/// lead to the creation of
    instances of the `NautilusInternalPlaceFile` subclass.

This means that `call_when_ready()` requests for these files do not ask
for a GVFS to handle unsupported URI schemes. So, we no longer get a
G_IO_NOT_SUPPORTED error when getting info on these locations.

As such, let's no longer ignore such errors.
2024-06-15 15:36:31 +00:00
António Fernandes
4db38919c2 placessidebar: Drop OTHER_LOCATIONS leftovers 2024-06-15 15:36:31 +00:00
António Fernandes
f7bb6975a5 placessidebar: Sort internal volumes last
These used to be hidden in Other Locations view. Now that they live in
the sidebar, let's sort them last, in order to avoid pushing external
volumes (e.g. plugged-in devices or connected remotes) down the list
and possibly out of view.

Let's keep external volumes above the recently returned internal ones.

Part of: https://gitlab.gnome.org/GNOME/nautilus/-/issues/3012
2024-06-15 15:36:31 +00:00
António Fernandes
2e4151ca3d placessidebar: Drop CONNECT_TO_SERVER row type
It's unused.
2024-06-15 15:36:31 +00:00
António Fernandes
f0d5b36a6a placessidebar: Don't offer to add mounts to bookmarks
Previously, the only way to "save" a remove server connection was
bookmarking it. So, we have an action in the sidebar just for that.

Now that we have a new Network view making previous connections easy
to find, there is no need to promote this action from the sidebar.

Furthermore, adding mounts to bookmarks is problematic because:

  - for local mounts it makes no sense and results in errors when
    trying to use a bookmark to an unmounted partition[0]
  - for remote mounts, it results in a duplicated sidebar entry[1].

Drop this action from the sidebar menu, not to encourage using it.

[0] https://gitlab.gnome.org/GNOME/nautilus/-/issues/858
[1] https://gitlab.gnome.org/GNOME/nautilus/-/issues/607
2024-06-15 15:36:31 +00:00
António Fernandes
588062afbc placessidebar: Remove duplicate folder icons code
This has been copied from nautilus to gtk and then back, so now we have
the same code twice. Let's clean this up.
2024-06-15 15:36:31 +00:00
António Fernandes
c5a3dad7a4 internal-place-file: Skip ALREADY_MOUNTED error
That error is as good as a successful mount for all we care about.

Let's neither send a warning nor fail to open Network view in that case.
2024-06-15 15:09:26 +00:00
Scrambled 777
21f2c91d69 Update Hindi translation 2024-06-15 12:50:27 +00:00
António Fernandes
3e8b382fce toolbar: Handle showing current location menu
This makes NautilusPathBar effectively private to NautilusToolbar,
like NautilusLocationEntry already is.
2024-06-15 10:56:27 +00:00
António Fernandes
874150b017 toolbar: Handle NautilusPathBar::open-location
There is no need for NautilusWindow to handle it. This way the
upcoming FileChooser window will not have to duplicate the code.

Part of: https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3431
2024-06-15 10:56:27 +00:00
António Fernandes
7360be440a toolbar: Handle prompt for special locations
The last remaining direct interaction between NautilusWindow and the
location entry are the location prompt actions.

Let's do everything in the toolbar instead, to make it easy to reuse
in the upcoming FileChooser dialog. Now the location entry is entirely
private to the toolbar.

Part of: https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3431
2024-06-15 10:56:27 +00:00
António Fernandes
c908c94108 toolbar: Handle location entry signals
There is no need for the window itself to do it. This will ensure
they are handled the same way in the upcoming FileChooser window.

Also fix signal parameter type to reflect the assumed object type.

Part of: https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3431
2024-06-15 10:56:27 +00:00
António Fernandes
911e366ca9 toolbar: Handle modal-like entry focus
When the location entry is shown, we remember the previous focus widget
to restore the focus back into it when the location entry is hidden.

This only happens before or after asking the toolbar to show/hide it,
so, we can instead have the toolbar handle this behavior itself.

Replace the setter with explicit open and close methods which handle
the focus. These can also be conveniently used as callbacks.

This way, when the toolbar gets reused in the upcoming FileChooser
window, this behavior will also exist there.

Part of: https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3431
2024-06-15 10:56:27 +00:00
António Fernandes
a58739f30d toolbar: Drop unused :show-location-entry RW property
Removing this make the refactoring of the next commit simpler.
2024-06-15 10:56:27 +00:00
António Fernandes
85c44aa42b toolbar: Update internals on location change
Instead of the window, it makes more sense to have the toolbar update
its own children. The role of the window should be only to connect
the active slot with the toolbar, then let them talk among themselves.

This makes it easier to reuse the toolbar in the upcoming FileChooser.

(While touching nautilus_toolbar_set_window_slot_real(), also remove
unused variable.)

Part of: https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3431
2024-06-15 10:56:27 +00:00
António Fernandes
02c67b8879 toolbar: Don't override .constructed
We don't have any construct properties to wait for, so there is no
reason to split the code between init() and constructed().
2024-06-15 10:56:27 +00:00
Anuraag Reddy Patllollu
23e41c5aef batch-rename-dialog: Replace '/' with '_' for metadata
Fixes #1749
2024-06-12 21:14:25 -04:00
Anuraag Reddy Patllollu
e419ffb7bd batch-rename-dialog: Fix missing season-number and episode-number metadata tags 2024-06-12 10:43:15 -04:00
António Fernandes
25f445f4d7 tests: Use localsearch3 test-sandbox
Test sandbox program has been moved from the `TinySPARQL` (previously
`tracker`) project to `localsearch` (previously `tracker-miners`).

067e855151
abc100fa6b
2024-06-12 10:46:19 +00:00
António Fernandes
972d717816 flatpak: Request access to more tracker graphs
Batch rename dialog doesn't offer metadata while running as flatpak.

This is because we do not request access to the graphs where that
metadata lives.

Fixes https://gitlab.gnome.org/GNOME/nautilus/-/issues/1819
2024-06-12 10:46:19 +00:00
António Fernandes
0e6e3946eb general: React to tracker projects rename
Tracker SPARQL is now TinySPARQL. Tracker Miners is now LocalSearch.

The old DBus and library APIs still work so there is no rush there.

But the executables and git repositories need to be updated now.

https://discourse.gnome.org/t/renaming-tracker-git-and-tracker-sparql-git-and-changing-default-branch/21461
2024-06-12 10:46:19 +00:00
António Fernandes
746f9c4247 internal-place-file: Really don't access self pointer after destruction
We've avoided the trivial case of cancellation on destruction, as part of 
commit 16b81477b3 

But there may be cases where the async task returns an error even before it's cancelled,
but the async callback is only called in a future iteration where the file is already 
destroyed. So, handle that case too and add a warning while at it.

(cherry picked from commit 7d80a9ad82)
2024-06-10 23:24:11 +00:00
António Fernandes
da4dd182a1 window-slot: Import go up and down actions
To make them reusable in the upcoming FileChooser window.

Part of https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3413
2024-06-10 10:17:12 +00:00
António Fernandes
2d6f4b8280 window-slot: Import back/forward actions
This will allow them to be used by the upcoming FileChooser window.

Part of https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3413
2024-06-10 10:17:12 +00:00
António Fernandes
13ae2e6fd3 files-view: Don't add accels to application
Same change as for NautilusWindowSlot. Refer to parent commit.

Part of: https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3411
2024-06-10 10:17:12 +00:00
António Fernandes
9dbe8569c3 window-slot: Don't add accels to application
We've been using GtkApplication, through a NautilusApplication method,
to set accelerators (i.e., global shortctus which trigger regardless
of where the focus is on the application window).

This will not work if NautilusWindowSlot is added to a window which
is nor a GtkApplicationWindow instance, as will be the case for the
upcoming FileChooser window.

Let's instead add them to a shortcut controller in the slow, but with
a "managed" scope which allows it to trigger even if the focus is not
on the slot.

Part of: https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3411
2024-06-10 10:17:12 +00:00
António Fernandes
3f17995dbc window: Limit managed shortcuts to :child
In order for some window-level shortcuts to trigger on a FileChooser
dialog, which do not belong to NautilusApplication, we need to stop
using gtk_application_set_accels_for_action() and set the shortcuts
directly on widgets.

While at it, their GtkShortcutScope is to be changed from `GLOBAL`
to `MANAGED`. This gives us an opportunity to fully control their
scope and, thus, prevent them from being triggered while, e.g., an
AdwDialog is up.

Related to https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3411
2024-06-10 10:17:12 +00:00
Khalid Abu Shawarib
9edcd430c3 file-operations: Fix incorrect operation
The ternary operator has lower precedence than bitwise or and thus had
made the expression a tautology.
2024-06-08 23:25:37 +00:00
Khalid Abu Shawarib
78e22d0448 window-slot: Drop superflous code
These lines do nothing as explained in the previous commit.
2024-06-08 23:25:37 +00:00
Peter Eisenmann
e19923adf8 window-slot: Inline location loading helper function
The bigger code block of activating a pending file only applies for one
caller, so the helper function did not deduplicate any code and really
only created more overhead, making the code harder to follow.

One significant side affect of this refactoring is that we don't pass
`self->pending_selection` by value to `nautilus_view_set_selection()`.
This resolves a crash in the case when `nautilus_view_set_location()`
will reach a code [1] that uses and frees `self->pending_selection`,
thus leaving the pointer passed by value for selection to become a
dangling pointer if it was pointing to `self->pending_selection`.

[1] d046bf4a8b/src/nautilus-files-view.c (L3896)

Fixes: https://gitlab.gnome.org/GNOME/nautilus/-/issues/3036
2024-06-08 23:25:37 +00:00
Khalid Abu Shawarib
c57c9f57ae files-view: Fix heap overflow
Fix a heap overflow by designating the data type as a buffer instead
of a string in the case of a template copy and check for the operation
type to perform copying correctly.
2024-06-08 23:25:37 +00:00
Martin
2288345ba2 Update Slovenian translation 2024-06-08 21:22:03 +00:00
Automeris naranja
88a941ff74 file-properties-change-permissions: Modernize the UI
Use AdwPreferencesPage, AdwPreferencesGroup and AdwComboRow. Also,
add mnemonics.
2024-06-08 18:08:43 +00:00
António Fernandes
d98967693e general: Stop importing nautilus-window.h where unnecessary 2024-06-05 11:50:10 +01:00
António Fernandes
33aedd51fd window-slot: Drop :window property
We need NautilusWindowSlot to be reusable in the FileChooser window.

This means it cannot assume its parent is a NautilusWindow.

For NautilusWindowSlot code, rely on gtk_widget_get_root().
For NautilusApplication we can assume a NautilusWindow ancestor.

Part of: https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3402
2024-06-05 11:50:10 +01:00
António Fernandes
00019651b6 window-slot: Clean up location loading error handling
We have a whole branch of dead code under the condition that a window
is not visible. This is dead code because, as of GTK4, the :visible
property is TRUE by default; but even before that, I doubt the window
wasn't presented already before this callback.

The logic on this conditional branch is ancient[0] and employs rather
drastic measures: destroy the window if it failed to load its initial
location. At a later point[1], a special case hase been added not to
destroy the window if there is no other nautilus window. It would open
Home instead, or, failing that, the filesystem root. But if both fail,
it would still resort to destroying the window.

Not only is destroying the window unecessary, the special case of a
single application window assumes NautilusWindowSlot can only exist
inside a NautilusWindow (belonging to NautilusApplication). This is
going to be a problem for the FileChooser window, which will not be
a NautilusWindow, not belong to the NautilusApplication, but still
run in the same process.

Let's drop the dead branch. But salvage the handling of rare cases
where $HOME fails to load for some reason.

Part of https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3402

[0] commit 4ce7b8ead3
[1] commit 06f5c77133
2024-06-05 11:50:10 +01:00
António Fernandes
cc9374e87d files-view: Don't assume NautilusWindow ancestor
We don't need to, for a matter of fact. `gtk_widget_get_root()` is
just as effective and is going to make it easier to reuse in the
upcoming FileChoser window.

Part of: https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3402
2024-06-05 11:50:10 +01:00
António Fernandes
d1742d078d previewer: Manage window handles internally
We've been expecting NautilusFilesView to pass a window handle to
nautilus_previewer_call_show_file(), requiring it to call async
methods from NautilusWindow to get them.

There are a few problems with this approach:

  1. It's a layer violation for the view to call into the window.
     Not only is this conceptually wrong, it's keeping us from
     reusing the view in other windows which are not NautilusWindow
     instances, like as the upcoming FileChooser window.
  2. It's leaking details of the NautilusPreviewer2 D-Bus API into
     NautilusFilesView and NautilusWindow, namely the expected format
     of the window handle.
  3. Even though this format is a de-facto standard nowadays, we are
     not using it for anything else, so there is no value in keeping
     it in NautilusWindow API.
  4. Even if we start using it for other purposes, there it nothing
     specific to NautilusWindow in how to generate a window handle;
     it's the same process for any toplevel surface.
  5. Tying the window handle's validity to the lifetime of the
     NautilusWindow instance means we keep it exported even if no
     longer used by the previewer, and in theory we would use the
     same handle for multiple peers.

So, have NautilusFilesView pass a generic GtkRoot pointer instead
and handle the exporting and unexporting lifetime of window handles
in the previewer glue code instead.

The NautilusWindow API, no unused, is also removed. If the need arises
in the future to reuse this export/unexport logic, we can always move
it into ui-utilities.c or something like that.

Part of: https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3402
2024-06-05 11:50:10 +01:00
António Fernandes
0c5d28bcd6 previewer: Drop ununsed XID parameter
It's been supperceeded by the window handle string, which, for X11
windows, is a concatenation of "x11:" and the XID.
2024-06-05 11:50:10 +01:00
António Fernandes
9698bcaccf history-controls: Don't assume NautilusWindow
Middle click on back/forward buttons opens the previous/next location
in a new tab.

We want to reuse the history controls for FileChooser window, but it
will neither have tabs nor be a NautilusWindow at all.

So, make this feature conditional on the root widget being an instance
of NautilusWindow.

Part of: https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3402
2024-06-05 11:50:10 +01:00
António Fernandes
c036a1178c pathbar: Don't call NautilusWindow nor NautilusApplication
We want to make the pathbar reusable for the FileChooser window,
which is neither going to be a NautilusWindow nor part of the
NautilusApplication instance.

But we don't really need anything from the application or window
classes which cannot be done directly with the slot class. And
the slot is going to be reused in FileChooser too.

In order to have access to the slot, expect the pathbar owner
(currently only NautilusToolbar) to set it as a property. The
FileChooser is going to be able to set the slot itself as well.

Part of: https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3402
2024-06-05 11:50:10 +01:00
António Fernandes
a501907f70 toolbar: Have PathBar and LocationEntry in UI template
We have "container" boxes in the .ui file to which we add the
actual widgets in code.

I believe this was done back when we desired these UI files to
be editable in Glade, which didn't know our custom widgets.

But we no longer care about that, so let's do everything in the
UI template. This will make the next commit simpler by enabling
bindings to be declared in the UI template as well.
2024-06-05 11:50:10 +01:00
António Fernandes
c3d4cbdd0e files-view: Stop getting active slot from the window
We can ask the slot directly whether it is the active one.

This removes one NautilusWindow method call from inner widgets,
which is a layer violation and gets in the way of reusing them
for the upcoming FileChooser window.

Part of: https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3402
2024-06-05 11:50:10 +01:00
António Fernandes
095f699da1 window-slot: Import the stop and reload actions
These actions have been living in the window, but they are actually
implemented by the slot, and conceptually they are slot actions.

Import them in preparation to use them also in the FileChooser window.

Part of https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3413
2024-06-05 11:50:10 +01:00
António Fernandes
13e0bba7ff window-slot: Don't manually sync allow-stop
We do so in two cases: active slot change, or :allow-stop change.

Have the window handle both cases: it is the one who changes active
slot already, and listening to NautilusWindowSlot:allow-stop changes
is trivial.

This resolves a layer violation and is one fewer NautilusWindow
method being called by NautilusWindowSlot, preparing the later for
reuse in the FileChooser portal dialog window.

Part of https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3402
2024-06-05 11:50:10 +01:00
António Fernandes
0f52276179 window: Drop nautilus_window_reset_menus()
This is used by NautilusFilesView, which is a layer violation. But
it's also useless, because the only thing it does is sync the
start/reload actions, and that's already done by the slot calling
nautilus_window_sync_allow_stop() anyway in the same situations
(i.e. when view starts or ends loading).

Drop it, to prepare the view to be reusable in FileChooser dialogs.

Part of: https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3402
2024-06-05 11:50:10 +01:00
António Fernandes
3efa7fa6e8 window-slot: Stop sync'ing location widgets
Like the previous commit, this resolves a layer violation and paves the
way for NautilusWindowSlot to be reusable in future FileChooser dialog,
by not using NautilusWindow methods.

On this particular case, we have been updating window widgets which
depend of current location whenever the active lot changes or the the
location of the active slot changes.

On the first case, the window is in charge of setting the active slot,
and in the second case it is already listening to the locatio change.
In both cases, on_location_changed() in nautilus-window.c is called.

So, sync the location widgets from on_location_changed() and stop
exposing it in the header.

Part of https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3402
2024-06-05 11:50:10 +01:00
António Fernandes
22d214e818 window: Bind title to expression
We rely on the slots calling sync_title() on the window, which is
wasteful (if the slot is not active), fragile, and a layer violation.

We already have properties for all of these pieces, so let's use
expressions. This also helps with preparation for FileChooser window,
as we need NautilusWindowSlot to stop calling NautilusWindow method,
as part of https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3402
2024-06-05 11:50:10 +01:00
António Fernandes
30194a1fdc window-slot: Stop calling nautilus_window_get_active_slot()
We call it to assert the slot being set as inactive is (still) active.

Not only is this counter intuitive, but it also relies on order of
events in nautilus_window_set_active_slot(). Therefore, the assertion
is useless because we already rely on NautilusWindow doing it right.

Instead, make the caller of nautilus_window_slot_set_active() (i.e. the
window) responsible for ensuring consistency. To ensure it is not set
by any other means, make the property read-only.

One less NautilusWindow method being called by NautilusWindowSlot, as
part of https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3402
2024-06-05 11:50:10 +01:00
António Fernandes
bb9231b6a0 window-slot: Don't access the tab view
The slot accesses the window's tab view to change the selected tab.

This is a layer violation, which is both completely unnecessary and
is getting in the way of reusing the slot widget in a tabs-less
window (such as the upcoming FileChooser window).

So, have NautilusWindow manage the selected tab directly. This is
one less NautilusWindow method being called by NautilusWindowSlot.

Part of https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3402
2024-06-05 11:50:09 +01:00
António Fernandes
6bd4e06faa window-slot: Rework and document grab_focus() call
We'v been relying on a gtk_widget_grab_focus() call to avoid broken
focus states after view (re)loading.

But there is one particular case where we must not do it: if the
popover menu is shown. This is a rare situation which is currently
only possible to trigger by pressing [Spacebar] while the "Show
Hidden Files" menu item has focus.

But this currently relies on the slot calling a NautilusWindow method,
which is a layer violation which is getting in the way of reusing
NautilusWindowSlot in the FileChooser window[4].

Let's use generic GTK/GDK API to assess wether the menu is shown,
and drop the NautilusWindow method.

Originally I've just removed the grab_focus() call, but came to
realize it was still needed, so let's also document my findings here.

Part of: https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3402
2024-06-05 11:50:09 +01:00
António Fernandes
c960cfa439 files-view: Make logic order look intentional
The selection check is done after the emission of delayed singals which
may change it, as per commit 09f4546d50.

However, nowadays we have a habit of combining declaration and
assingment into a single statement. So, during future hacking, one
might be tempted to move the assignments into the declaration lines,
effectively reverting that commit.

Let's keep declaration and assingment together but after that call,
and also add a comment to make it clear this order is intentional.
2024-06-04 23:09:54 +01:00
António Fernandes
e5e53ea2c9 window: Don't leak file 2024-06-04 22:29:20 +01:00
Martin
10d823295a Update Slovenian translation 2024-06-04 07:33:02 +00:00
Khalid Abu Shawarib
d4bc511f69 test/file-utilities-get-common-filename-prefix: Add tests
Adds tests for `nautilus_get_common_filename_prefix()`
2024-06-04 01:59:56 +00:00
Khalid Abu Shawarib
89ae1730b9 test/file-utilities-get-common-filename-prefix: Increase test level
Embed the existing tests in a new category in preperation for
adding another one.
2024-06-04 01:59:56 +00:00
António Fernandes
fceb9ee923 window: Drop actual wayland export handle
We've not been dropping handles properly, and we've been getting
warnings from gdk_wayland_toplevel_real_unexport_handle() as such.

This is because we are passing the "wayland:"-prefixed string, but
the actual wayland export handle is only the part after the colon.

Fixes a regression from commit ad865de618


(cherry picked from commit 4fc8812040)
2024-06-04 01:43:05 +00:00
José Guilherme
fa7b77fe6c window: Add Star Folder context menu entries
Add starring and unstarring actions to the pathbar context menu.

In order to disallow starring the home directory, add a new function to
the tag manager, which checks if a given directory can be starred.
2024-06-04 01:42:36 +00:00
piegames
626a04509c Floating-bar: Make background slightly darker
This improves the contrast against the background, and is consistent
with the background color of the path bar.
2024-06-03 20:28:32 +00:00
António Fernandes
16b81477b3 internal-place-file: Don't access self pointer after destruction
If the file is destroyed before the mount operation is completed,
we cancel the mount operation.

However, due to the nature of GAsyncResult, the callback is still
called in a future iteration of the main loop, when the file is
long gone. But since it's passed as callback data, we try to
cast it, with predictably bad results.

Access the file pointer only if the operation hasn't been cancelled.
2024-06-02 17:18:55 +01:00
António Fernandes
12980ee1bd files-view: Update actions immediately on selection change
In the network view, if the row is not selected, clicking the unmount
button does nothing. Indeed, the action is still disabled, despite an
elligible item being selected already.

This happens because the actions state is updated on idle along with
the context menus. This is reasonable as the context menus update can
be expensive.

However, not updating actions state imimediately is unexpected, so
let's immediately update them when selection changes.
2024-06-02 15:39:09 +00:00
António Fernandes
e4deb16def files-view: Disable a few more action on network view
The Properties dialog is useless unless locations are mounted.

Also, disable a few current location menu actions.
2024-06-02 15:39:09 +00:00
António Fernandes
37634b960b files-view: Add network view actions 2024-06-02 15:39:09 +00:00
António Fernandes
fcbfcd4c5d files-view: Omit some menu sections on Network View
These actions do not make sense on the virtual files of that view.
2024-06-02 15:39:09 +00:00
António Fernandes
6d47c4c1f3 network-view: Disable background context menu
It's useless here.
2024-06-02 15:39:09 +00:00
António Fernandes
0ff13a90f0 files-view: Add network view empty state 2024-06-02 15:39:09 +00:00
António Fernandes
3494cd79df network-cell: Show spinner while mounting/unmounting 2024-06-02 15:39:09 +00:00
António Fernandes
c674046e29 files-view: Prevent use-after-free with mount and stop
Unmount and eject are already doing this since commit 80dd8fb8ff

Let's do the same for mount and stop, and use g_autoptr() to emphasize
the callback taking ownership of the reference passed to the method.
2024-06-02 15:39:09 +00:00
António Fernandes
da79c2f3bf files-view: Update file mount info when mounted
Otherwise, nautilus_file_can_unmount() will still return FALSE for
a file which is already mounted, until the can-unmount attribute
is updated asynchronously by the file monitor.

This is needed for the next commit to be able to check whether
unmount is possible as soon as the mount operation completes.
2024-06-02 15:39:09 +00:00
António Fernandes
7e6af9d61d general: Introduce Network place
And request network view for network view directory.

Remember whether the previous view was grid or list, to preserve
per-window settings.
2024-06-02 15:39:09 +00:00
António Fernandes
d1437e9fd6 network-view: Introduce new view and cells
This is the replacement for the Other Locations.

See https://gitlab.gnome.org/GNOME/nautilus/-/issues/2785
2024-06-02 15:39:09 +00:00
António Fernandes
41b3bed264 pathbar: Add support for custom network view scheme 2024-06-02 15:39:09 +00:00
António Fernandes
a157d6d07f file: Enhance mountables and shortcuts support
We have barely been exposing to these file types since the Computer and
Network places were replaced by Other Locations.

Now that NautilusNetworkDirectory brings them back into use, we need
to account for their special status.

Both mountables and shortcuts to folders open in view, acknowledge it.
And use mountable target URI (if available) as its activation URI.
2024-06-02 15:39:09 +00:00
António Fernandes
e845387f80 view-model: Provide section sorter setter 2024-06-02 15:39:09 +00:00
António Fernandes
8ce91a54b6 recent-servers: Load on idle
GBookmarkFile doesn't provide an asynchronous loading API. Given how
GtkPlacesView has always been doing it in the main thread, I suppose
it's fine.

Still, least it cause some delays, let's do it on idle.
2024-06-02 15:39:09 +00:00
António Fernandes
b72f62f65c recent-servers: Expose functions for UI
For the purpose of these functions, there is no need to set up a file
monitor, nor for the NautilusRecentServers object at all. But they are
provided here to keep context and reuse server_list_load().

The network address bar is going to be adding servers to the list,
while the upcoming network view is going to allow to remove them.
2024-06-02 15:39:09 +00:00
António Fernandes
0a78f8cee2 network-directory: Provide recent servers
These used to be displayed in a popover attached to the address entry
in the old Other Locations view.

The new design asks for them to be provided in-line with other items
in the view.

As such, reuse and expand the recent servers code to produce GFileInfo
models for the NautilusNetworkDirectory to create new virtual files
from. Unlike the virtual files aggregated sourced from the network:///
and computer:/// GVFS backends, these virtual NautilusFiles have no
corresponding GVFS presence, and are entirely "nautilus-land" files.

Big credit goes to the people who designed the nautilus directory and
file abstractions with this in mind.
2024-06-02 15:39:09 +00:00
António Fernandes
a0a54a72dd recent-servers: New recycled object 2024-06-02 15:39:09 +00:00
António Fernandes
2e9fca4510 gtkplacesview: Format with uncrustify 2024-06-02 15:39:09 +00:00
António Fernandes
c19589fc43 gtkplacesview: Drop non-reusable code 2024-06-02 15:39:09 +00:00
António Fernandes
1906daebd8 network-address-bar: Add clear button
It had already been added once[0], later replaced by the info icon[1].

[0] 9341f64c19
[1] bb8b459407
2024-06-02 15:39:09 +00:00
António Fernandes
1d9332c6c9 network-address-bar: Use new icon
As per mockups.

Part of: https://gitlab.gnome.org/GNOME/nautilus/-/issues/2785
2024-06-02 15:39:09 +00:00
António Fernandes
62c4a979ba network-address-bar: Recycle widgetry (step 2/2)
The new design for Network view uses an address entry bar which is
similar to the one from Other Locations view. Instead of reinventing
the wheel, let's salvage some code.

In addition to formatting the code to nautilus style, this also makes
a couple of visual changes to match the design requests.

https://gitlab.gnome.org/GNOME/nautilus/-/issues/2785
2024-06-02 15:39:09 +00:00
António Fernandes
2e59a031c1 network-address-bar: Recycle widgetry (step 1/2)
Rename file before applying changes to it, for git to preserve its
history. Otherwise it will look like the XML is new.
2024-06-02 15:39:09 +00:00
António Fernandes
7c12611bd0 gtkplacesview: Remove from build
Now that NautilusPlacesView is gone, we don't use this anymore.

But there is quite a bit of recycleable code here. So, let's take this
out of the build pipeline in order to disassemble it freely.
2024-06-02 15:39:09 +00:00
António Fernandes
6997f3a5eb general: Remove Other Locations
It's going to be replaced with a new Network view.[0]

For now this removes only the direct support in nautilus code proper.
The code imported from GtkPlacesView is kept to be recycled for a new
purpose.

[0] https://gitlab.gnome.org/GNOME/nautilus/-/issues/2785
2024-06-02 15:39:09 +00:00
António Fernandes
b85d0773a4 gtkplacessidebar: Drop unused places and options
This used to be shared with GTK, and even public GTK API, before GTK 4.

Therefore, it has optional behaviors we don't use. Drop them.
2024-06-02 15:39:09 +00:00
Martin
cbee15bd21 Update Slovenian translation 2024-06-02 05:39:26 +00:00
Khalid Abu Shawarib
13f3ec9f35 proprties: Don't scale up the image
In [1], a frame and an overlay were introduced for the redesign of the
thumbnail editor so that the new edit and clear buttons will not be
entirely inside the image frame. This was inside a GtkStack with
another a image which caused it to be scaled since the stack enforces
size homogeneity by default. This is undesirable, so disable it.

[1] 1c70bab1f0

Fixes: https://gitlab.gnome.org/GNOME/nautilus/-/issues/3422#note_2128815
2024-06-01 14:03:54 +00:00
António Fernandes
41c0c1f624 internal-place-file: Mount network:/// on ready request
The whole application freezes the first time `x-network-view:///` is
visited during a session (or after `killall gvfsd-network`).

This happens because GDaemonFile makes sync DBus calls to mount the
`network:///` location when we call `g_file_monitor_directory()`[0],
which is done by the view when the ready callback is invoked.

In order to avoid this, ensure the `network:///` location is mounted
before invoking the ready callback for the `x-network-view:///` file.

(This achieves a result which is similar to accessing `network:///`
directly, or any other location which is slow to mount: the location
is not changed until after the mount succeeds. I don't think this is
good UX, but it's an entirely different problem which is not specific
to the Network view at all.)

[0] More context on https://gitlab.gnome.org/GNOME/gvfs/-/issues/455
2024-06-01 11:57:05 +00:00
António Fernandes
f0d250d0cc network-directory: Introduce new directory subclass
This aggregates files from two sources:

* network:// for discoverable network resources
* computer:// for remote mounts and volumes

For the second case, we need to filter out local mounts and volumes.
For the time being, this is implemented by relying on the the icon
names, until a new file attribute is provided by GVFS.
2024-06-01 11:57:05 +00:00
António Fernandes
7776f13c69 internal-place-file: Introduce new file subclass
Instead of special casing the NautilusFile for the starred:/// URI,
give it a proper display name as part of a new specialized subclass.

This is prepared to handle more cases, like the upcoming Network view.
2024-06-01 11:57:05 +00:00
António Fernandes
61032380f3 file: Document vtable
Ensure no virtual method is left undefined by subclasses.
2024-06-01 11:57:05 +00:00
António Fernandes
6d47fce9c9 file: Make get_where_string() non-polymorphic
Similarly to .get_date(), addressed by the previous commit, this has
been added for the sake of NautilusTrashFile[0] for it to say it lives:

   "on the desktop"

We have no desktop anymore. NautilusSearchDirectoryFile is not on
desktop nor in any view, and it doesn't have a parent, so it doesn't
need this either.

[0] commit d23bb1b5be
2024-06-01 11:57:05 +00:00
António Fernandes
ce35cd2441 file: Make get_date() method non-polymorphic
It was born as a virtual method with 2 implementations: NautilusVfsFile
and NautilusTrashFile: commit e82bab8c49

Nowadays only the NautilusVfsFile implements it anyway, so, rather than
leaving it undefined for other subclasses it's best to move the
implementation to the parent class and drop the vfunc.

An undefined virtual method obviously can cause problems. A crash
can be reproduced through FileManager1 D-Bus method ShowItemProperties
with the parameters (["x-nautilus-search://0/"],""). We are lucky this
probably never happens under regular usage.
2024-06-01 11:57:05 +00:00
António Fernandes
c7d515942b search-directory: Create own file
There is no reason for nautilus-directory.c to include the header for
a subclass just to implement a virtual method the subclass could have
implemented itself.

So, have NautilusSearchDirectory create NautilusSearchDirectoryFile
and stop including unneeded headers in directory.c.

Also do precondition checking in the method, not the implementation.

This sets a pattern for upcoming new NautilusFile subclasses.
2024-06-01 11:57:05 +00:00
António Fernandes
3c23786c8c file: Make directory a construct property
We always call nautilus_file_set_directory() right after creating the
object, and a file is not expected to live without a directory.

Therefore, it makes sense to require the directory to be passed upon
object construction.

This is not just about adopting idiomatic GObject patterns: it's
going to become useful later for new file subclasses who will need to
know something about their parent directory upon construction.
2024-06-01 11:57:05 +00:00
Jordi Mas i Hernandez
3153252095 Update Catalan translation 2024-05-31 22:12:16 +00:00
Pawan Chitrakar
4511a7ab9b Update Nepali translation
(cherry picked from commit ea10fe4a07)
2024-05-28 16:36:45 +00:00
Khalid Abu Shawarib
0aab4b8458 files-view: Don't always reload on global search
In [1], global search was excluded from skipping the reloading of
the view like normal search in order for the current content of the
view to not appear in the global search for a short time until the
results were loaded. This causes global search results to flicker
for every key stroke.

Instead, make the condition more specific so that it will not
affect loading between search queries.

[1] ce47e61372

Fixes: https://gitlab.gnome.org/GNOME/nautilus/-/issues/3403
2024-05-27 23:57:35 +00:00
António Fernandes
a9ca62f771 file: Don't rely on application-x-generic
`application-x-generic` is our preferred fallback themed icon. However,
it's  not present in the icon naming specification[0] and, as such, is
not included in the icon themes some downstreams adopt.

Instead of immediately resorting to the unthemed fallback texture, we
can give a second themed alternative which is likely available in any
icon theme: text-x-generic.

[0] https://specifications.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html

Fixes https://gitlab.gnome.org/GNOME/nautilus/-/issues/3268
2024-05-27 22:47:34 +00:00
Martin
56a9882610 Update Slovenian translation 2024-05-27 12:44:29 +00:00
Artur S0
6dd4f7ef9f Update Russian translation 2024-05-27 10:18:30 +00:00
Asier Sarasua Garmendia
bfde9badb5 Update Basque translation
(cherry picked from commit 52f4db5071)
2024-05-26 09:36:48 +00:00
Balázs Úr
5a7347867f Update Hungarian translation 2024-05-26 09:22:53 +00:00
António Fernandes
356570978c bookmark: Don't mark non-native bookmarks as broken
We want to use a warning icon to warn about broken bookmarks,
i.e., bookmarks whose pointed path is gone.

But for non-local files, this may just mean they are not currently
mounted or temporarily innaccessible, not necessarily broken.

So, apply the broken bookmark icon logic to native icons only.

Fixes https://gitlab.gnome.org/GNOME/nautilus/-/merge_requests/1430#note_2069827
2024-05-24 15:09:12 +00:00
António Fernandes
a011010567 bookmark: Simplify get_native_icon() and get_xdg_type()
The usage of goto's makes get_native_icon() unnecessarily complex and
error-prone.

Indeed, the goto's may be the reason why the commit[0] which introduced
the `nautilus_bookmark_get_xdg_type()` function as a replacement for
`nautilus_file_is_user_special_directory()` didn't remove the obsolete
checks `bookmark->file == NULL` and `xdg_type < G_USER_N_DIRECTORIES`.

Simplify and modernize `nautilus_bookmark_get_xdg_type()` as well, to
make it clear it the passed `GUserDirectory` value is always lower than
G_USER_N_DIRECTORIES, because it's the for loop condition.

[0] commit 1dcd2d816a
2024-05-24 15:09:12 +00:00
Corey Berla
7e427c0ba7 sidebar: Remove "enter-location" row
We don't use it, and likely never will again.
2024-05-24 15:09:12 +00:00
Corey Berla
26480b7017 sidebar: Replace gtkbookmarksmanager with nautilus-bookmark-list 2024-05-24 15:09:12 +00:00
Corey Berla
3aca4ce418 bookmark-list: Save file on name changed
Now that we allow changing the name at any time, save the file when
the name is updated, as that information ends up in the bookmarks file.
2024-05-24 15:09:12 +00:00
Corey Berla
4dd0e6aa57 bookmark: Expose nautilus_bookmark_set_name
In the following commits we will be dropping gtkbookmarkmanager and
using nautilus-bookmark/list instead.  In order to allow renaming
bookmarks we need access to set_name.
2024-05-24 15:09:12 +00:00
Corey Berla
3bdf93975a bookmark: Update custom_name on new name
We incorrectly only set custom_name on construction.
2024-05-24 15:09:12 +00:00
Corey Berla
ced25b64e3 bookmark: Stop notifying twice on set_name 2024-05-24 15:09:12 +00:00
Corey Berla
08ec5c4b45 bookmark-list: Remove legacy fallback bookmark file
The current location was added almost 12 years ago in commit ed90577118
("Use new GTK bookmarks location").
2024-05-24 15:09:12 +00:00
António Fernandes
1ff52d2e46 bookmark-list: Modernize old-new code
There is no need to use g_list_free_1() when we can achieve the same
result using g_list_delete_link() instead of g_list_remove_link().

There is also no need to free 1 link when it can be reinserted in
another position.

Also other style rearrangements, mixing declarations with code, etc.
2024-05-24 15:09:12 +00:00
António Fernandes
f92141abb8 bookmark-link: Don't leak link 2024-05-24 15:09:12 +00:00
Corey Berla
facd45d7c2 bookmark-list: Restore formerly unused methods
This partially reverts commit [1] and [2].

We didn't need these when the sidebar lived in
GTK, but now the sidebar has come back and we should prefer
our code over the gtkbookmarkmanager.

[1] 380124b5cf.
[2] e13b3e2fcd
2024-05-24 15:09:12 +00:00
Automeris naranja
f2b853ca5b properties-window: Don't show a blank space if extension_models_list_box is empty
If "Image/Audio/Video Properties" rows aren't present, a blank space
will unnecessarily be shown at the bottom of the properties window.
To fix this, hide the AdwPreferencesGroup that contains these rows.
2024-05-22 17:41:47 -03:00
Automeris naranja
d7b9b3722f properties-window: Fix indentation 2024-05-22 17:28:46 -03:00
Peter Eisenmann
df0878e3ce fd-holder: Don't try to iterate NULL hash table 2024-05-22 11:28:22 +01:00
Automeris naranja
cc6378b337 properties-window: Remove period from status page description
"Text generally shouldn’t end with a period. This applies
to headings, descriptions, and includes text that is
written as a complete sentence."

https://developer.gnome.org/hig/guidelines/writing-style.html#periods
2024-05-20 20:57:29 -03:00
Automeris naranja
eb285df21d properties-window: Remove the "title-lines" property from some rows
Some rows have title-lines=1, but it's unlikely that their
titles will get ellipsized, as they are fixed and predictable,
unlike their subtitles. So remove this property as it's
unnecessary in this case.
2024-05-20 16:10:03 -03:00
109 changed files with 16715 additions and 21742 deletions

View File

@ -29,7 +29,7 @@ git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/main
## Runtime dependencies
- [Bubblewrap](https://github.com/projectatomic/bubblewrap) installed. Used for security reasons.
- [Tracker (including tracker-miners)](https://gitlab.gnome.org/GNOME/tracker) properly set up and with all features enabled. Used for fast search and metadata extraction, starred files and batch renaming.
- [LocalSearch](https://gitlab.gnome.org/GNOME/localsearch) properly set up and with all features enabled. Used for fast search and metadata extraction, starred files and batch renaming.
## Discourse

View File

@ -29,8 +29,12 @@
"--talk-name=org.gnome.Settings",
"--talk-name=org.gnome.Console",
"--env=DCONF_USER_CONFIG_DIR=.config/dconf",
"--add-policy=Tracker3.dbus:org.freedesktop.Tracker3.Miner.Files=tracker:Audio",
"--add-policy=Tracker3.dbus:org.freedesktop.Tracker3.Miner.Files=tracker:Documents",
"--add-policy=Tracker3.dbus:org.freedesktop.Tracker3.Miner.Files=tracker:FileSystem",
"--add-policy=Tracker3.dbus:org.freedesktop.Tracker3.Miner.Files=tracker:Documents"
"--add-policy=Tracker3.dbus:org.freedesktop.Tracker3.Miner.Files=tracker:Pictures",
"--add-policy=Tracker3.dbus:org.freedesktop.Tracker3.Miner.Files=tracker:Music",
"--add-policy=Tracker3.dbus:org.freedesktop.Tracker3.Miner.Files=tracker:Video"
],
"modules": [
{
@ -67,11 +71,11 @@
]
},
{
"name": "tracker-miners",
"name": "localsearch",
"buildsystem": "meson",
"cleanup": [
"/etc",
"/libexec/tracker-3",
"/libexec/localsearch-3",
"/share/dbus-1/services/org.freedesktop.Tracker3.Miner.Extract.service",
"/share/dbus-1/services/org.freedesktop.Tracker3.Miner.Files.service",
"/share/dbus-1/services/org.freedesktop.Tracker3.Miner.Files.Control.service"
@ -90,8 +94,8 @@
"sources": [
{
"type": "git",
"url": "https://gitlab.gnome.org/GNOME/tracker-miners.git",
"branch": "master"
"url": "https://gitlab.gnome.org/GNOME/localsearch.git",
"branch": "main"
}
]
},

View File

@ -4,6 +4,7 @@ leak:libfontconfig.so.1
leak:libEGL_mesa.so.0
leak:libtracker-sparql-3.0.so.0
leak:gtk_init
leak:adw_init
leak:xdg_mime_init
leak:gtk_at_context_create
leak:libim-ibus.so

View File

@ -1,11 +1,12 @@
# Files needed for running Tracker inside the Flatpak sandbox, for systems
# which don't have a suitable version of Tracker in the host OS.
# Files needed for running LocalSearch (historically known as Tracker) inside
# the Flatpak sandbox, for systems which don't have a suitable version of
# LocalSearch in the host OS.
#
# We must export the .service files from the sandbox so they work on the
# session bus. This means the Tracker domain name must correspond with the
# session bus. This means the LocalSearch domain name must correspond with the
# application ID.
domain_ontologies_dir = get_option('datadir') / 'tracker3' / 'domain-ontologies'
domain_ontologies_dir = get_option('datadir') / 'localsearch3' / 'domain-ontologies'
dbus_services_dir = get_option('datadir') / 'dbus-1' / 'services'
tracker_domain_config = configuration_data()

View File

@ -1,7 +1,7 @@
[D-BUS Service]
Name=@application_id@.Tracker3.Miner.Extract
Exec=/app/libexec/tracker-extract-3 --domain-ontology @domain_rule@
Exec=/app/libexec/localsearch-extractor-3 --domain-ontology @domain_rule@
# Miner details needed for tracker-control
# Miner details needed for localsearch-control
Path=/org/freedesktop/Tracker3/Miner/Extract
NameSuffix=Miner.Files

View File

@ -1,7 +1,7 @@
[D-BUS Service]
Name=@application_id@.Tracker3.Miner.Files
Exec=/app/libexec/tracker-miner-fs-3 --domain-ontology @domain_rule@ --initial-sleep 0
Exec=/app/libexec/localsearch-3 --domain-ontology @domain_rule@ --initial-sleep 0
# Miner details needed for tracker-control
# Miner details needed for localsearch-control
Path=/org/freedesktop/Tracker3/Miner/Files
NameSuffix=Miner.Files

View File

@ -36,15 +36,18 @@ src/nautilus-file-undo-operations.c
src/nautilus-file-utilities.c
src/nautilus-filename-utilities.c
src/nautilus-global-preferences.c
src/nautilus-internal-place-file.c
src/nautilus-list-view.c
src/nautilus-location-banner.c
src/nautilus-location-entry.c
src/nautilus-main.c
src/nautilus-mime-actions.c
src/nautilus-network-address-bar.c
src/nautilus-network-cell.c
src/nautilus-network-view.c
src/nautilus-new-folder-dialog.c
src/nautilus-operations-ui-manager.c
src/nautilus-pathbar.c
src/nautilus-places-view.c
src/nautilus-preferences-window.c
src/nautilus-program-choosing.c
src/nautilus-progress-info.c
@ -80,6 +83,8 @@ src/resources/ui/nautilus-files-view.ui
src/resources/ui/nautilus-grid-cell.ui
src/resources/ui/nautilus-history-controls.ui
src/resources/ui/nautilus-name-cell.ui
src/resources/ui/nautilus-network-address-bar.ui
src/resources/ui/nautilus-network-cell.ui
src/resources/ui/nautilus-operations-ui-manager-request-passphrase.ui
src/resources/ui/nautilus-pathbar-context-menu.ui
src/resources/ui/nautilus-preferences-window.ui
@ -92,10 +97,5 @@ src/resources/ui/nautilus-toolbar.ui
src/resources/ui/nautilus-toolbar-view-menu.ui
src/resources/ui/nautilus-view-controls.ui
src/resources/ui/nautilus-window.ui
src/gtk/nautilusgtkplacesview.c
src/gtk/nautilusgtkplacesviewrow.c
src/gtk/nautilusgtkplacesviewrow.ui
src/gtk/nautilusgtkplacesview.ui
src/gtk/nautilusgtkbookmarksmanager.c
src/gtk/nautilusgtkplacessidebar.c
src/gtk/nautilusgtksidebarrow.ui

934
po/ca.po

File diff suppressed because it is too large Load Diff

200
po/eu.po
View File

@ -12,7 +12,7 @@
msgid ""
msgstr "Project-Id-Version: nautilus master\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/nautilus/issues\n"
"POT-Creation-Date: 2024-02-22 20:12+0000\n"
"POT-Creation-Date: 2024-04-04 12:02+0000\n"
"PO-Revision-Date: 2024-02-25 10:00+0100\n"
"Last-Translator: Asier Sarasua Garmendia <asiersarasua@ni.eus>\n"
"Language-Team: Basque <librezale@librezale.eus>\n"
@ -55,16 +55,16 @@ msgid ""
"can be extended with plugins and scripts."
msgstr "Nautilus aplikazioak fitxategi-kudeatzaile baten oinarrizko funtzioak eta askoz gehiago ditu. Zure fitxategiak eta karpetak bilatu eta kudeatu ditzake, bai lokalean baita sarean ere. Datuak euskarri aldagarrietatik irakurri eta idatzi ditzake, scriptak exekutatu eta aplikazioak abiarazi. Hiru ikuspegi ditu: ikonoen sareta, ikonoen zerrenda eta zuhaitzaren zerrenda. Bere gaitasunak hedatu daitezke pluginen eta scripten bidez."
#: data/org.gnome.Nautilus.metainfo.xml.in.in:52 src/nautilus-view.c:150
#: data/org.gnome.Nautilus.metainfo.xml.in.in:53 src/nautilus-view.c:150
msgid "Grid View"
msgstr "Sareta-ikuspegia"
#: data/org.gnome.Nautilus.metainfo.xml.in.in:56 src/nautilus-view.c:154
#: data/org.gnome.Nautilus.metainfo.xml.in.in:57 src/nautilus-view.c:154
#: src/nautilus-view.c:158
msgid "List View"
msgstr "Zerrenda-ikuspegia"
#: data/org.gnome.Nautilus.metainfo.xml.in.in:60 src/nautilus-query.c:542
#: data/org.gnome.Nautilus.metainfo.xml.in.in:61 src/nautilus-query.c:542
#: src/nautilus-search-directory-file.c:177
#: src/nautilus-search-directory-file.c:231
#: src/nautilus-search-directory-file.c:271
@ -72,7 +72,7 @@ msgstr "Zerrenda-ikuspegia"
msgid "Search"
msgstr "Bilatu"
#: data/org.gnome.Nautilus.metainfo.xml.in.in:64 src/nautilus-bookmark.c:106
#: data/org.gnome.Nautilus.metainfo.xml.in.in:65 src/nautilus-bookmark.c:106
#: src/nautilus-file.c:4238 src/nautilus-file-utilities.c:75
#: src/nautilus-pathbar.c:386 src/gtk/nautilusgtkplacesview.ui:158
#: src/gtk/nautilusgtkplacessidebar.c:1435
@ -970,7 +970,7 @@ msgid "The type of the file."
msgstr "Fitxategi mota."
#: src/nautilus-column-utilities.c:90
#: src/resources/ui/nautilus-properties-window.ui:602
#: src/resources/ui/nautilus-properties-window.ui:601
msgid "Modified"
msgstr "Aldatze-data"
@ -987,7 +987,7 @@ msgid "The detailed type of the file."
msgstr "Fitxategiaren mota xehea"
#: src/nautilus-column-utilities.c:106
#: src/resources/ui/nautilus-properties-window.ui:564
#: src/resources/ui/nautilus-properties-window.ui:563
msgid "Accessed"
msgstr "Atzitze-data"
@ -996,7 +996,7 @@ msgid "The date the file was accessed."
msgstr "Fitxategia atzitu zeneko data."
#: src/nautilus-column-utilities.c:115
#: src/resources/ui/nautilus-properties-window.ui:640
#: src/resources/ui/nautilus-properties-window.ui:639
msgid "Created"
msgstr "Sortze-data"
@ -1040,7 +1040,7 @@ msgid "The date the file was accessed by the user."
msgstr "Erabiltzaileak fitxategia atzitu zueneko data."
#: src/nautilus-column-utilities.c:159 src/nautilus-properties-window.c:741
#: src/nautilus-star-cell.c:73
#: src/nautilus-star-cell.c:66
msgid "Star"
msgstr "Izarra"
@ -1817,7 +1817,7 @@ msgid "Deleting Files"
msgstr "Fitxategiak ezabatzen"
#. Translators: %s is a file name formatted for display
#: src/nautilus-file-operations.c:2331 src/nautilus-files-view.c:6837
#: src/nautilus-file-operations.c:2331 src/nautilus-files-view.c:6874
#: src/gtk/nautilusgtkplacessidebar.c:2689
#: src/gtk/nautilusgtkplacessidebar.c:2718
#, c-format
@ -1844,7 +1844,7 @@ msgid "Do _not Empty Trash"
msgstr "_Ez hustu zakarrontzia"
#. Translators: %s is a file name formatted for display
#: src/nautilus-file-operations.c:2655 src/nautilus-files-view.c:6785
#: src/nautilus-file-operations.c:2655 src/nautilus-files-view.c:6822
#: src/gtk/nautilusgtkplacessidebar.c:2049
#, c-format
msgid "Unable to access “%s”"
@ -2393,39 +2393,39 @@ msgstr[1] "%'d fitxategi “%s”(e)n konprimatuta"
msgid "Compressing Files"
msgstr "Fitxategiak konprimatzen"
#: src/nautilus-files-view.c:392
#: src/nautilus-files-view.c:390
msgid "Searching…"
msgstr "Bilatzen…"
#: src/nautilus-files-view.c:392 src/nautilus-window-slot.c:911
#: src/nautilus-files-view.c:390 src/nautilus-window-slot.c:911
msgid "Loading…"
msgstr "Kargatzen…"
#: src/nautilus-files-view.c:1874
#: src/nautilus-files-view.c:1872
msgid "Examples: "
msgstr "Adibideak: "
#: src/nautilus-files-view.c:2931
#: src/nautilus-files-view.c:2929
msgid "Could not paste files"
msgstr "Ezin izan dira fitxategiak itsatsi"
#: src/nautilus-files-view.c:2932
#: src/nautilus-files-view.c:2930
msgid "Permissions do not allow pasting files in this directory"
msgstr "Baimenek ez dute uzten direktorio honetan fitxategiak itsasten"
#: src/nautilus-files-view.c:3575 src/nautilus-files-view.c:3622
#: src/nautilus-files-view.c:3583 src/nautilus-files-view.c:3630
#, c-format
msgid "“%s” selected"
msgstr "“%s” hautatuta"
#: src/nautilus-files-view.c:3579
#: src/nautilus-files-view.c:3587
#, c-format
msgid "%'d folder selected"
msgid_plural "%'d folders selected"
msgstr[0] "Karpeta %'d hautatuta"
msgstr[1] "%'d karpeta hautatuta"
#: src/nautilus-files-view.c:3593
#: src/nautilus-files-view.c:3601
#, c-format
msgid "(containing %'d item)"
msgid_plural "(containing %'d items)"
@ -2433,14 +2433,14 @@ msgstr[0] "(elementu %'d du)"
msgstr[1] "(%'d elementu ditu)"
#. translators: this is preceded with a string of form 'N folders' (N more than 1)
#: src/nautilus-files-view.c:3608
#: src/nautilus-files-view.c:3616
#, c-format
msgid "(containing a total of %'d item)"
msgid_plural "(containing a total of %'d items)"
msgstr[0] "(guztira elementu %'d du)"
msgstr[1] "(guztira %'d elementu ditu)"
#: src/nautilus-files-view.c:3627
#: src/nautilus-files-view.c:3635
#, c-format
msgid "%'d item selected"
msgid_plural "%'d items selected"
@ -2448,7 +2448,7 @@ msgstr[0] "Eementu %'d hautatuta"
msgstr[1] "%'d elementu hautatuta"
#. Folders selected also, use "other" terminology
#: src/nautilus-files-view.c:3636
#: src/nautilus-files-view.c:3644
#, c-format
msgid "%'d other item selected"
msgid_plural "%'d other items selected"
@ -2459,7 +2459,7 @@ msgstr[1] "Beste %'d elementu hautatuta"
#. * needs to use something other than parentheses. The
#. * the message in parentheses is the size of the selected items.
#.
#: src/nautilus-files-view.c:3651
#: src/nautilus-files-view.c:3659
#, c-format
msgid "(%s)"
msgstr "(%s)"
@ -2471,153 +2471,153 @@ msgstr "(%s)"
#. * message about the number of other items and the
#. * total size of those items.
#.
#: src/nautilus-files-view.c:3701
#: src/nautilus-files-view.c:3709
#, c-format
msgid "%s, %s"
msgstr "%s, %s"
#: src/nautilus-files-view.c:3764
#: src/nautilus-files-view.c:3772
msgid "Search _Settings"
msgstr "Bilaketa-e_zarpenak"
#: src/nautilus-files-view.c:3776
#: src/nautilus-files-view.c:3784
msgid "Search _Everywhere"
msgstr "Bilatu _edonon"
#: src/nautilus-files-view.c:3813
#: src/nautilus-files-view.c:3821
msgid "More locations can be added to search in the settings"
msgstr "Ezarpenetan kokaleku gehiago gehitu daitezke bilaketak egiteko"
#. Translators: %s is the name of the search location formatted for display
#: src/nautilus-files-view.c:3821
#: src/nautilus-files-view.c:3829
#, c-format
msgid "No matches in “%s”"
msgstr "Ez dago bat etortzerik hemen: “%s”"
#: src/nautilus-files-view.c:3829 src/gtk/nautilusgtkplacesview.ui:193
#: src/nautilus-files-view.c:3837 src/gtk/nautilusgtkplacesview.ui:193
msgid "No Results Found"
msgstr "Ez da emaitzarik aurkitu"
#: src/nautilus-files-view.c:3834
#: src/nautilus-files-view.c:3842
msgid "Trash is Empty"
msgstr "Zakarrontzia hutsik dago"
#: src/nautilus-files-view.c:3840
#: src/nautilus-files-view.c:3848
msgid "No Starred Files"
msgstr "Ez dago izardun fitxategirik"
#: src/nautilus-files-view.c:3846
#: src/nautilus-files-view.c:3854
msgid "No Recent Files"
msgstr "Ez dago azken aldiko fitxategirik"
#: src/nautilus-files-view.c:3852
#: src/nautilus-files-view.c:3860
msgid "Folder is Empty"
msgstr "Karpeta hutsik dago"
#: src/nautilus-files-view.c:6011
#: src/nautilus-files-view.c:6076
msgid "Select Move Destination"
msgstr "Hautatu helburua eramateko"
#: src/nautilus-files-view.c:6015
#: src/nautilus-files-view.c:6080
msgid "Select Copy Destination"
msgstr "Hautatu helburua kopiatzeko"
#: src/nautilus-files-view.c:6021 src/nautilus-files-view.c:6425
#: src/nautilus-files-view.c:6086 src/nautilus-files-view.c:6475
#: src/nautilus-properties-window.c:4077
#: src/resources/ui/nautilus-files-view-select-items.ui:24
msgid "_Select"
msgstr "_Hautatu"
#: src/nautilus-files-view.c:6424
#: src/nautilus-files-view.c:6474
msgid "Select Extract Destination"
msgstr "Hautatu erauzketaren helburua"
#: src/nautilus-files-view.c:6513
#: src/nautilus-files-view.c:6550
msgid "Error sending email."
msgstr "Errorea mezua bidaltzean"
#. Translators: %s is a file name formatted for display
#: src/nautilus-files-view.c:6811
#: src/nautilus-files-view.c:6848
#, c-format
msgid "Unable to remove “%s”"
msgstr "Ezin da “%s” kendu"
#: src/nautilus-files-view.c:6861
#: src/nautilus-files-view.c:6898
msgid "Unable to stop drive"
msgstr "Ezin da unitatea gelditu"
#. Translators: %s is a file name formatted for display
#: src/nautilus-files-view.c:6972 src/gtk/nautilusgtkplacessidebar.c:2011
#: src/nautilus-files-view.c:7009 src/gtk/nautilusgtkplacessidebar.c:2011
#: src/gtk/nautilusgtkplacessidebar.c:2915
#, c-format
msgid "Unable to start “%s”"
msgstr "Ezin da “%s” abiatu"
#: src/nautilus-files-view.c:7956
#: src/nautilus-files-view.c:7993
#, c-format
msgid "New Folder with Selection (%'d Item)"
msgid_plural "New Folder with Selection (%'d Items)"
msgstr[0] "Karpeta berria hautapenarekin (elementu %'d)"
msgstr[1] "Karpeta berria hautapenarekin (%'d elementu)"
#: src/nautilus-files-view.c:8011
#: src/nautilus-files-view.c:8048
#, c-format
msgid "Open With %s"
msgstr "Ireki honekin: %s"
#: src/nautilus-files-view.c:8022
#: src/nautilus-files-view.c:8059
msgid "Run"
msgstr "Exekutatu"
#: src/nautilus-files-view.c:8027
#: src/nautilus-files-view.c:8064
#: src/resources/ui/nautilus-operations-ui-manager-request-passphrase.ui:17
msgid "Extract"
msgstr "Erauzi"
#: src/nautilus-files-view.c:8028
#: src/nautilus-files-view.c:8065
msgid "Extract to…"
msgstr "Erauzi hona…"
#: src/nautilus-files-view.c:8032
#: src/nautilus-files-view.c:8069
#: src/resources/ui/nautilus-files-view-context-menus.ui:89
msgid "Open"
msgstr "Ireki"
#: src/nautilus-files-view.c:8110
#: src/nautilus-files-view.c:8147
#: src/resources/ui/nautilus-files-view-context-menus.ui:153
#: src/gtk/nautilusgtkplacessidebar.c:3345
msgid "_Start"
msgstr "_Hasi"
#: src/nautilus-files-view.c:8116 src/gtk/nautilusgtkplacesview.c:1724
#: src/nautilus-files-view.c:8153 src/gtk/nautilusgtkplacesview.c:1724
msgid "_Connect"
msgstr "_Konektatu"
#: src/nautilus-files-view.c:8122
#: src/nautilus-files-view.c:8159
msgid "_Start Multi-disk Drive"
msgstr "_Abiatu disko anitzeko unitatea"
#: src/nautilus-files-view.c:8128
#: src/nautilus-files-view.c:8165
msgid "U_nlock Drive"
msgstr "_Desblokeatu unitatea"
#: src/nautilus-files-view.c:8146
#: src/nautilus-files-view.c:8183
msgid "Stop Drive"
msgstr "Gelditu unitatea"
#: src/nautilus-files-view.c:8152 src/gtk/nautilusgtkplacessidebar.c:3362
#: src/nautilus-files-view.c:8189 src/gtk/nautilusgtkplacessidebar.c:3362
msgid "_Safely Remove Drive"
msgstr "_Kendu unitatea modu seguruan"
#: src/nautilus-files-view.c:8158 src/gtk/nautilusgtkplacesview.c:1713
#: src/nautilus-files-view.c:8195 src/gtk/nautilusgtkplacesview.c:1713
msgid "_Disconnect"
msgstr "_Deskonektatu"
#: src/nautilus-files-view.c:8164
#: src/nautilus-files-view.c:8201
msgid "_Stop Multi-disk Drive"
msgstr "_Gelditu disko anitzeko unitatea"
#: src/nautilus-files-view.c:8170
#: src/nautilus-files-view.c:8207
msgid "_Lock Drive"
msgstr "_Blokeatu unitatea"
@ -3723,7 +3723,7 @@ msgstr "Jaregin duzun fitxategia ez da irudia."
#. Translators: This is a verb for tagging or untagging a file with a star.
#. Unmarks a file as starred (starred)
#: src/nautilus-properties-window.c:741 src/nautilus-star-cell.c:73
#: src/nautilus-properties-window.c:741 src/nautilus-star-cell.c:66
#: src/resources/ui/nautilus-files-view-context-menus.ui:247
msgid "Unstar"
msgstr "Kendu izarra"
@ -3960,6 +3960,11 @@ msgstr "_Berregin"
msgid "Open %s"
msgstr "Ireki %s"
#: src/nautilus-window.c:2494 src/nautilus-window.c:2499
#: src/nautilus-window.c:2504 src/nautilus-window.c:2524
msgid "The GNOME Project"
msgstr "GNOME proiektua"
#: src/nautilus-window.c:2511
msgid "No plugins currently installed."
msgstr "Ez dago pluginik instalatuta."
@ -3972,10 +3977,6 @@ msgstr "Unean instalatutako pluginak:"
msgid "For bug testing only, the following command can be used:"
msgstr "Akatsak probatzeko soilik, honako komandoa erabili daiteke:"
#: src/nautilus-window.c:2524
msgid "The GNOME Project"
msgstr "GNOME proiektua"
#. Translators should localize the following string
#. * which will be displayed at the bottom of the about
#. * box to give credit to the translator(s).
@ -4072,11 +4073,6 @@ msgstr "Zerbitzariak konexioa ukatu du. Normalean horrek esan nahi du suebakia s
msgid "Unhandled error message: %s"
msgstr "Kudeatu gabeko errorea: %s"
#: src/nautilus-window-slot.c:1873
#, c-format
msgid "Unable to load location"
msgstr "Ezin da kokalekua kargatu"
#: src/nautilus-x-content-bar.c:141
msgid "Open with:"
msgstr "Ireki honekin:"
@ -4571,7 +4567,7 @@ msgstr "_Hautatu helburuaren izen berria"
msgid "_Reset"
msgstr "_Berrezarri"
#: src/resources/ui/nautilus-file-conflict-dialog.ui:145
#: src/resources/ui/nautilus-file-conflict-dialog.ui:142
msgid "Apply this action to all files and folders"
msgstr "Aplikatu ekintza hau fitxategi eta karpeta guztiei"
@ -4584,7 +4580,7 @@ msgid "C_hange"
msgstr "_Aldatu"
#: src/resources/ui/nautilus-file-properties-change-permissions.ui:147
#: src/resources/ui/nautilus-properties-window.ui:877
#: src/resources/ui/nautilus-properties-window.ui:876
msgid "Others"
msgstr "Bestelakoak"
@ -4891,7 +4887,7 @@ msgstr "Gehitu informazioa fitxategien eta karpeten izenen azpian bistaratzeko.
#: src/resources/ui/nautilus-preferences-window.ui:139
msgid "Grid View Captions"
msgstr "Sareta-ikuspegiaren epigrafeak"
msgstr "Sareta-ikuspegiaren azalpenak"
#. Translators: This is an ordinal number
#: src/resources/ui/nautilus-preferences-window.ui:144
@ -4933,108 +4929,108 @@ msgstr "Kendu ikono pertsonalizatua"
msgid "Unknown Filesystem"
msgstr "Fitxategi-sistema ezezaguna"
#: src/resources/ui/nautilus-properties-window.ui:257
#: src/resources/ui/nautilus-properties-window.ui:256
msgid "total"
msgstr "guztira"
#. Refers to the capacity of the filesystem
#: src/resources/ui/nautilus-properties-window.ui:286
#: src/resources/ui/nautilus-properties-window.ui:285
msgid "used"
msgstr "erabilita"
#. Refers to the capacity of the filesystem
#: src/resources/ui/nautilus-properties-window.ui:316
#: src/resources/ui/nautilus-properties-window.ui:315
msgid "free"
msgstr "libre"
#. Disks refers to GNOME Disks.
#: src/resources/ui/nautilus-properties-window.ui:345
#: src/resources/ui/nautilus-properties-window.ui:344
msgid "Open in Disks"
msgstr "Ireki Diskoak aplikazioan"
#: src/resources/ui/nautilus-properties-window.ui:379
#: src/resources/ui/nautilus-properties-window.ui:378
msgid "_Link Target"
msgstr "Estekaren _helburua"
#: src/resources/ui/nautilus-properties-window.ui:403
#: src/resources/ui/nautilus-properties-window.ui:402
msgid "Open Link Target"
msgstr "Ireki estekaren helburua"
#: src/resources/ui/nautilus-properties-window.ui:427
#: src/resources/ui/nautilus-properties-window.ui:426
msgid "Parent _Folder"
msgstr "Karpeta _gurasoa"
#: src/resources/ui/nautilus-properties-window.ui:451
#: src/resources/ui/nautilus-properties-window.ui:450
msgid "Open Parent Folder"
msgstr "Ireki karpeta gurasoa"
#: src/resources/ui/nautilus-properties-window.ui:483
#: src/resources/ui/nautilus-properties-window.ui:482
msgid "Original Folder"
msgstr "Jatorrizko karpeta"
#: src/resources/ui/nautilus-properties-window.ui:517
#: src/resources/ui/nautilus-properties-window.ui:516
msgid "Trashed on"
msgstr "Zakarrontzira botata"
#: src/resources/ui/nautilus-properties-window.ui:677
#: src/resources/ui/nautilus-properties-window.ui:676
msgid "_Permissions"
msgstr "_Baimenak"
#: src/resources/ui/nautilus-properties-window.ui:699
#: src/resources/ui/nautilus-properties-window.ui:698
msgid "_Executable as Program"
msgstr "Programa gisa _exekutagarria"
#: src/resources/ui/nautilus-properties-window.ui:729
#: src/resources/ui/nautilus-properties-window.ui:728
msgid "Set Custom Permissions"
msgstr "Ezarri baimen pertsonalizatuak"
#: src/resources/ui/nautilus-properties-window.ui:753
#: src/resources/ui/nautilus-properties-window.ui:752
msgid "Unknown Permissions"
msgstr "Baimen ezezagunak"
#: src/resources/ui/nautilus-properties-window.ui:754
#: src/resources/ui/nautilus-properties-window.ui:753
msgid "The permissions of the selected files could not be determined."
msgstr "Ezin izan dira hautatutako fitxategien baimenak zehaztu."
#: src/resources/ui/nautilus-properties-window.ui:769
#: src/resources/ui/nautilus-properties-window.ui:768
msgid "You are not the owner, so you cannot change these permissions."
msgstr "Ez zara jabea, beraz ezin dituzu baimen hauek aldatu."
#: src/resources/ui/nautilus-properties-window.ui:785
#: src/resources/ui/nautilus-properties-window.ui:784
msgid "The permissions of the selected file could not be determined."
msgstr "Ezin izan dira hautatutako fitxategiaren baimenak zehaztu."
#: src/resources/ui/nautilus-properties-window.ui:798
#: src/resources/ui/nautilus-properties-window.ui:797
msgid "_Owner"
msgstr "_Jabea"
#: src/resources/ui/nautilus-properties-window.ui:809
#: src/resources/ui/nautilus-properties-window.ui:849
#: src/resources/ui/nautilus-properties-window.ui:884
#: src/resources/ui/nautilus-properties-window.ui:808
#: src/resources/ui/nautilus-properties-window.ui:848
#: src/resources/ui/nautilus-properties-window.ui:883
msgid "Access"
msgstr "Atzitzea"
#: src/resources/ui/nautilus-properties-window.ui:816
#: src/resources/ui/nautilus-properties-window.ui:856
#: src/resources/ui/nautilus-properties-window.ui:891
#: src/resources/ui/nautilus-properties-window.ui:815
#: src/resources/ui/nautilus-properties-window.ui:855
#: src/resources/ui/nautilus-properties-window.ui:890
msgid "Folder Access"
msgstr "Karpeta-atzitzea"
#: src/resources/ui/nautilus-properties-window.ui:823
#: src/resources/ui/nautilus-properties-window.ui:863
#: src/resources/ui/nautilus-properties-window.ui:898
#: src/resources/ui/nautilus-properties-window.ui:822
#: src/resources/ui/nautilus-properties-window.ui:862
#: src/resources/ui/nautilus-properties-window.ui:897
msgid "File Access"
msgstr "Fitxategi-atzitzea"
#: src/resources/ui/nautilus-properties-window.ui:838
#: src/resources/ui/nautilus-properties-window.ui:837
msgid "_Group"
msgstr "_Taldea"
#: src/resources/ui/nautilus-properties-window.ui:920
#: src/resources/ui/nautilus-properties-window.ui:919
msgid "Security Context"
msgstr "Segurtasun-testuingurua"
#: src/resources/ui/nautilus-properties-window.ui:953
#: src/resources/ui/nautilus-properties-window.ui:952
msgid "Change Permissions for _Enclosed Files…"
msgstr "Aldatu baimenak fitxategi i_nguratuei…"
@ -5236,7 +5232,7 @@ msgid "No network locations found"
msgstr "Ez da sareko kokalekurik aurkitu"
#. Restore from Cancel to Connect
#: src/gtk/nautilusgtkplacesview.c:1233 src/gtk/nautilusgtkplacesview.ui:241
#: src/gtk/nautilusgtkplacesview.c:1233 src/gtk/nautilusgtkplacesview.ui:243
msgid "Con_nect"
msgstr "_Konektatu"
@ -5504,6 +5500,10 @@ msgstr "Alboko barra"
msgid "List of common shortcuts, mountpoints, and bookmarks."
msgstr "Lasterbide, muntatze-puntu eta laster-marka arrunten zerrenda."
#, c-format
#~ msgid "Unable to load location"
#~ msgstr "Ezin da kokalekua kargatu"
#~ msgid "No matches found in indexed locations"
#~ msgstr "Ez da bat etortzerik aurkitu indexatutako kokalekuetan"

12336
po/hi.po

File diff suppressed because it is too large Load Diff

1157
po/hu.po

File diff suppressed because it is too large Load Diff

6113
po/ne.po

File diff suppressed because it is too large Load Diff

413
po/ru.po

File diff suppressed because it is too large Load Diff

1141
po/sl.po

File diff suppressed because it is too large Load Diff

3264
po/sr.po

File diff suppressed because it is too large Load Diff

View File

@ -1,646 +0,0 @@
/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
/* GTK - The GIMP Toolkit
* nautilusgtkbookmarksmanager.c: Utilities to manage and monitor ~/.gtk-bookmarks
* Copyright (C) 2003, Red Hat, Inc.
* Copyright (C) 2007-2008 Carlos Garnacho
* Copyright (C) 2011 Suse
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This program 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Authors: Federico Mena Quintero <federico@gnome.org>
*/
#include "config.h"
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include "nautilus-enum-types.h"
#include <string.h>
#include "nautilusgtkbookmarksmanagerprivate.h"
static void
_gtk_bookmark_free (gpointer data)
{
GtkBookmark *bookmark = data;
g_object_unref (bookmark->file);
g_free (bookmark->label);
g_slice_free (GtkBookmark, bookmark);
}
static void
set_error_bookmark_doesnt_exist (GFile *file, GError **error)
{
char *uri = g_file_get_uri (file);
g_set_error (error,
GTK_FILE_CHOOSER_ERROR,
GTK_FILE_CHOOSER_ERROR_NONEXISTENT,
_("%s does not exist in the bookmarks list"),
uri);
g_free (uri);
}
static GFile *
get_legacy_bookmarks_file (void)
{
GFile *file;
char *filename;
filename = g_build_filename (g_get_home_dir (), ".gtk-bookmarks", NULL);
file = g_file_new_for_path (filename);
g_free (filename);
return file;
}
static GFile *
get_bookmarks_file (void)
{
GFile *file;
char *filename;
/* Use gtk-3.0's bookmarks file as the format didn't change.
* Add the 3.0 file format to get_legacy_bookmarks_file() when
* the format does change.
*/
filename = g_build_filename (g_get_user_config_dir (), "gtk-3.0", "bookmarks", NULL);
file = g_file_new_for_path (filename);
g_free (filename);
return file;
}
static GSList *
parse_bookmarks (const char *contents)
{
char **lines, *space;
GSList *bookmarks = NULL;
int i;
lines = g_strsplit (contents, "\n", -1);
for (i = 0; lines[i]; i++)
{
GtkBookmark *bookmark;
if (!*lines[i])
continue;
if (!g_utf8_validate (lines[i], -1, NULL))
continue;
bookmark = g_slice_new0 (GtkBookmark);
if ((space = strchr (lines[i], ' ')) != NULL)
{
space[0] = '\0';
bookmark->label = g_strdup (space + 1);
}
bookmark->file = g_file_new_for_uri (lines[i]);
bookmarks = g_slist_prepend (bookmarks, bookmark);
}
bookmarks = g_slist_reverse (bookmarks);
g_strfreev (lines);
return bookmarks;
}
static GSList *
read_bookmarks (GFile *file)
{
char *contents;
GSList *bookmarks = NULL;
if (!g_file_load_contents (file, NULL, &contents,
NULL, NULL, NULL))
return NULL;
bookmarks = parse_bookmarks (contents);
g_free (contents);
return bookmarks;
}
static void
notify_changed (NautilusGtkBookmarksManager *manager)
{
if (manager->changed_func)
manager->changed_func (manager->changed_func_data);
}
static void
read_bookmarks_finish (GObject *source,
GAsyncResult *result,
gpointer data)
{
GFile *file = G_FILE (source);
NautilusGtkBookmarksManager *manager = data;
char *contents = NULL;
GError *error = NULL;
if (!g_file_load_contents_finish (file, result, &contents, NULL, NULL, &error))
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
g_warning ("Failed to load '%s': %s", g_file_peek_path (file), error->message);
g_error_free (error);
return;
}
g_slist_free_full (manager->bookmarks, _gtk_bookmark_free);
manager->bookmarks = parse_bookmarks (contents);
g_free (contents);
notify_changed (manager);
}
static void
save_bookmarks (GFile *bookmarks_file,
GSList *bookmarks)
{
GError *error = NULL;
GString *contents;
GSList *l;
GFile *parent = NULL;
contents = g_string_new ("");
for (l = bookmarks; l; l = l->next)
{
GtkBookmark *bookmark = l->data;
char *uri;
uri = g_file_get_uri (bookmark->file);
if (!uri)
continue;
g_string_append (contents, uri);
if (bookmark->label && g_utf8_validate (bookmark->label, -1, NULL))
g_string_append_printf (contents, " %s", bookmark->label);
g_string_append_c (contents, '\n');
g_free (uri);
}
parent = g_file_get_parent (bookmarks_file);
if (!g_file_make_directory_with_parents (parent, NULL, &error))
{
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
g_clear_error (&error);
else
goto out;
}
if (!g_file_replace_contents (bookmarks_file,
contents->str,
contents->len,
NULL, FALSE, 0, NULL,
NULL, &error))
goto out;
out:
if (error)
{
g_critical ("%s", error->message);
g_error_free (error);
}
g_clear_object (&parent);
g_string_free (contents, TRUE);
}
static void
bookmarks_file_changed (GFileMonitor *monitor,
GFile *file,
GFile *other_file,
GFileMonitorEvent event,
gpointer data)
{
NautilusGtkBookmarksManager *manager = data;
switch (event)
{
case G_FILE_MONITOR_EVENT_CHANGED:
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
case G_FILE_MONITOR_EVENT_CREATED:
g_file_load_contents_async (file, manager->cancellable, read_bookmarks_finish, manager);
break;
case G_FILE_MONITOR_EVENT_DELETED:
case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
case G_FILE_MONITOR_EVENT_UNMOUNTED:
case G_FILE_MONITOR_EVENT_MOVED:
case G_FILE_MONITOR_EVENT_RENAMED:
case G_FILE_MONITOR_EVENT_MOVED_IN:
case G_FILE_MONITOR_EVENT_MOVED_OUT:
default:
/* ignore at the moment */
break;
}
}
NautilusGtkBookmarksManager *
_nautilus_gtk_bookmarks_manager_new (GtkBookmarksChangedFunc changed_func, gpointer changed_func_data)
{
NautilusGtkBookmarksManager *manager;
GFile *bookmarks_file;
GError *error;
manager = g_new0 (NautilusGtkBookmarksManager, 1);
manager->changed_func = changed_func;
manager->changed_func_data = changed_func_data;
manager->cancellable = g_cancellable_new ();
bookmarks_file = get_bookmarks_file ();
if (!g_file_query_exists (bookmarks_file, NULL))
{
GFile *legacy_bookmarks_file;
/* Read the legacy one and write it to the new one */
legacy_bookmarks_file = get_legacy_bookmarks_file ();
manager->bookmarks = read_bookmarks (legacy_bookmarks_file);
if (manager->bookmarks)
save_bookmarks (bookmarks_file, manager->bookmarks);
g_object_unref (legacy_bookmarks_file);
}
else
g_file_load_contents_async (bookmarks_file, manager->cancellable, read_bookmarks_finish, manager);
error = NULL;
manager->bookmarks_monitor = g_file_monitor_file (bookmarks_file,
G_FILE_MONITOR_NONE,
NULL, &error);
if (error)
{
g_warning ("%s", error->message);
g_error_free (error);
}
else
manager->bookmarks_monitor_changed_id = g_signal_connect (manager->bookmarks_monitor, "changed",
G_CALLBACK (bookmarks_file_changed), manager);
g_object_unref (bookmarks_file);
return manager;
}
void
_nautilus_gtk_bookmarks_manager_free (NautilusGtkBookmarksManager *manager)
{
g_return_if_fail (manager != NULL);
g_cancellable_cancel (manager->cancellable);
g_object_unref (manager->cancellable);
if (manager->bookmarks_monitor)
{
g_file_monitor_cancel (manager->bookmarks_monitor);
g_signal_handler_disconnect (manager->bookmarks_monitor, manager->bookmarks_monitor_changed_id);
manager->bookmarks_monitor_changed_id = 0;
g_object_unref (manager->bookmarks_monitor);
}
g_slist_free_full (manager->bookmarks, _gtk_bookmark_free);
g_free (manager);
}
GSList *
_nautilus_gtk_bookmarks_manager_list_bookmarks (NautilusGtkBookmarksManager *manager)
{
GSList *bookmarks, *files = NULL;
g_return_val_if_fail (manager != NULL, NULL);
bookmarks = manager->bookmarks;
while (bookmarks)
{
GtkBookmark *bookmark;
bookmark = bookmarks->data;
bookmarks = bookmarks->next;
files = g_slist_prepend (files, g_object_ref (bookmark->file));
}
return g_slist_reverse (files);
}
static GSList *
find_bookmark_link_for_file (GSList *bookmarks, GFile *file, int *position_ret)
{
int pos;
pos = 0;
for (; bookmarks; bookmarks = bookmarks->next)
{
GtkBookmark *bookmark = bookmarks->data;
if (g_file_equal (file, bookmark->file))
{
if (position_ret)
*position_ret = pos;
return bookmarks;
}
pos++;
}
if (position_ret)
*position_ret = -1;
return NULL;
}
gboolean
_nautilus_gtk_bookmarks_manager_has_bookmark (NautilusGtkBookmarksManager *manager,
GFile *file)
{
GSList *link;
link = find_bookmark_link_for_file (manager->bookmarks, file, NULL);
return (link != NULL);
}
gboolean
_nautilus_gtk_bookmarks_manager_insert_bookmark (NautilusGtkBookmarksManager *manager,
GFile *file,
int position,
GError **error)
{
GSList *link;
GtkBookmark *bookmark;
GFile *bookmarks_file;
g_return_val_if_fail (manager != NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
link = find_bookmark_link_for_file (manager->bookmarks, file, NULL);
if (link)
{
char *uri;
bookmark = link->data;
uri = g_file_get_uri (bookmark->file);
g_set_error (error,
GTK_FILE_CHOOSER_ERROR,
GTK_FILE_CHOOSER_ERROR_ALREADY_EXISTS,
_("%s already exists in the bookmarks list"),
uri);
g_free (uri);
return FALSE;
}
bookmark = g_slice_new0 (GtkBookmark);
bookmark->file = g_object_ref (file);
manager->bookmarks = g_slist_insert (manager->bookmarks, bookmark, position);
bookmarks_file = get_bookmarks_file ();
save_bookmarks (bookmarks_file, manager->bookmarks);
g_object_unref (bookmarks_file);
notify_changed (manager);
return TRUE;
}
gboolean
_nautilus_gtk_bookmarks_manager_remove_bookmark (NautilusGtkBookmarksManager *manager,
GFile *file,
GError **error)
{
GSList *link;
GFile *bookmarks_file;
g_return_val_if_fail (manager != NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
if (!manager->bookmarks)
return FALSE;
link = find_bookmark_link_for_file (manager->bookmarks, file, NULL);
if (link)
{
GtkBookmark *bookmark = link->data;
manager->bookmarks = g_slist_remove_link (manager->bookmarks, link);
_gtk_bookmark_free (bookmark);
g_slist_free_1 (link);
}
else
{
set_error_bookmark_doesnt_exist (file, error);
return FALSE;
}
bookmarks_file = get_bookmarks_file ();
save_bookmarks (bookmarks_file, manager->bookmarks);
g_object_unref (bookmarks_file);
notify_changed (manager);
return TRUE;
}
gboolean
_nautilus_gtk_bookmarks_manager_reorder_bookmark (NautilusGtkBookmarksManager *manager,
GFile *file,
int new_position,
GError **error)
{
GSList *link;
GFile *bookmarks_file;
int old_position;
g_return_val_if_fail (manager != NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
g_return_val_if_fail (new_position >= 0, FALSE);
if (!manager->bookmarks)
return FALSE;
link = find_bookmark_link_for_file (manager->bookmarks, file, &old_position);
if (new_position == old_position)
return TRUE;
if (link)
{
GtkBookmark *bookmark = link->data;
manager->bookmarks = g_slist_remove_link (manager->bookmarks, link);
g_slist_free_1 (link);
if (new_position > old_position)
new_position--;
manager->bookmarks = g_slist_insert (manager->bookmarks, bookmark, new_position);
}
else
{
set_error_bookmark_doesnt_exist (file, error);
return FALSE;
}
bookmarks_file = get_bookmarks_file ();
save_bookmarks (bookmarks_file, manager->bookmarks);
g_object_unref (bookmarks_file);
notify_changed (manager);
return TRUE;
}
char *
_nautilus_gtk_bookmarks_manager_get_bookmark_label (NautilusGtkBookmarksManager *manager,
GFile *file)
{
GSList *bookmarks;
char *label = NULL;
g_return_val_if_fail (manager != NULL, NULL);
g_return_val_if_fail (file != NULL, NULL);
bookmarks = manager->bookmarks;
while (bookmarks)
{
GtkBookmark *bookmark;
bookmark = bookmarks->data;
bookmarks = bookmarks->next;
if (g_file_equal (file, bookmark->file))
{
label = g_strdup (bookmark->label);
break;
}
}
return label;
}
gboolean
_nautilus_gtk_bookmarks_manager_set_bookmark_label (NautilusGtkBookmarksManager *manager,
GFile *file,
const char *label,
GError **error)
{
GFile *bookmarks_file;
GSList *link;
g_return_val_if_fail (manager != NULL, FALSE);
g_return_val_if_fail (file != NULL, FALSE);
link = find_bookmark_link_for_file (manager->bookmarks, file, NULL);
if (link)
{
GtkBookmark *bookmark = link->data;
GString *inlined_label = g_string_new (label);
g_string_replace (inlined_label, "\n", " ", 0);
g_free (bookmark->label);
bookmark->label = g_string_free_and_steal (inlined_label);
}
else
{
set_error_bookmark_doesnt_exist (file, error);
return FALSE;
}
bookmarks_file = get_bookmarks_file ();
save_bookmarks (bookmarks_file, manager->bookmarks);
g_object_unref (bookmarks_file);
notify_changed (manager);
return TRUE;
}
static gboolean
_nautilus_gtk_bookmarks_manager_get_xdg_type (NautilusGtkBookmarksManager *manager,
GFile *file,
GUserDirectory *directory)
{
GSList *link;
gboolean match;
GFile *location;
const char *path;
GUserDirectory dir;
GtkBookmark *bookmark;
link = find_bookmark_link_for_file (manager->bookmarks, file, NULL);
if (!link)
return FALSE;
match = FALSE;
bookmark = link->data;
for (dir = 0; dir < G_USER_N_DIRECTORIES; dir++)
{
path = g_get_user_special_dir (dir);
if (!path)
continue;
location = g_file_new_for_path (path);
match = g_file_equal (location, bookmark->file);
g_object_unref (location);
if (match)
break;
}
if (match && directory != NULL)
*directory = dir;
return match;
}
gboolean
_nautilus_gtk_bookmarks_manager_get_is_builtin (NautilusGtkBookmarksManager *manager,
GFile *file)
{
GUserDirectory xdg_type;
/* if this is not an XDG dir, it's never builtin */
if (!_nautilus_gtk_bookmarks_manager_get_xdg_type (manager, file, &xdg_type))
return FALSE;
/* exclude XDG locations we don't display by default */
return _nautilus_gtk_bookmarks_manager_get_is_xdg_dir_builtin (xdg_type);
}
gboolean
_nautilus_gtk_bookmarks_manager_get_is_xdg_dir_builtin (GUserDirectory xdg_type)
{
return (xdg_type != G_USER_DIRECTORY_DESKTOP) &&
(xdg_type != G_USER_DIRECTORY_TEMPLATES) &&
(xdg_type != G_USER_DIRECTORY_PUBLIC_SHARE);
}

View File

@ -1,89 +0,0 @@
/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
/* GTK - The GIMP Toolkit
* nautilusgtkbookmarksmanager.h: Utilities to manage and monitor ~/.gtk-bookmarks
* Copyright (C) 2003, Red Hat, Inc.
* Copyright (C) 2007-2008 Carlos Garnacho
* Copyright (C) 2011 Suse
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This program 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Authors: Federico Mena Quintero <federico@gnome.org>
*/
#ifndef __NAUTILUS_GTK_BOOKMARKS_MANAGER_H__
#define __NAUTILUS_GTK_BOOKMARKS_MANAGER_H__
#include <gio/gio.h>
typedef void (* GtkBookmarksChangedFunc) (gpointer data);
typedef struct
{
/* This list contains GtkBookmark structs */
GSList *bookmarks;
GFileMonitor *bookmarks_monitor;
gulong bookmarks_monitor_changed_id;
gpointer changed_func_data;
GtkBookmarksChangedFunc changed_func;
GCancellable *cancellable;
} NautilusGtkBookmarksManager;
typedef struct
{
GFile *file;
char *label;
} GtkBookmark;
NautilusGtkBookmarksManager *_nautilus_gtk_bookmarks_manager_new (GtkBookmarksChangedFunc changed_func,
gpointer changed_func_data);
void _nautilus_gtk_bookmarks_manager_free (NautilusGtkBookmarksManager *manager);
GSList *_nautilus_gtk_bookmarks_manager_list_bookmarks (NautilusGtkBookmarksManager *manager);
gboolean _nautilus_gtk_bookmarks_manager_insert_bookmark (NautilusGtkBookmarksManager *manager,
GFile *file,
int position,
GError **error);
gboolean _nautilus_gtk_bookmarks_manager_remove_bookmark (NautilusGtkBookmarksManager *manager,
GFile *file,
GError **error);
gboolean _nautilus_gtk_bookmarks_manager_reorder_bookmark (NautilusGtkBookmarksManager *manager,
GFile *file,
int new_position,
GError **error);
gboolean _nautilus_gtk_bookmarks_manager_has_bookmark (NautilusGtkBookmarksManager *manager,
GFile *file);
char * _nautilus_gtk_bookmarks_manager_get_bookmark_label (NautilusGtkBookmarksManager *manager,
GFile *file);
gboolean _nautilus_gtk_bookmarks_manager_set_bookmark_label (NautilusGtkBookmarksManager *manager,
GFile *file,
const char *label,
GError **error);
gboolean _nautilus_gtk_bookmarks_manager_get_is_builtin (NautilusGtkBookmarksManager *manager,
GFile *file);
gboolean _nautilus_gtk_bookmarks_manager_get_is_xdg_dir_builtin (GUserDirectory xdg_type);
#endif /* __NAUTILUS_GTK_BOOKMARKS_MANAGER_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -24,6 +24,8 @@
#include <glib.h>
#include <gtk/gtk.h>
#include "nautilus-enums.h"
G_BEGIN_DECLS
#define NAUTILUS_TYPE_GTK_PLACES_SIDEBAR (nautilus_gtk_places_sidebar_get_type ())
@ -36,108 +38,41 @@ G_BEGIN_DECLS
typedef struct _NautilusGtkPlacesSidebar NautilusGtkPlacesSidebar;
typedef struct _NautilusGtkPlacesSidebarClass NautilusGtkPlacesSidebarClass;
/*
* NautilusGtkPlacesOpenFlags:
* @NAUTILUS_GTK_PLACES_OPEN_NORMAL: This is the default mode that NautilusGtkPlacesSidebar uses if no other flags
* are specified. It indicates that the calling application should open the selected location
* in the normal way, for example, in the folder view beside the sidebar.
* @NAUTILUS_GTK_PLACES_OPEN_NEW_TAB: When passed to nautilus_gtk_places_sidebar_set_open_flags(), this indicates
* that the application can open folders selected from the sidebar in new tabs. This value
* will be passed to the NautilusGtkPlacesSidebar::open-location signal when the user selects
* that a location be opened in a new tab instead of in the standard fashion.
* @NAUTILUS_GTK_PLACES_OPEN_NEW_WINDOW: Similar to @NAUTILUS_GTK_PLACES_OPEN_NEW_TAB, but indicates that the application
* can open folders in new windows.
*
* These flags serve two purposes. First, the application can call nautilus_gtk_places_sidebar_set_open_flags()
* using these flags as a bitmask. This tells the sidebar that the application is able to open
* folders selected from the sidebar in various ways, for example, in new tabs or in new windows in
* addition to the normal mode.
*
* Second, when one of these values gets passed back to the application in the
* NautilusGtkPlacesSidebar::open-location signal, it means that the application should
* open the selected location in the normal way, in a new tab, or in a new
* window. The sidebar takes care of determining the desired way to open the location,
* based on the modifier keys that the user is pressing at the time the selection is made.
*
* If the application never calls nautilus_gtk_places_sidebar_set_open_flags(), then the sidebar will only
* use NAUTILUS_GTK_PLACES_OPEN_NORMAL in the NautilusGtkPlacesSidebar::open-location signal. This is the
* default mode of operation.
*/
typedef enum {
NAUTILUS_GTK_PLACES_OPEN_NORMAL = 1 << 0,
NAUTILUS_GTK_PLACES_OPEN_NEW_TAB = 1 << 1,
NAUTILUS_GTK_PLACES_OPEN_NEW_WINDOW = 1 << 2
} NautilusGtkPlacesOpenFlags;
GType nautilus_gtk_places_sidebar_get_type (void) G_GNUC_CONST;
GtkWidget * nautilus_gtk_places_sidebar_new (void);
NautilusGtkPlacesOpenFlags nautilus_gtk_places_sidebar_get_open_flags (NautilusGtkPlacesSidebar *sidebar);
NautilusOpenFlags nautilus_gtk_places_sidebar_get_open_flags (NautilusGtkPlacesSidebar *sidebar);
void nautilus_gtk_places_sidebar_set_open_flags (NautilusGtkPlacesSidebar *sidebar,
NautilusGtkPlacesOpenFlags flags);
NautilusOpenFlags flags);
GFile * nautilus_gtk_places_sidebar_get_location (NautilusGtkPlacesSidebar *sidebar);
void nautilus_gtk_places_sidebar_set_location (NautilusGtkPlacesSidebar *sidebar,
GFile *location);
gboolean nautilus_gtk_places_sidebar_get_show_recent (NautilusGtkPlacesSidebar *sidebar);
void nautilus_gtk_places_sidebar_set_show_recent (NautilusGtkPlacesSidebar *sidebar,
gboolean show_recent);
gboolean nautilus_gtk_places_sidebar_get_show_desktop (NautilusGtkPlacesSidebar *sidebar);
void nautilus_gtk_places_sidebar_set_show_desktop (NautilusGtkPlacesSidebar *sidebar,
gboolean show_desktop);
gboolean nautilus_gtk_places_sidebar_get_show_enter_location (NautilusGtkPlacesSidebar *sidebar);
void nautilus_gtk_places_sidebar_set_show_enter_location (NautilusGtkPlacesSidebar *sidebar,
gboolean show_enter_location);
void nautilus_gtk_places_sidebar_add_shortcut (NautilusGtkPlacesSidebar *sidebar,
GFile *location);
void nautilus_gtk_places_sidebar_remove_shortcut (NautilusGtkPlacesSidebar *sidebar,
GFile *location);
GListModel * nautilus_gtk_places_sidebar_get_shortcuts (NautilusGtkPlacesSidebar *sidebar);
GFile * nautilus_gtk_places_sidebar_get_nth_bookmark (NautilusGtkPlacesSidebar *sidebar,
int n);
void nautilus_gtk_places_sidebar_set_drop_targets_visible (NautilusGtkPlacesSidebar *sidebar,
gboolean visible);
gboolean nautilus_gtk_places_sidebar_get_show_trash (NautilusGtkPlacesSidebar *sidebar);
void nautilus_gtk_places_sidebar_set_show_trash (NautilusGtkPlacesSidebar *sidebar,
gboolean show_trash);
void nautilus_gtk_places_sidebar_set_show_other_locations (NautilusGtkPlacesSidebar *sidebar,
gboolean show_other_locations);
gboolean nautilus_gtk_places_sidebar_get_show_other_locations (NautilusGtkPlacesSidebar *sidebar);
void nautilus_gtk_places_sidebar_set_show_starred_location (NautilusGtkPlacesSidebar *sidebar,
gboolean show_starred_location);
gboolean nautilus_gtk_places_sidebar_get_show_starred_location (NautilusGtkPlacesSidebar *sidebar);
/* Keep order, since it's used for the sort functions */
typedef enum {
NAUTILUS_GTK_PLACES_SECTION_INVALID,
NAUTILUS_GTK_PLACES_SECTION_COMPUTER,
NAUTILUS_GTK_PLACES_SECTION_MOUNTS,
NAUTILUS_GTK_PLACES_SECTION_CLOUD,
NAUTILUS_GTK_PLACES_SECTION_DEFAULT_LOCATIONS,
NAUTILUS_GTK_PLACES_SECTION_BOOKMARKS,
NAUTILUS_GTK_PLACES_SECTION_OTHER_LOCATIONS,
NAUTILUS_GTK_PLACES_SECTION_CLOUD,
NAUTILUS_GTK_PLACES_SECTION_MOUNTS,
NAUTILUS_GTK_PLACES_N_SECTIONS
} NautilusGtkPlacesSectionType;
typedef enum {
NAUTILUS_GTK_PLACES_INVALID,
NAUTILUS_GTK_PLACES_BUILT_IN,
NAUTILUS_GTK_PLACES_XDG_DIR,
NAUTILUS_GTK_PLACES_MOUNTED_VOLUME,
NAUTILUS_GTK_PLACES_EXTERNAL_MOUNT,
NAUTILUS_GTK_PLACES_INTERNAL_MOUNT,
NAUTILUS_GTK_PLACES_BOOKMARK,
NAUTILUS_GTK_PLACES_HEADING,
NAUTILUS_GTK_PLACES_CONNECT_TO_SERVER,
NAUTILUS_GTK_PLACES_ENTER_LOCATION,
NAUTILUS_GTK_PLACES_DROP_FEEDBACK,
NAUTILUS_GTK_PLACES_BOOKMARK_PLACEHOLDER,
NAUTILUS_GTK_PLACES_OTHER_LOCATIONS,
NAUTILUS_GTK_PLACES_STARRED_LOCATION,
NAUTILUS_GTK_PLACES_N_PLACES
} NautilusGtkPlacesPlaceType;

File diff suppressed because it is too large Load Diff

View File

@ -1,254 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkListStore" id="completion_store">
<columns>
<column type="gchararray"/>
<column type="gchararray"/>
</columns>
</object>
<object class="GtkEntryCompletion" id="address_entry_completion">
<property name="model">completion_store</property>
<property name="text-column">1</property>
<property name="inline-completion">1</property>
<property name="popup-completion">0</property>
</object>
<object class="GtkPopover" id="server_adresses_popover">
<property name="position">2</property>
<child>
<object class="GtkBox">
<property name="orientation">1</property>
<property name="spacing">6</property>
<property name="margin-start">18</property>
<property name="margin-end">18</property>
<property name="margin-top">18</property>
<property name="margin-bottom">18</property>
<child>
<object class="GtkLabel">
<property name="hexpand">1</property>
<property name="label" translatable="yes">Server Addresses</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="hexpand">1</property>
<property name="label" translatable="yes">Server addresses are made up of a protocol prefix and an address. Examples:</property>
<property name="wrap">1</property>
<property name="width-chars">40</property>
<property name="max-width-chars">40</property>
<property name="xalign">0</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="hexpand">1</property>
<property name="label">smb://gnome.org, ssh://192.168.0.1, ftp://[2001:db8::1]</property>
<property name="wrap">1</property>
<property name="width-chars">40</property>
<property name="max-width-chars">40</property>
<property name="xalign">0</property>
</object>
</child>
<child>
<object class="GtkGrid" id="available_protocols_grid">
<property name="margin-top">12</property>
<property name="hexpand">1</property>
<property name="row-spacing">6</property>
<property name="column-spacing">12</property>
<child>
<object class="GtkLabel">
<property name="hexpand">1</property>
<property name="label" translatable="yes">Available Protocols</property>
<property name="xalign">0</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
<layout>
<property name="column">0</property>
<property name="row">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Prefix</property>
<property name="xalign">0</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
<layout>
<property name="column">1</property>
<property name="row">0</property>
</layout>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<object class="GtkPopover" id="recent_servers_popover">
<child>
<object class="GtkStack" id="recent_servers_stack">
<child>
<object class="GtkStackPage">
<property name="name">empty</property>
<property name="child">
<object class="AdwStatusPage">
<property name="icon-name">network-server-symbolic</property>
<property name="title" translatable="yes" comments="Translators: Server as any successfully connected network address">No Recent Servers</property>
<style>
<class name="compact"/>
</style>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">list</property>
<property name="child">
<object class="GtkBox">
<property name="orientation">1</property>
<property name="spacing">12</property>
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<property name="margin-top">12</property>
<property name="margin-bottom">12</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Recent Servers</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="vexpand">1</property>
<property name="has-frame">1</property>
<property name="min-content-width">250</property>
<property name="min-content-height">200</property>
<child>
<object class="GtkViewport">
<child>
<object class="GtkListBox" id="recent_servers_listbox">
<property name="selection-mode">0</property>
<signal name="row-activated" handler="on_recent_servers_listbox_row_activated" object="NautilusGtkPlacesView" swapped="yes"/>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</property>
</object>
</child>
</object>
</child>
</object>
<template class="NautilusGtkPlacesView" parent="GtkBox">
<accessibility>
<property name="label" translatable="yes">Other Locations</property>
<property name="description" translatable="yes">List of common local and remote mountpoints.</property>
</accessibility>
<property name="orientation">1</property>
<child>
<object class="GtkStack" id="stack">
<property name="vhomogeneous">0</property>
<property name="transition-type">1</property>
<child>
<object class="GtkStackPage">
<property name="name">browse</property>
<property name="child">
<object class="GtkScrolledWindow">
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<child>
<object class="GtkViewport">
<child>
<object class="GtkListBox" id="listbox">
<property name="selection-mode">0</property>
<signal name="row-activated" handler="on_listbox_row_activated" object="NautilusGtkPlacesView" swapped="yes"/>
</object>
</child>
</object>
</child>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">empty-search</property>
<property name="child">
<object class="AdwStatusPage">
<property name="icon-name">edit-find-symbolic</property>
<property name="title" translatable="yes">No Results Found</property>
<property name="description" translatable="yes">Try a different search.</property>
</object>
</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkBox" id="actionbar">
<property name="hexpand">1</property>
<style>
<class name="toolbar"/>
</style>
<child>
<object class="GtkBox">
<child>
<object class="GtkEntry" id="address_entry">
<property name="width-chars">10</property>
<property name="max-width-chars">34</property>
<property name="placeholder-text" translatable="yes">Enter server address…</property>
<property name="secondary-icon-name">dialog-question-symbolic</property>
<property name="completion">address_entry_completion</property>
<property name="input-purpose">url</property>
<property name="input-hints">no-spellcheck | no-emoji</property>
<signal name="notify::text" handler="on_address_entry_text_changed" object="NautilusGtkPlacesView" swapped="yes"/>
<signal name="activate" handler="on_connect_button_clicked" object="NautilusGtkPlacesView" swapped="yes"/>
<signal name="icon-press" handler="on_address_entry_show_help_pressed" object="NautilusGtkPlacesView" swapped="yes"/>
</object>
</child>
<child>
<object class="GtkMenuButton" id="server_list_button">
<property name="direction">0</property>
<property name="popover">recent_servers_popover</property>
<property name="icon-name">pan-down-symbolic</property>
<style>
<class name="server-list-button"/>
</style>
</object>
</child>
<style>
<class name="linked"/>
</style>
</object>
</child>
<child>
<object class="GtkButton" id="connect_button">
<property name="label" translatable="yes">Con_nect</property>
<property name="use-underline">1</property>
<property name="can-shrink">true</property>
<property name="sensitive">0</property>
<property name="valign">3</property>
<signal name="clicked" handler="on_connect_button_clicked" object="NautilusGtkPlacesView" swapped="yes"/>
</object>
</child>
</object>
</child>
</template>
</interface>

View File

@ -1,55 +0,0 @@
/* nautilusgtkplacesview.h
*
* Copyright (C) 2015 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NAUTILUS_GTK_PLACES_VIEW_H
#define NAUTILUS_GTK_PLACES_VIEW_H
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#endif
#include "nautilusgtkplacessidebarprivate.h"
G_BEGIN_DECLS
#define NAUTILUS_TYPE_GTK_PLACES_VIEW (nautilus_gtk_places_view_get_type ())
#define NAUTILUS_GTK_PLACES_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_GTK_PLACES_VIEW, NautilusGtkPlacesView))
#define NAUTILUS_GTK_PLACES_VIEW_CLASS(klass)(G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_GTK_PLACES_VIEW, NautilusGtkPlacesViewClass))
#define NAUTILUS_IS_GTK_PLACES_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_GTK_PLACES_VIEW))
#define NAUTILUS_IS_GTK_PLACES_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_GTK_PLACES_VIEW))
#define NAUTILUS_GTK_PLACES_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NAUTILUS_TYPE_GTK_PLACES_VIEW, NautilusGtkPlacesViewClass))
typedef struct _NautilusGtkPlacesView NautilusGtkPlacesView;
typedef struct _NautilusGtkPlacesViewClass NautilusGtkPlacesViewClass;
GType nautilus_gtk_places_view_get_type (void) G_GNUC_CONST;
NautilusGtkPlacesOpenFlags nautilus_gtk_places_view_get_open_flags (NautilusGtkPlacesView *view);
void nautilus_gtk_places_view_set_open_flags (NautilusGtkPlacesView *view,
NautilusGtkPlacesOpenFlags flags);
const char * nautilus_gtk_places_view_get_search_query (NautilusGtkPlacesView *view);
void nautilus_gtk_places_view_set_search_query (NautilusGtkPlacesView *view,
const char *query_text);
gboolean nautilus_gtk_places_view_get_loading (NautilusGtkPlacesView *view);
GtkWidget * nautilus_gtk_places_view_new (void);
G_END_DECLS
#endif /* NAUTILUS_GTK_PLACES_VIEW_H */

View File

@ -1,520 +0,0 @@
/* nautilusgtkplacesviewrow.c
*
* Copyright (C) 2015 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include "nautilus-application.h"
#include "nautilus-enum-types.h"
#include <gio/gio.h>
#include "nautilusgtkplacesviewrowprivate.h"
/* As this widget is shared with Nautilus, we use this guard to
* ensure that internally we only include the files that we need
* instead of including gtk.h
*/
#ifdef GTK_COMPILATION
#else
#include <gtk/gtk.h>
#endif
struct _NautilusGtkPlacesViewRow
{
GtkListBoxRow parent_instance;
GtkLabel *available_space_label;
GtkStack *mount_stack;
GtkSpinner *busy_spinner;
GtkButton *eject_button;
GtkImage *eject_icon;
GtkImage *icon_image;
GtkLabel *name_label;
GtkLabel *path_label;
GVolume *volume;
GMount *mount;
GFile *file;
GCancellable *cancellable;
int is_network : 1;
};
G_DEFINE_TYPE (NautilusGtkPlacesViewRow, nautilus_gtk_places_view_row, GTK_TYPE_LIST_BOX_ROW)
enum {
PROP_0,
PROP_ICON,
PROP_NAME,
PROP_PATH,
PROP_VOLUME,
PROP_MOUNT,
PROP_FILE,
PROP_IS_NETWORK,
LAST_PROP
};
static GParamSpec *properties [LAST_PROP];
static void
measure_available_space_finished (GObject *object,
GAsyncResult *res,
gpointer user_data)
{
NautilusGtkPlacesViewRow *row = user_data;
GFileInfo *info;
GError *error;
guint64 free_space;
guint64 total_space;
char *formatted_free_size;
char *formatted_total_size;
char *label;
guint plural_form;
error = NULL;
info = g_file_query_filesystem_info_finish (G_FILE (object),
res,
&error);
if (error)
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_MOUNTED))
{
g_warning ("Failed to measure available space: %s", error->message);
}
g_clear_error (&error);
goto out;
}
if (!g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE) ||
!g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE))
{
g_object_unref (info);
goto out;
}
free_space = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
total_space = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE);
formatted_free_size = g_format_size (free_space);
formatted_total_size = g_format_size (total_space);
/* read g_format_size code in glib for further understanding */
plural_form = free_space < 1000 ? free_space : free_space % 1000 + 1000;
/* Translators: respectively, free and total space of the drive. The plural form
* should be based on the free space available.
* i.e. 1 GB / 24 GB available.
*/
label = g_strdup_printf (dngettext (GETTEXT_PACKAGE, "%s / %s available", "%s / %s available", plural_form),
formatted_free_size, formatted_total_size);
gtk_label_set_label (row->available_space_label, label);
g_object_unref (info);
g_free (formatted_total_size);
g_free (formatted_free_size);
g_free (label);
out:
g_object_unref (object);
}
static void
measure_available_space (NautilusGtkPlacesViewRow *row)
{
gboolean skip_measure;
gboolean should_measure;
g_autoptr (GFile) root = NULL;
skip_measure = FALSE;
if (nautilus_application_is_sandboxed ())
{
root = g_file_new_for_uri ("file:///");
if (row->file != NULL)
skip_measure = g_file_equal (root, row->file);
}
should_measure = ((row->volume || row->mount || row->file) &&
!row->is_network && !skip_measure);
gtk_label_set_label (row->available_space_label, "");
gtk_widget_set_visible (GTK_WIDGET (row->available_space_label), should_measure);
if (should_measure)
{
GFile *file = NULL;
if (row->file)
{
file = g_object_ref (row->file);
}
else if (row->mount)
{
file = g_mount_get_root (row->mount);
}
else if (row->volume)
{
GMount *mount;
mount = g_volume_get_mount (row->volume);
if (mount)
file = g_mount_get_root (row->mount);
g_clear_object (&mount);
}
if (file)
{
g_cancellable_cancel (row->cancellable);
g_clear_object (&row->cancellable);
row->cancellable = g_cancellable_new ();
g_file_query_filesystem_info_async (file,
G_FILE_ATTRIBUTE_FILESYSTEM_FREE "," G_FILE_ATTRIBUTE_FILESYSTEM_SIZE,
G_PRIORITY_DEFAULT,
row->cancellable,
measure_available_space_finished,
row);
}
}
}
static void
nautilus_gtk_places_view_row_dispose (GObject *object)
{
NautilusGtkPlacesViewRow *self = NAUTILUS_GTK_PLACES_VIEW_ROW (object);
gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (self), NULL);
gtk_widget_dispose_template (GTK_WIDGET (self), NAUTILUS_TYPE_GTK_PLACES_VIEW_ROW);
G_OBJECT_CLASS (nautilus_gtk_places_view_row_parent_class)->dispose (object);
}
static void
nautilus_gtk_places_view_row_finalize (GObject *object)
{
NautilusGtkPlacesViewRow *self = NAUTILUS_GTK_PLACES_VIEW_ROW (object);
g_cancellable_cancel (self->cancellable);
g_clear_object (&self->volume);
g_clear_object (&self->mount);
g_clear_object (&self->file);
g_clear_object (&self->cancellable);
G_OBJECT_CLASS (nautilus_gtk_places_view_row_parent_class)->finalize (object);
}
static void
nautilus_gtk_places_view_row_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
NautilusGtkPlacesViewRow *self;
self = NAUTILUS_GTK_PLACES_VIEW_ROW (object);
switch (prop_id)
{
case PROP_ICON:
g_value_set_object (value, gtk_image_get_gicon (self->icon_image));
break;
case PROP_NAME:
g_value_set_string (value, gtk_label_get_label (self->name_label));
break;
case PROP_PATH:
g_value_set_string (value, gtk_label_get_label (self->path_label));
break;
case PROP_VOLUME:
g_value_set_object (value, self->volume);
break;
case PROP_MOUNT:
g_value_set_object (value, self->mount);
break;
case PROP_FILE:
g_value_set_object (value, self->file);
break;
case PROP_IS_NETWORK:
g_value_set_boolean (value, self->is_network);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
nautilus_gtk_places_view_row_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
NautilusGtkPlacesViewRow *self = NAUTILUS_GTK_PLACES_VIEW_ROW (object);
switch (prop_id)
{
case PROP_ICON:
gtk_image_set_from_gicon (self->icon_image, g_value_get_object (value));
break;
case PROP_NAME:
gtk_label_set_label (self->name_label, g_value_get_string (value));
break;
case PROP_PATH:
gtk_label_set_label (self->path_label, g_value_get_string (value));
break;
case PROP_VOLUME:
g_set_object (&self->volume, g_value_get_object (value));
break;
case PROP_MOUNT:
g_set_object (&self->mount, g_value_get_object (value));
if (self->mount != NULL)
{
gtk_stack_set_visible_child (self->mount_stack, GTK_WIDGET (self->eject_button));
gtk_widget_set_child_visible (GTK_WIDGET (self->mount_stack), TRUE);
}
else
{
gtk_widget_set_child_visible (GTK_WIDGET (self->mount_stack), FALSE);
}
measure_available_space (self);
break;
case PROP_FILE:
g_set_object (&self->file, g_value_get_object (value));
measure_available_space (self);
break;
case PROP_IS_NETWORK:
nautilus_gtk_places_view_row_set_is_network (self, g_value_get_boolean (value));
measure_available_space (self);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
nautilus_gtk_places_view_row_size_allocate (GtkWidget *widget,
int width,
int height,
int baseline)
{
GtkWidget *menu = GTK_WIDGET (g_object_get_data (G_OBJECT (widget), "menu"));
GTK_WIDGET_CLASS (nautilus_gtk_places_view_row_parent_class)->size_allocate (widget, width, height, baseline);
if (menu)
gtk_popover_present (GTK_POPOVER (menu));
}
static void
nautilus_gtk_places_view_row_class_init (NautilusGtkPlacesViewRowClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = nautilus_gtk_places_view_row_dispose;
object_class->finalize = nautilus_gtk_places_view_row_finalize;
object_class->get_property = nautilus_gtk_places_view_row_get_property;
object_class->set_property = nautilus_gtk_places_view_row_set_property;
widget_class->size_allocate = nautilus_gtk_places_view_row_size_allocate;
properties[PROP_ICON] =
g_param_spec_object ("icon",
"Icon of the row",
"The icon representing the volume",
G_TYPE_ICON,
G_PARAM_READWRITE);
properties[PROP_NAME] =
g_param_spec_string ("name",
"Name of the volume",
"The name of the volume",
"",
G_PARAM_READWRITE);
properties[PROP_PATH] =
g_param_spec_string ("path",
"Path of the volume",
"The path of the volume",
"",
G_PARAM_READWRITE);
properties[PROP_VOLUME] =
g_param_spec_object ("volume",
"Volume represented by the row",
"The volume represented by the row",
G_TYPE_VOLUME,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_MOUNT] =
g_param_spec_object ("mount",
"Mount represented by the row",
"The mount point represented by the row, if any",
G_TYPE_MOUNT,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_FILE] =
g_param_spec_object ("file",
"File represented by the row",
"The file represented by the row, if any",
G_TYPE_FILE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_IS_NETWORK] =
g_param_spec_boolean ("is-network",
"Whether the row represents a network location",
"Whether the row represents a network location",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, LAST_PROP, properties);
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/nautilus/gtk/ui/nautilusgtkplacesviewrow.ui");
gtk_widget_class_bind_template_child (widget_class, NautilusGtkPlacesViewRow, available_space_label);
gtk_widget_class_bind_template_child (widget_class, NautilusGtkPlacesViewRow, mount_stack);
gtk_widget_class_bind_template_child (widget_class, NautilusGtkPlacesViewRow, busy_spinner);
gtk_widget_class_bind_template_child (widget_class, NautilusGtkPlacesViewRow, eject_button);
gtk_widget_class_bind_template_child (widget_class, NautilusGtkPlacesViewRow, eject_icon);
gtk_widget_class_bind_template_child (widget_class, NautilusGtkPlacesViewRow, icon_image);
gtk_widget_class_bind_template_child (widget_class, NautilusGtkPlacesViewRow, name_label);
gtk_widget_class_bind_template_child (widget_class, NautilusGtkPlacesViewRow, path_label);
}
static void
nautilus_gtk_places_view_row_init (NautilusGtkPlacesViewRow *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
}
GtkWidget*
nautilus_gtk_places_view_row_new (GVolume *volume,
GMount *mount)
{
return g_object_new (NAUTILUS_TYPE_GTK_PLACES_VIEW_ROW,
"volume", volume,
"mount", mount,
NULL);
}
GMount*
nautilus_gtk_places_view_row_get_mount (NautilusGtkPlacesViewRow *row)
{
g_return_val_if_fail (NAUTILUS_IS_GTK_PLACES_VIEW_ROW (row), NULL);
return row->mount;
}
GVolume*
nautilus_gtk_places_view_row_get_volume (NautilusGtkPlacesViewRow *row)
{
g_return_val_if_fail (NAUTILUS_IS_GTK_PLACES_VIEW_ROW (row), NULL);
return row->volume;
}
GFile*
nautilus_gtk_places_view_row_get_file (NautilusGtkPlacesViewRow *row)
{
g_return_val_if_fail (NAUTILUS_IS_GTK_PLACES_VIEW_ROW (row), NULL);
return row->file;
}
GtkWidget*
nautilus_gtk_places_view_row_get_eject_button (NautilusGtkPlacesViewRow *row)
{
g_return_val_if_fail (NAUTILUS_IS_GTK_PLACES_VIEW_ROW (row), NULL);
return GTK_WIDGET (row->eject_button);
}
void
nautilus_gtk_places_view_row_set_busy (NautilusGtkPlacesViewRow *row,
gboolean is_busy)
{
g_return_if_fail (NAUTILUS_IS_GTK_PLACES_VIEW_ROW (row));
if (is_busy)
{
gtk_stack_set_visible_child (row->mount_stack, GTK_WIDGET (row->busy_spinner));
gtk_widget_set_child_visible (GTK_WIDGET (row->mount_stack), TRUE);
gtk_spinner_start (row->busy_spinner);
}
else
{
gtk_widget_set_child_visible (GTK_WIDGET (row->mount_stack), FALSE);
gtk_spinner_stop (row->busy_spinner);
}
}
gboolean
nautilus_gtk_places_view_row_get_is_network (NautilusGtkPlacesViewRow *row)
{
g_return_val_if_fail (NAUTILUS_IS_GTK_PLACES_VIEW_ROW (row), FALSE);
return row->is_network;
}
void
nautilus_gtk_places_view_row_set_is_network (NautilusGtkPlacesViewRow *row,
gboolean is_network)
{
if (row->is_network != is_network)
{
row->is_network = is_network;
gtk_image_set_from_icon_name (row->eject_icon, "media-eject-symbolic");
gtk_widget_set_tooltip_text (GTK_WIDGET (row->eject_button), is_network ? _("Disconnect") : _("Unmount"));
}
}
void
nautilus_gtk_places_view_row_set_path_size_group (NautilusGtkPlacesViewRow *row,
GtkSizeGroup *group)
{
if (group)
gtk_size_group_add_widget (group, GTK_WIDGET (row->path_label));
}
void
nautilus_gtk_places_view_row_set_space_size_group (NautilusGtkPlacesViewRow *row,
GtkSizeGroup *group)
{
if (group)
gtk_size_group_add_widget (group, GTK_WIDGET (row->available_space_label));
}

View File

@ -1,83 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="NautilusGtkPlacesViewRow" parent="GtkListBoxRow">
<property name="width-request">100</property>
<property name="child">
<object class="GtkBox" id="box">
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<property name="margin-top">6</property>
<property name="margin-bottom">6</property>
<property name="spacing">18</property>
<child>
<object class="GtkImage" id="icon_image">
<property name="pixel-size">32</property>
</object>
</child>
<child>
<object class="GtkLabel" id="name_label">
<property name="hexpand">1</property>
<property name="xalign">0</property>
<property name="ellipsize">3</property>
</object>
</child>
<child>
<object class="GtkLabel" id="available_space_label">
<property name="xalign">1</property>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel" id="path_label">
<property name="justify">1</property>
<property name="ellipsize">2</property>
<property name="xalign">0</property>
<property name="max-width-chars">15</property>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
<child>
<object class="GtkStack" id="mount_stack">
<child>
<object class="GtkStackPage">
<property name="name">button</property>
<property name="child">
<object class="GtkButton" id="eject_button">
<property name="visible">0</property>
<property name="halign">3</property>
<property name="valign">3</property>
<property name="tooltip-text" translatable="yes">Unmount</property>
<child>
<object class="GtkImage" id="eject_icon">
<property name="icon-name">media-eject-symbolic</property>
</object>
</child>
<style>
<class name="image-button"/>
<class name="sidebar-button"/>
</style>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">spinner</property>
<property name="child">
<object class="GtkSpinner" id="busy_spinner">
<property name="halign">3</property>
<property name="valign">3</property>
</object>
</property>
</object>
</child>
</object>
</child>
</object>
</property>
</template>
</interface>

View File

@ -1,59 +0,0 @@
/* nautilusgtkplacesviewrow.h
*
* Copyright (C) 2015 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NAUTILUS_GTK_PLACES_VIEW_ROW_H
#define NAUTILUS_GTK_PLACES_VIEW_ROW_H
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#endif
G_BEGIN_DECLS
#define NAUTILUS_TYPE_GTK_PLACES_VIEW_ROW (nautilus_gtk_places_view_row_get_type())
G_DECLARE_FINAL_TYPE (NautilusGtkPlacesViewRow, nautilus_gtk_places_view_row, NAUTILUS, GTK_PLACES_VIEW_ROW, GtkListBoxRow)
GtkWidget* nautilus_gtk_places_view_row_new (GVolume *volume,
GMount *mount);
GtkWidget* nautilus_gtk_places_view_row_get_eject_button (NautilusGtkPlacesViewRow *row);
GMount* nautilus_gtk_places_view_row_get_mount (NautilusGtkPlacesViewRow *row);
GVolume* nautilus_gtk_places_view_row_get_volume (NautilusGtkPlacesViewRow *row);
GFile* nautilus_gtk_places_view_row_get_file (NautilusGtkPlacesViewRow *row);
void nautilus_gtk_places_view_row_set_busy (NautilusGtkPlacesViewRow *row,
gboolean is_busy);
gboolean nautilus_gtk_places_view_row_get_is_network (NautilusGtkPlacesViewRow *row);
void nautilus_gtk_places_view_row_set_is_network (NautilusGtkPlacesViewRow *row,
gboolean is_network);
void nautilus_gtk_places_view_row_set_path_size_group (NautilusGtkPlacesViewRow *row,
GtkSizeGroup *group);
void nautilus_gtk_places_view_row_set_space_size_group (NautilusGtkPlacesViewRow *row,
GtkSizeGroup *group);
G_END_DECLS
#endif /* NAUTILUS_GTK_PLACES_VIEW_ROW_H */

View File

@ -336,8 +336,7 @@ nautilus_gtk_sidebar_row_set_property (GObject *object,
case PROP_SECTION_TYPE:
self->section_type = g_value_get_enum (value);
if (self->section_type == NAUTILUS_GTK_PLACES_SECTION_COMPUTER ||
self->section_type == NAUTILUS_GTK_PLACES_SECTION_OTHER_LOCATIONS)
if (self->section_type == NAUTILUS_GTK_PLACES_SECTION_DEFAULT_LOCATIONS)
gtk_label_set_ellipsize (GTK_LABEL (self->label_widget), PANGO_ELLIPSIZE_NONE);
else
gtk_label_set_ellipsize (GTK_LABEL (self->label_widget), PANGO_ELLIPSIZE_END);

View File

@ -55,16 +55,10 @@ libnautilus_sources = [
interface_prefix: 'org.gnome',
namespace: 'Nautilus'
),
'gtk/nautilusgtkbookmarksmanager.c',
'gtk/nautilusgtkbookmarksmanagerprivate.h',
'gtk/nautilusgtkplacessidebar.c',
'gtk/nautilusgtkplacessidebarprivate.h',
'gtk/nautilusgtksidebarrow.c',
'gtk/nautilusgtksidebarrowprivate.h',
'gtk/nautilusgtkplacesview.c',
'gtk/nautilusgtkplacesviewprivate.h',
'gtk/nautilusgtkplacesviewrow.c',
'gtk/nautilusgtkplacesviewrowprivate.h',
'nautilus-application.c',
'nautilus-application.h',
'nautilus-app-chooser.c',
@ -108,8 +102,6 @@ libnautilus_sources = [
'nautilus-name-cell.h',
'nautilus-pathbar.c',
'nautilus-pathbar.h',
'nautilus-places-view.c',
'nautilus-places-view.h',
'nautilus-previewer.c',
'nautilus-previewer.h',
'nautilus-progress-indicator.c',
@ -173,6 +165,14 @@ libnautilus_sources = [
'nautilus-filename-validator.h',
'nautilus-rename-file-popover.c',
'nautilus-rename-file-popover.h',
'nautilus-network-address-bar.c',
'nautilus-network-address-bar.h',
'nautilus-network-cell.c',
'nautilus-network-cell.h',
'nautilus-network-directory.c',
'nautilus-network-directory.h',
'nautilus-network-view.c',
'nautilus-network-view.h',
'nautilus-new-folder-dialog.c',
'nautilus-new-folder-dialog.h',
'nautilus-compress-dialog.c',
@ -197,6 +197,8 @@ libnautilus_sources = [
'nautilus-icon-info.c',
'nautilus-icon-info.h',
'nautilus-icon-names.h',
'nautilus-internal-place-file.c',
'nautilus-internal-place-file.h',
'nautilus-keyfile-metadata.c',
'nautilus-keyfile-metadata.h',
'nautilus-metadata.h',
@ -213,6 +215,8 @@ libnautilus_sources = [
'nautilus-progress-paintable.h',
'nautilus-program-choosing.c',
'nautilus-program-choosing.h',
'nautilus-recent-servers.c',
'nautilus-recent-servers.h',
'nautilus-search-directory.c',
'nautilus-search-directory.h',
'nautilus-search-directory-file.c',
@ -229,6 +233,8 @@ libnautilus_sources = [
'nautilus-search-engine-simple.h',
'nautilus-search-hit.c',
'nautilus-search-hit.h',
'nautilus-shortcut-manager.c',
'nautilus-shortcut-manager.h',
'nautilus-signaller.h',
'nautilus-signaller.c',
'nautilus-query.c',

View File

@ -288,7 +288,6 @@ get_window_slot_for_location (NautilusApplication *self,
if (file != NULL &&
!nautilus_file_is_directory (file) &&
!nautilus_file_is_other_locations (file) &&
g_file_has_parent (location, NULL))
{
searched_location = g_file_get_parent (location);
@ -317,6 +316,13 @@ get_window_slot_for_location (NautilusApplication *self,
return NULL;
}
static NautilusWindow *
get_nautilus_window_containing_slot (NautilusWindowSlot *slot)
{
return NAUTILUS_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (slot),
NAUTILUS_TYPE_WINDOW));
}
void
nautilus_application_open_location_full (NautilusApplication *self,
GFile *location,
@ -391,7 +397,7 @@ real_open_location_full (NautilusApplication *self,
* slot we target at */
if (target_slot != NULL)
{
target_window = nautilus_window_slot_get_window (target_slot);
target_window = get_nautilus_window_containing_slot (target_slot);
}
g_assert (!((flags & NAUTILUS_OPEN_FLAG_NEW_WINDOW) != 0 &&
@ -414,7 +420,7 @@ real_open_location_full (NautilusApplication *self,
}
else
{
target_window = nautilus_window_slot_get_window (target_slot);
target_window = get_nautilus_window_containing_slot (target_slot);
}
}
}
@ -483,7 +489,7 @@ nautilus_application_open_location (NautilusApplication *self,
}
else
{
window = nautilus_window_slot_get_window (slot);
window = get_nautilus_window_containing_slot (slot);
}
nautilus_application_open_location_full (self, location, 0, sel_list, window, slot);

View File

@ -36,7 +36,7 @@ struct _NautilusBatchRenameDialog
GtkDialog parent;
GtkWidget *grid;
NautilusWindow *window;
GtkRoot *window;
GtkWidget *cancel_button;
GtkWidget *original_name_listbox;
@ -1824,7 +1824,7 @@ nautilus_batch_rename_dialog_class_init (NautilusBatchRenameDialogClass *klass)
GtkWidget *
nautilus_batch_rename_dialog_new (GList *selection,
NautilusDirectory *directory,
NautilusWindow *window)
GtkRoot *window)
{
NautilusBatchRenameDialog *dialog;
GString *dialog_title;

View File

@ -223,7 +223,7 @@ G_DECLARE_FINAL_TYPE (NautilusBatchRenameDialog, nautilus_batch_rename_dialog, N
GtkWidget* nautilus_batch_rename_dialog_new (GList *selection,
NautilusDirectory *directory,
NautilusWindow *window);
GtkRoot *window);
void nautilus_batch_rename_dialog_query_finished (NautilusBatchRenameDialog *dialog,
GHashTable *hash_table,

View File

@ -939,10 +939,7 @@ on_cursor_callback (GObject *object,
break;
}
/* TODO: Figure out how to inform the user of why the metadata is
* unavailable when one or more contains the unallowed character "/"
*/
if (!current_metadata || g_strrstr (current_metadata, "/"))
if (!current_metadata)
{
remove_metadata (query_data,
metadata_type);
@ -975,6 +972,7 @@ on_cursor_callback (GObject *object,
else
{
file_metadata->metadata[metadata_type] = g_string_new (current_metadata);
g_string_replace (file_metadata->metadata[metadata_type], "/", "_", 0);
}
}
}

View File

@ -86,18 +86,6 @@ new_bookmark_from_uri (const char *uri,
return new_bookmark;
}
static GFile *
nautilus_bookmark_list_get_legacy_file (void)
{
g_autofree char *filename = NULL;
filename = g_build_filename (g_get_home_dir (),
".gtk-bookmarks",
NULL);
return g_file_new_for_path (filename);
}
static GFile *
nautilus_bookmark_list_get_file (void)
{
@ -125,14 +113,19 @@ bookmark_in_list_changed_callback (NautilusBookmark *bookmark,
}
static void
bookmark_in_list_notify (GObject *object,
GParamSpec *pspec,
NautilusBookmarkList *bookmarks)
bookmark_in_list_icon_changed (NautilusBookmarkList *bookmarks)
{
/* emit the changed signal without saving, as only appearance properties changed */
g_signal_emit (bookmarks, signals[CHANGED], 0);
}
static void
bookmark_in_list_name_changed (NautilusBookmarkList *bookmarks)
{
nautilus_bookmark_list_save_file (bookmarks);
g_signal_emit (bookmarks, signals[CHANGED], 0);
}
static void
stop_monitoring_bookmark (NautilusBookmarkList *bookmarks,
NautilusBookmark *bookmark)
@ -238,9 +231,9 @@ insert_bookmark_internal (NautilusBookmarkList *bookmarks,
g_signal_connect_object (bookmark, "contents-changed",
G_CALLBACK (bookmark_in_list_changed_callback), bookmarks, 0);
g_signal_connect_object (bookmark, "notify::icon",
G_CALLBACK (bookmark_in_list_notify), bookmarks, 0);
G_CALLBACK (bookmark_in_list_icon_changed), bookmarks, G_CONNECT_SWAPPED);
g_signal_connect_object (bookmark, "notify::name",
G_CALLBACK (bookmark_in_list_notify), bookmarks, 0);
G_CALLBACK (bookmark_in_list_name_changed), bookmarks, G_CONNECT_SWAPPED);
}
/**
@ -314,6 +307,176 @@ nautilus_bookmark_list_append (NautilusBookmarkList *bookmarks,
nautilus_bookmark_list_save_file (bookmarks);
}
/**
* nautilus_bookmark_list_contains:
*
* Check whether a bookmark with matching name and url is already in the list.
* @bookmarks: NautilusBookmarkList to check contents of.
* @bookmark: NautilusBookmark to match against.
*
* Return value: TRUE if matching bookmark is in list, FALSE otherwise
**/
gboolean
nautilus_bookmark_list_contains (NautilusBookmarkList *bookmarks,
NautilusBookmark *bookmark)
{
g_return_val_if_fail (NAUTILUS_IS_BOOKMARK_LIST (bookmarks), FALSE);
g_return_val_if_fail (NAUTILUS_IS_BOOKMARK (bookmark), FALSE);
return g_list_find_custom (bookmarks->list,
(gpointer) bookmark,
nautilus_bookmark_compare_with) != NULL;
}
/**
* nautilus_bookmark_list_delete_item_at:
*
* Delete the bookmark at the specified position.
* @bookmarks: the list of bookmarks.
* @index: index, must be less than length of list.
**/
void
nautilus_bookmark_list_delete_item_at (NautilusBookmarkList *bookmarks,
guint index)
{
g_return_if_fail (NAUTILUS_IS_BOOKMARK_LIST (bookmarks));
g_return_if_fail (index < g_list_length (bookmarks->list));
GList *doomed = g_list_nth (bookmarks->list, index);
g_assert (NAUTILUS_IS_BOOKMARK (doomed->data));
stop_monitoring_bookmark (bookmarks, NAUTILUS_BOOKMARK (doomed->data));
g_object_unref (doomed->data);
bookmarks->list = g_list_delete_link (bookmarks->list, doomed);
nautilus_bookmark_list_save_file (bookmarks);
}
/**
* nautilus_bookmark_list_move_item:
*
* Move the item from the given position to the destination.
* @index: the index of the first bookmark.
* @destination: the index of the second bookmark.
**/
void
nautilus_bookmark_list_move_item (NautilusBookmarkList *bookmarks,
guint index,
guint destination)
{
if (index == destination)
{
return;
}
GList *link_to_move = g_list_nth (bookmarks->list, index);
bookmarks->list = g_list_remove_link (bookmarks->list,
link_to_move);
GList *link_at_destination = g_list_nth (bookmarks->list, destination);
/* NULL link at destination means end of the list */
bookmarks->list = g_list_insert_before_link (bookmarks->list,
link_at_destination,
link_to_move);
nautilus_bookmark_list_save_file (bookmarks);
}
/**
* nautilus_bookmark_list_delete_items_with_uri:
*
* Delete all bookmarks with the given uri.
* @bookmarks: the list of bookmarks.
* @uri: The uri to match.
**/
void
nautilus_bookmark_list_delete_items_with_uri (NautilusBookmarkList *bookmarks,
const char *uri)
{
g_return_if_fail (NAUTILUS_IS_BOOKMARK_LIST (bookmarks));
g_return_if_fail (uri != NULL);
gboolean list_changed = FALSE;
GList *next = NULL;
for (GList *node = bookmarks->list; node != NULL; node = next)
{
next = node->next;
g_autofree char *bookmark_uri = nautilus_bookmark_get_uri (NAUTILUS_BOOKMARK (node->data));
if (g_strcmp0 (bookmark_uri, uri) == 0)
{
stop_monitoring_bookmark (bookmarks, NAUTILUS_BOOKMARK (node->data));
g_object_unref (node->data);
bookmarks->list = g_list_delete_link (bookmarks->list, node);
list_changed = TRUE;
}
}
if (list_changed)
{
nautilus_bookmark_list_save_file (bookmarks);
}
}
/**
* nautilus_bookmark_list_insert_item:
*
* Insert a bookmark at a specified position.
* @bookmarks: the list of bookmarks.
* @index: the position to insert the bookmark at.
* @new_bookmark: the bookmark to insert a copy of.
**/
void
nautilus_bookmark_list_insert_item (NautilusBookmarkList *bookmarks,
NautilusBookmark *new_bookmark,
guint index)
{
g_return_if_fail (NAUTILUS_IS_BOOKMARK_LIST (bookmarks));
g_return_if_fail (index <= g_list_length (bookmarks->list));
insert_bookmark_internal (bookmarks, g_object_ref (new_bookmark), index);
nautilus_bookmark_list_save_file (bookmarks);
}
/**
* nautilus_bookmark_list_item_at:
*
* Get the bookmark at the specified position.
* @bookmarks: the list of bookmarks.
* @index: index, must be less than length of list.
*
* Return value: the bookmark at position @index in @bookmarks.
**/
NautilusBookmark *
nautilus_bookmark_list_item_at (NautilusBookmarkList *bookmarks,
guint index)
{
g_return_val_if_fail (NAUTILUS_IS_BOOKMARK_LIST (bookmarks), NULL);
g_return_val_if_fail (index < g_list_length (bookmarks->list), NULL);
return NAUTILUS_BOOKMARK (g_list_nth_data (bookmarks->list, index));
}
/**
* nautilus_bookmark_list_length:
*
* Get the number of bookmarks in the list.
* @bookmarks: the list of bookmarks.
*
* Return value: the length of the bookmark list.
**/
guint
nautilus_bookmark_list_length (NautilusBookmarkList *bookmarks)
{
g_return_val_if_fail (NAUTILUS_IS_BOOKMARK_LIST (bookmarks), 0);
return g_list_length (bookmarks->list);
}
static void
process_next_op (NautilusBookmarkList *bookmarks);
@ -388,11 +551,6 @@ load_io_thread (GTask *task,
GError *error = NULL;
file = nautilus_bookmark_list_get_file ();
if (!g_file_query_exists (file, NULL))
{
g_object_unref (file);
file = nautilus_bookmark_list_get_legacy_file ();
}
g_file_load_contents (file, NULL, &contents, NULL, NULL, &error);
g_object_unref (file);
@ -612,8 +770,6 @@ gboolean
nautilus_bookmark_list_can_bookmark_location (NautilusBookmarkList *list,
GFile *location)
{
g_autoptr (NautilusBookmark) bookmark = NULL;
if (nautilus_bookmark_list_item_with_location (list, location, NULL))
{
/* Already bookmarked */
@ -628,15 +784,13 @@ nautilus_bookmark_list_can_bookmark_location (NautilusBookmarkList *list,
if (g_file_has_uri_scheme (location, SCHEME_RECENT) ||
g_file_has_uri_scheme (location, SCHEME_STARRED) ||
nautilus_is_home_directory (location) ||
g_file_has_uri_scheme (location, SCHEME_TRASH) ||
g_file_has_uri_scheme (location, SCHEME_OTHER_LOCATIONS))
g_file_has_uri_scheme (location, SCHEME_TRASH))
{
/* Already in the sidebar */
return FALSE;
}
bookmark = nautilus_bookmark_new (location, NULL);
return !nautilus_bookmark_get_is_builtin (bookmark);
return TRUE;
}
/**

View File

@ -43,5 +43,19 @@ NautilusBookmark * nautilus_bookmark_list_item_with_location (NautilusBook
gboolean nautilus_bookmark_list_can_bookmark_location (NautilusBookmarkList *list,
GFile *location);
GList * nautilus_bookmark_list_get_all (NautilusBookmarkList *bookmarks);
gboolean nautilus_bookmark_list_contains (NautilusBookmarkList *bookmarks,
NautilusBookmark *bookmark);
void nautilus_bookmark_list_delete_item_at (NautilusBookmarkList *bookmarks,
guint index);
void nautilus_bookmark_list_delete_items_with_uri (NautilusBookmarkList *bookmarks,
const char *uri);
void nautilus_bookmark_list_insert_item (NautilusBookmarkList *bookmarks,
NautilusBookmark *bookmark,
guint index);
guint nautilus_bookmark_list_length (NautilusBookmarkList *bookmarks);
NautilusBookmark * nautilus_bookmark_list_item_at (NautilusBookmarkList *bookmarks,
guint index);
void nautilus_bookmark_list_move_item (NautilusBookmarkList *bookmarks,
guint index,
guint destination);
G_END_DECLS

View File

@ -75,12 +75,19 @@ static void nautilus_bookmark_disconnect_file (NautilusBookmark *file);
G_DEFINE_TYPE (NautilusBookmark, nautilus_bookmark, G_TYPE_OBJECT);
static void
nautilus_bookmark_set_name_internal (NautilusBookmark *bookmark,
const char *new_name)
void
nautilus_bookmark_set_name (NautilusBookmark *bookmark,
const char *new_name)
{
if (g_set_str (&bookmark->name, new_name))
{
if ((new_name == NULL && bookmark->has_custom_name) ||
(new_name != NULL && !bookmark->has_custom_name))
{
bookmark->has_custom_name = !bookmark->has_custom_name;
g_object_notify_by_pspec (G_OBJECT (bookmark), properties[PROP_CUSTOM_NAME]);
}
g_object_notify_by_pspec (G_OBJECT (bookmark), properties[PROP_NAME]);
}
}
@ -98,17 +105,13 @@ bookmark_set_name_from_ready_file (NautilusBookmark *self,
display_name = nautilus_file_get_display_name (self->file);
if (nautilus_file_is_other_locations (self->file))
if (nautilus_file_is_home (self->file))
{
nautilus_bookmark_set_name_internal (self, _("Other Locations"));
}
else if (nautilus_file_is_home (self->file))
{
nautilus_bookmark_set_name_internal (self, _("Home"));
nautilus_bookmark_set_name (self, _("Home"));
}
else if (g_strcmp0 (self->name, display_name) != 0)
{
nautilus_bookmark_set_name_internal (self, display_name);
nautilus_bookmark_set_name (self, display_name);
g_debug ("%s: name changed to %s", nautilus_bookmark_get_name (self), display_name);
}
}
@ -162,103 +165,59 @@ bookmark_file_changed_callback (NautilusFile *file,
}
}
gboolean
nautilus_bookmark_get_is_builtin (NautilusBookmark *bookmark)
{
GUserDirectory xdg_type;
/* if this is not an XDG dir, it's never builtin */
if (!nautilus_bookmark_get_xdg_type (bookmark, &xdg_type))
{
return FALSE;
}
/* exclude XDG locations which are not in our builtin list */
return (xdg_type != G_USER_DIRECTORY_DESKTOP) &&
(xdg_type != G_USER_DIRECTORY_TEMPLATES) &&
(xdg_type != G_USER_DIRECTORY_PUBLIC_SHARE);
}
gboolean
static gboolean
nautilus_bookmark_get_xdg_type (NautilusBookmark *bookmark,
GUserDirectory *directory)
{
gboolean match;
GFile *location;
const gchar *path;
GUserDirectory dir;
match = FALSE;
for (dir = 0; dir < G_USER_N_DIRECTORIES; dir++)
for (GUserDirectory dir = 0; dir < G_USER_N_DIRECTORIES; dir++)
{
path = g_get_user_special_dir (dir);
if (!path)
const gchar *path = g_get_user_special_dir (dir);
if (path == NULL)
{
continue;
}
location = g_file_new_for_path (path);
match = g_file_equal (location, bookmark->location);
g_object_unref (location);
g_autoptr (GFile) location = g_file_new_for_path (path);
if (match)
if (g_file_equal (location, bookmark->location))
{
break;
if (directory != NULL)
{
*directory = dir;
}
return TRUE;
}
}
if (match && directory != NULL)
{
*directory = dir;
}
return match;
return FALSE;
}
static GIcon *
get_native_icon (NautilusBookmark *bookmark,
gboolean symbolic)
{
if (!bookmark->exists)
{
g_debug ("%s: file does not exist, set warning icon", nautilus_bookmark_get_name (bookmark));
return g_themed_icon_new (symbolic ? "dialog-warning-symbolic" : "dialog-warning");
}
GUserDirectory xdg_type;
GIcon *icon = NULL;
if (bookmark->file == NULL)
{
goto out;
}
if (!nautilus_bookmark_get_xdg_type (bookmark, &xdg_type))
{
goto out;
}
if (xdg_type < G_USER_N_DIRECTORIES)
if (nautilus_bookmark_get_xdg_type (bookmark, &xdg_type))
{
if (symbolic)
{
icon = nautilus_special_directory_get_symbolic_icon (xdg_type);
return nautilus_special_directory_get_symbolic_icon (xdg_type);
}
else
{
icon = nautilus_special_directory_get_icon (xdg_type);
return nautilus_special_directory_get_icon (xdg_type);
}
}
out:
if (icon == NULL)
{
if (symbolic)
{
icon = g_themed_icon_new (NAUTILUS_ICON_FOLDER);
}
else
{
icon = g_themed_icon_new (NAUTILUS_ICON_FULLCOLOR_FOLDER);
}
}
return icon;
return g_themed_icon_new (symbolic ? NAUTILUS_ICON_FOLDER : NAUTILUS_ICON_FULLCOLOR_FOLDER);
}
static void
@ -267,13 +226,7 @@ nautilus_bookmark_set_icon_to_default (NautilusBookmark *bookmark)
g_autoptr (GIcon) icon = NULL;
g_autoptr (GIcon) symbolic_icon = NULL;
if (!bookmark->exists)
{
g_debug ("%s: file does not exist, set warning icon", nautilus_bookmark_get_name (bookmark));
symbolic_icon = g_themed_icon_new ("dialog-warning-symbolic");
icon = g_themed_icon_new ("dialog-warning");
}
else if (g_file_is_native (bookmark->location))
if (g_file_is_native (bookmark->location))
{
symbolic_icon = get_native_icon (bookmark, TRUE);
icon = get_native_icon (bookmark, FALSE);
@ -489,7 +442,7 @@ nautilus_bookmark_set_property (GObject *object,
case PROP_NAME:
{
nautilus_bookmark_set_name_internal (self, g_value_get_string (value));
nautilus_bookmark_set_name (self, g_value_get_string (value));
}
break;
@ -603,7 +556,7 @@ nautilus_bookmark_class_init (NautilusBookmarkClass *class)
"Bookmark's name",
"The name of this bookmark",
NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY);
properties[PROP_CUSTOM_NAME] =
g_param_spec_boolean ("custom-name",

View File

@ -40,9 +40,6 @@ GFile * nautilus_bookmark_get_location (NautilusBookmark
char * nautilus_bookmark_get_uri (NautilusBookmark *bookmark);
GIcon * nautilus_bookmark_get_icon (NautilusBookmark *bookmark);
GIcon * nautilus_bookmark_get_symbolic_icon (NautilusBookmark *bookmark);
gboolean nautilus_bookmark_get_xdg_type (NautilusBookmark *bookmark,
GUserDirectory *directory);
gboolean nautilus_bookmark_get_is_builtin (NautilusBookmark *bookmark);
gboolean nautilus_bookmark_get_has_custom_name (NautilusBookmark *bookmark);
int nautilus_bookmark_compare_with (gconstpointer a,
gconstpointer b);
@ -50,5 +47,7 @@ int nautilus_bookmark_compare_with (gconstpointer
void nautilus_bookmark_take_selected_uris (NautilusBookmark *bookmark,
GStrv selected_uris);
GStrv nautilus_bookmark_get_selected_uris (NautilusBookmark *bookmark);
void nautilus_bookmark_set_name (NautilusBookmark *bookmark,
const char *new_name);
G_END_DECLS

View File

@ -33,9 +33,6 @@
#include "nautilus-hash-queue.h"
#include "nautilus-metadata.h"
#include "nautilus-scheme.h"
#include "nautilus-search-directory-file.h"
#include "nautilus-search-directory.h"
#include "nautilus-starred-directory.h"
#include "nautilus-vfs-directory.h"
#include "nautilus-vfs-file.h"
@ -124,32 +121,9 @@ real_new_file_from_filename (NautilusDirectory *directory,
const char *filename,
gboolean self_owned)
{
NautilusFile *file;
g_assert (NAUTILUS_IS_DIRECTORY (directory));
g_assert (filename != NULL);
g_assert (filename[0] != '\0');
if (NAUTILUS_IS_SEARCH_DIRECTORY (directory))
{
if (self_owned)
{
file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_SEARCH_DIRECTORY_FILE, NULL));
}
else
{
/* This doesn't normally happen, unless the user somehow types in a uri
* that references a file like this. (See #349840) */
file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_VFS_FILE, NULL));
}
}
else
{
file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_VFS_FILE, NULL));
}
nautilus_file_set_directory (file, directory);
return file;
return NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_VFS_FILE,
"directory", directory,
NULL));
}
static gboolean
@ -687,6 +661,10 @@ nautilus_directory_new_file_from_filename (NautilusDirectory *directory,
const char *filename,
gboolean self_owned)
{
g_assert (NAUTILUS_IS_DIRECTORY (directory));
g_assert (filename != NULL);
g_assert (filename[0] != '\0');
return NAUTILUS_DIRECTORY_CLASS (G_OBJECT_GET_CLASS (directory))->new_file_from_filename (directory,
filename,
self_owned);

View File

@ -271,6 +271,11 @@ nautilus_fd_holders_release_for_mount (GMount *mount)
GFile *location;
GFileEnumerator *enumerator;
if (G_UNLIKELY (location_enumerator_map == NULL))
{
return;
}
g_hash_table_iter_init (&iter, location_enumerator_map);
while (g_hash_table_iter_next (&iter, (gpointer *) &location, (gpointer *) &enumerator))
{

View File

@ -116,7 +116,7 @@ typedef struct
char *filename;
gboolean make_dir;
GFile *src;
char *src_data;
void *src_data;
int length;
gboolean new_mtime;
GFile *created_file;
@ -7118,7 +7118,7 @@ create_task_thread_func (GTask *task,
gboolean filename_is_utf8;
char *primary, *secondary, *details;
int response;
char *data;
void *data;
gsize length;
GFileOutputStream *out;
gboolean handled_invalid_filename;
@ -7222,7 +7222,7 @@ retry:
res = g_file_copy (job->src,
dest,
G_FILE_COPY_TARGET_DEFAULT_PERMS |
job->new_mtime ? G_FILE_COPY_TARGET_DEFAULT_MODIFIED_TIME : 0,
(job->new_mtime ? G_FILE_COPY_TARGET_DEFAULT_MODIFIED_TIME : 0),
common->cancellable,
NULL, NULL,
&error);
@ -7254,7 +7254,7 @@ retry:
}
else
{
data = "";
data = NULL;
length = 0;
if (job->src_data)
{
@ -7694,7 +7694,7 @@ void
nautilus_file_operations_new_file (GtkWidget *parent_view,
const char *parent_dir,
const char *target_filename,
const char *initial_contents,
const void *initial_contents,
gsize length,
NautilusCreateCallback done_callback,
gpointer done_callback_data)

View File

@ -68,7 +68,7 @@ void nautilus_file_operations_new_folder (GtkWidget *paren
void nautilus_file_operations_new_file (GtkWidget *parent_view,
const char *parent_dir,
const char *target_filename,
const char *initial_contents,
const void *initial_contents,
gsize length,
NautilusCreateCallback done_callback,
gpointer data);

View File

@ -805,9 +805,13 @@ struct _NautilusFileUndoInfoCreate
{
NautilusFileUndoInfo parent_instance;
char *template;
union
{
char *template;
void *buffer;
};
GFile *target_file;
gint length;
gsize length;
};
G_DEFINE_TYPE (NautilusFileUndoInfoCreate, nautilus_file_undo_info_create, NAUTILUS_TYPE_FILE_UNDO_INFO)
@ -1011,12 +1015,23 @@ nautilus_file_undo_info_create_new (NautilusFileUndoOp op_type)
void
nautilus_file_undo_info_create_set_data (NautilusFileUndoInfoCreate *self,
GFile *file,
const char *template,
const void *template,
gsize length)
{
NautilusFileUndoOp op_type = nautilus_file_undo_info_get_op_type (NAUTILUS_FILE_UNDO_INFO (self));
self->target_file = g_object_ref (file);
self->template = g_strdup (template);
self->length = length;
if (op_type == NAUTILUS_FILE_UNDO_OP_CREATE_EMPTY_FILE)
{
/* Operation name is a misnomer, it still can hold data to write to
* the newly created file. */
self->buffer = g_memdup2 (template, length);
self->length = length;
}
else if (op_type == NAUTILUS_FILE_UNDO_OP_CREATE_FILE_FROM_TEMPLATE)
{
self->template = g_strdup (template);
}
}
/* rename */

View File

@ -119,7 +119,7 @@ G_DECLARE_FINAL_TYPE (NautilusFileUndoInfoCreate, nautilus_file_undo_info_create
NautilusFileUndoInfo *nautilus_file_undo_info_create_new (NautilusFileUndoOp op_type);
void nautilus_file_undo_info_create_set_data (NautilusFileUndoInfoCreate *self,
GFile *file,
const char *template,
const void *template,
gsize length);
/* rename */

View File

@ -23,13 +23,13 @@
#include "nautilus-file-utilities.h"
#include "nautilus-application.h"
#include "nautilus-file.h"
#include "nautilus-file-operations.h"
#include "nautilus-filename-utilities.h"
#include "nautilus-global-preferences.h"
#include "nautilus-icon-names.h"
#include "nautilus-metadata.h"
#include "nautilus-file.h"
#include "nautilus-file-operations.h"
#include "nautilus-filename-utilities.h"
#include "nautilus-network-directory.h"
#include "nautilus-scheme.h"
#include "nautilus-search-directory.h"
#include "nautilus-starred-directory.h"
@ -70,18 +70,8 @@ nautilus_compute_title_for_location (GFile *location)
{
file = nautilus_file_get (location);
if (nautilus_file_is_other_locations (file))
{
title = g_strdup (_("Other Locations"));
}
else if (nautilus_file_is_starred_location (file))
{
title = g_strdup (_("Starred"));
}
else
{
title = g_strdup (nautilus_file_get_display_name (file));
}
title = g_strdup (nautilus_file_get_display_name (file));
nautilus_file_unref (file);
}
@ -989,6 +979,7 @@ nautilus_ensure_extension_builtins (void)
* that they will be registered by the time the extension point
* is iterating over its extensions.
*/
g_type_ensure (NAUTILUS_TYPE_NETWORK_DIRECTORY);
g_type_ensure (NAUTILUS_TYPE_SEARCH_DIRECTORY);
g_type_ensure (NAUTILUS_TYPE_STARRED_DIRECTORY);
}

View File

@ -182,6 +182,7 @@ G_DEFINE_TYPE_WITH_CODE (NautilusFile, nautilus_file, G_TYPE_OBJECT,
enum
{
PROP_0,
PROP_DIRECTORY,
PROP_DISPLAY_NAME,
N_PROPS
};
@ -587,16 +588,17 @@ void
nautilus_file_set_directory (NautilusFile *file,
NautilusDirectory *directory)
{
char *parent_uri;
if (!g_set_object (&file->details->directory, directory))
{
return;
}
g_autofree char *parent_uri = nautilus_file_get_parent_uri (file);
g_clear_object (&file->details->directory);
g_free (file->details->directory_name_collation_key);
file->details->directory = nautilus_directory_ref (directory);
parent_uri = nautilus_file_get_parent_uri (file);
file->details->directory_name_collation_key = g_utf8_collate_key_for_filename (parent_uri, -1);
g_free (parent_uri);
g_object_notify_by_pspec (G_OBJECT (file), properties[PROP_DIRECTORY]);
}
NautilusFile *
@ -719,8 +721,9 @@ nautilus_file_new_from_info (NautilusDirectory *directory,
g_return_val_if_fail (NAUTILUS_IS_DIRECTORY (directory), NULL);
g_return_val_if_fail (info != NULL, NULL);
file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_VFS_FILE, NULL));
nautilus_file_set_directory (file, directory);
file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_VFS_FILE,
"directory", directory,
NULL));
update_info_and_name (file, info);
@ -987,7 +990,7 @@ nautilus_file_unref (NautilusFile *file)
* and adding trailing slash).
* If the parent is NULL, returns the empty string.
*/
char *
static char *
nautilus_file_get_parent_uri_for_display (NautilusFile *file)
{
g_autoptr (GFile) parent = NULL;
@ -1652,7 +1655,10 @@ nautilus_file_can_trash (NautilusFile *file)
gboolean
nautilus_file_opens_in_view (NautilusFile *file)
{
return nautilus_file_is_directory (file);
return (nautilus_file_is_directory (file) ||
nautilus_file_get_file_type (file) == G_FILE_TYPE_MOUNTABLE ||
(nautilus_file_get_file_type (file) == G_FILE_TYPE_SHORTCUT &&
g_strcmp0 (nautilus_file_get_mime_type (file), "inode/directory") == 0));
}
NautilusFileOperation *
@ -2425,6 +2431,7 @@ update_info_internal (NautilusFile *file,
if (g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_STANDARD_IS_VIRTUAL) ||
file_type == G_FILE_TYPE_SHORTCUT ||
file_type == G_FILE_TYPE_MOUNTABLE ||
nautilus_file_is_in_recent (file))
{
if (g_set_str (&file->details->activation_uri,
@ -4225,18 +4232,7 @@ nautilus_file_peek_display_name (NautilusFile *file)
const char *
nautilus_file_get_display_name (NautilusFile *file)
{
if (nautilus_file_is_other_locations (file))
{
return _("Other Locations");
}
else if (nautilus_file_is_starred_location (file))
{
return _("Starred");
}
else
{
return nautilus_file_peek_display_name (file);
}
return nautilus_file_peek_display_name (file);
}
const char *
@ -4398,7 +4394,8 @@ get_default_file_icon (void)
static GIcon *fallback_icon = NULL;
if (fallback_icon == NULL)
{
fallback_icon = g_themed_icon_new ("application-x-generic");
fallback_icon = g_themed_icon_new_from_names ((char *[]){"application-x-generic",
"text-x-generic"}, 2);
}
return fallback_icon;
@ -4914,13 +4911,6 @@ GDateTime *
nautilus_file_get_date (NautilusFile *file,
NautilusDateType date_type)
{
g_return_val_if_fail (date_type == NAUTILUS_DATE_TYPE_ACCESSED
|| date_type == NAUTILUS_DATE_TYPE_MODIFIED
|| date_type == NAUTILUS_DATE_TYPE_CREATED
|| date_type == NAUTILUS_DATE_TYPE_TRASHED
|| date_type == NAUTILUS_DATE_TYPE_RECENCY,
FALSE);
if (file == NULL)
{
return NULL;
@ -4928,7 +4918,53 @@ nautilus_file_get_date (NautilusFile *file,
g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
return NAUTILUS_FILE_CLASS (G_OBJECT_GET_CLASS (file))->get_date (file, date_type);
time_t file_time_raw = 0;
switch (date_type)
{
case NAUTILUS_DATE_TYPE_ACCESSED:
{
file_time_raw = nautilus_file_get_atime (file);
}
break;
case NAUTILUS_DATE_TYPE_MODIFIED:
{
file_time_raw = nautilus_file_get_mtime (file);
}
break;
case NAUTILUS_DATE_TYPE_CREATED:
{
file_time_raw = nautilus_file_get_btime (file);
}
break;
case NAUTILUS_DATE_TYPE_TRASHED:
{
file_time_raw = nautilus_file_get_trash_time (file);
}
break;
case NAUTILUS_DATE_TYPE_RECENCY:
{
file_time_raw = nautilus_file_get_recency (file);
}
break;
default:
{
g_return_val_if_reached (NULL);
}
}
/* Before we have info on a file, the date is unknown. */
if (file_time_raw == 0)
{
return NULL;
}
return g_date_time_new_from_unix_local (file_time_raw);
}
static char *
@ -4941,7 +4977,20 @@ nautilus_file_get_where_string (NautilusFile *file)
g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
return NAUTILUS_FILE_CLASS (G_OBJECT_GET_CLASS (file))->get_where_string (file);
g_autoptr (NautilusFile) real_file = NULL;
if (nautilus_file_is_in_recent (file))
{
g_autoptr (GFile) activation_location = nautilus_file_get_activation_location (file);
real_file = nautilus_file_get (activation_location);
}
else
{
real_file = g_object_ref (file);
}
return nautilus_file_get_parent_uri_for_display (real_file);
}
static char *
@ -7378,27 +7427,6 @@ nautilus_file_is_remote (NautilusFile *file)
return get_filesystem_remote (file, NULL);
}
/**
* nautilus_file_is_other_locations
*
* Check if this file is Other Locations.
* @file: NautilusFile representing the file in question.
*
* Returns: TRUE if @file is Other Locations.
*
**/
gboolean
nautilus_file_is_other_locations (NautilusFile *file)
{
g_autoptr (GFile) location = NULL;
g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
location = nautilus_file_get_location (file);
return nautilus_is_root_for_scheme (location, SCHEME_OTHER_LOCATIONS);
}
/**
* nautilus_file_is_starred_location
*
@ -7420,6 +7448,16 @@ nautilus_file_is_starred_location (NautilusFile *file)
return g_file_has_uri_scheme (location, SCHEME_STARRED);
}
gboolean
nautilus_file_is_network_view (NautilusFile *file)
{
g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
g_autoptr (GFile) location = nautilus_file_get_location (file);
return nautilus_is_root_for_scheme (location, SCHEME_NETWORK_VIEW);
}
/**
* nautilus_file_is_in_admin
*
@ -8471,22 +8509,6 @@ real_get_deep_counts (NautilusFile *file,
return NAUTILUS_REQUEST_DONE;
}
static void
real_set_metadata (NautilusFile *file,
const char *key,
const char *value)
{
/* Dummy default impl */
}
static void
real_set_metadata_as_list (NautilusFile *file,
const char *key,
char **value)
{
/* Dummy default impl */
}
static void
nautilus_file_get_property (GObject *object,
guint prop_id,
@ -8510,6 +8532,35 @@ nautilus_file_get_property (GObject *object,
}
}
static void
nautilus_file_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
NautilusFile *file = NAUTILUS_FILE (object);
switch (prop_id)
{
case PROP_DIRECTORY:
{
nautilus_file_set_directory (file, g_value_get_object (value));
}
break;
default:
{
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
}
static void
default_no_op (NautilusFile *file)
{
/* Dummy default impl */
}
static void
nautilus_file_class_init (NautilusFileClass *class)
{
@ -8553,11 +8604,22 @@ nautilus_file_class_init (NautilusFileClass *class)
G_OBJECT_CLASS (class)->finalize = finalize;
G_OBJECT_CLASS (class)->constructor = nautilus_file_constructor;
G_OBJECT_CLASS (class)->get_property = nautilus_file_get_property;
G_OBJECT_CLASS (class)->set_property = nautilus_file_set_property;
class->get_item_count = real_get_item_count;
class->get_deep_counts = real_get_deep_counts;
class->set_metadata = real_set_metadata;
class->set_metadata_as_list = real_set_metadata_as_list;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
class->set_metadata = default_no_op;
class->set_metadata_as_list = default_no_op;
class->mount = default_no_op;
class->unmount = default_no_op;
class->eject = default_no_op;
class->start = default_no_op;
class->stop = default_no_op;
class->poll_for_media = default_no_op;
#pragma GCC diagnostic pop
signals[CHANGED] =
g_signal_new ("changed",
@ -8598,6 +8660,10 @@ nautilus_file_class_init (NautilusFileClass *class)
G_CALLBACK (mime_type_data_changed_callback),
NULL);
properties[PROP_DIRECTORY] = g_param_spec_object ("directory", NULL, NULL,
NAUTILUS_TYPE_DIRECTORY,
(G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
properties[PROP_DISPLAY_NAME] = g_param_spec_string ("display-name", NULL, NULL,
"",
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);

View File

@ -163,7 +163,6 @@ char * nautilus_file_get_uri_scheme (Nautilu
NautilusFile * nautilus_file_get_parent (NautilusFile *file);
GFile * nautilus_file_get_parent_location (NautilusFile *file);
char * nautilus_file_get_parent_uri (NautilusFile *file);
char * nautilus_file_get_parent_uri_for_display (NautilusFile *file);
const char * nautilus_file_get_thumbnail_path (NautilusFile *file);
gboolean nautilus_file_can_get_size (NautilusFile *file);
guint64 nautilus_file_get_size (NautilusFile *file);
@ -197,8 +196,8 @@ gboolean nautilus_file_is_in_recent (Nautilu
gboolean nautilus_file_is_in_starred (NautilusFile *file);
gboolean nautilus_file_is_in_admin (NautilusFile *file);
gboolean nautilus_file_is_remote (NautilusFile *file);
gboolean nautilus_file_is_other_locations (NautilusFile *file);
gboolean nautilus_file_is_starred_location (NautilusFile *file);
gboolean nautilus_file_is_network_view (NautilusFile *file);
gboolean nautilus_file_is_home (NautilusFile *file);
GError * nautilus_file_get_file_info_error (NautilusFile *file);
gboolean nautilus_file_get_directory_item_count (NautilusFile *file,
@ -500,7 +499,7 @@ typedef struct {
/* Called periodically while directory deep count is being computed. */
void (* updated_deep_count_in_progress) (NautilusFile *file);
/* Virtual functions (mainly used for trash directory). */
/* Virtual functions which MUST be implemented by subclasses */
void (* monitor_add) (NautilusFile *file,
gconstpointer client,
NautilusFileAttributes attributes);
@ -515,6 +514,8 @@ typedef struct {
gpointer callback_data);
gboolean (* check_if_ready) (NautilusFile *file,
NautilusFileAttributes attributes);
/* Virtual functions which MAY be overridden by subclasses */
gboolean (* get_item_count) (NautilusFile *file,
guint *count,
gboolean *count_unreadable);
@ -523,10 +524,8 @@ typedef struct {
guint *file_count,
guint *unreadable_directory_count,
goffset *total_size);
GDateTime * (* get_date) (NautilusFile *file,
NautilusDateType type);
char * (* get_where_string) (NautilusFile *file);
/* Virtual functions which MAY be implemented by subclasses (default implementation does nothing) */
void (* set_metadata) (NautilusFile *file,
const char *key,
const char *value);

View File

@ -67,11 +67,13 @@
#include "nautilus-list-view.h"
#include "nautilus-metadata.h"
#include "nautilus-mime-actions.h"
#include "nautilus-network-view.h"
#include "nautilus-module.h"
#include "nautilus-new-folder-dialog.h"
#include "nautilus-previewer.h"
#include "nautilus-program-choosing.h"
#include "nautilus-properties-window.h"
#include "nautilus-recent-servers.h"
#include "nautilus-rename-file-popover.h"
#include "nautilus-scheme.h"
#include "nautilus-search-directory.h"
@ -82,7 +84,6 @@
#include "nautilus-ui-utilities.h"
#include "nautilus-view.h"
#include "nautilus-view-model.h"
#include "nautilus-window.h"
#include "nautilus-tracker-utilities.h"
/* Minimum starting update inverval */
@ -232,6 +233,7 @@ typedef struct
GtkWidget *background_menu;
GActionGroup *view_action_group;
GtkShortcutController *shortcuts;
/* Empty states */
GtkWidget *empty_view_page;
@ -953,11 +955,14 @@ nautilus_files_view_invert_selection (NautilusFilesView *self)
static NautilusToolbarMenuSections *
nautilus_files_view_get_toolbar_menu_sections (NautilusView *view)
{
NautilusFilesViewPrivate *priv;
g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), NULL);
priv = nautilus_files_view_get_instance_private (NAUTILUS_FILES_VIEW (view));
NautilusFilesViewPrivate *priv = nautilus_files_view_get_instance_private (NAUTILUS_FILES_VIEW (view));
if (NAUTILUS_IS_NETWORK_VIEW (priv->list_base))
{
return NULL;
}
return priv->toolbar_menu_sections;
}
@ -1222,16 +1227,6 @@ create_templates_parameters_free (CreateTemplateParameters *parameters)
g_free (parameters);
}
static NautilusWindow *
nautilus_files_view_get_window (NautilusFilesView *view)
{
NautilusFilesViewPrivate *priv;
priv = nautilus_files_view_get_instance_private (view);
return nautilus_window_slot_get_window (priv->slot);
}
/* Returns the GtkWindow that this directory view occupies, or NULL
* if at the moment this directory view is not in a GtkWindow or the
* GtkWindow cannot be determined. Primarily used for parenting dialogs.
@ -1270,53 +1265,13 @@ get_view_directory (NautilusFilesView *view)
return path;
}
typedef struct
{
gchar *uri;
gboolean is_update;
} PreviewExportData;
static void
preview_export_data_free (gpointer _data)
{
PreviewExportData *data = _data;
g_free (data->uri);
g_free (data);
}
G_DEFINE_AUTOPTR_CLEANUP_FUNC (PreviewExportData, preview_export_data_free)
static void
on_window_handle_export (NautilusWindow *window,
const char *handle,
guint xid,
gpointer user_data)
{
g_autoptr (PreviewExportData) data = user_data;
nautilus_previewer_call_show_file (data->uri, handle, xid, !data->is_update);
}
static void
nautilus_files_view_preview (NautilusFilesView *view,
PreviewExportData *data)
{
if (!nautilus_window_export_handle (nautilus_files_view_get_window (view),
on_window_handle_export,
data))
{
/* Let's use a fallback, so at least a preview will be displayed */
nautilus_previewer_call_show_file (data->uri, "x11:0", 0, !data->is_update);
}
}
static void
nautilus_files_view_preview_update (NautilusFilesView *view)
{
NautilusFilesViewPrivate *priv = nautilus_files_view_get_instance_private (view);
GtkApplication *app;
GtkWindow *window;
GtkRoot *window;
g_autolist (NautilusFile) selection = NULL;
PreviewExportData *data;
if (!priv->active ||
!nautilus_previewer_is_visible ())
@ -1325,8 +1280,8 @@ nautilus_files_view_preview_update (NautilusFilesView *view)
}
app = GTK_APPLICATION (g_application_get_default ());
window = GTK_WINDOW (nautilus_files_view_get_window (view));
if (window == NULL || window != gtk_application_get_active_window (app))
window = gtk_widget_get_root (GTK_WIDGET (view));
if (window == NULL || GTK_WINDOW (window) != gtk_application_get_active_window (app))
{
return;
}
@ -1337,11 +1292,9 @@ nautilus_files_view_preview_update (NautilusFilesView *view)
return;
}
data = g_new0 (PreviewExportData, 1);
data->uri = nautilus_file_get_uri (selection->data);
data->is_update = TRUE;
g_autofree gchar *uri = nautilus_file_get_uri (selection->data);
nautilus_files_view_preview (view, data);
nautilus_previewer_call_show_file (uri, window, FALSE);
}
void
@ -1815,14 +1768,13 @@ action_preview_selection (GSimpleAction *action,
{
NautilusFilesView *view = NAUTILUS_FILES_VIEW (user_data);
g_autolist (NautilusFile) selection = NULL;
PreviewExportData *data = g_new0 (PreviewExportData, 1);
GtkRoot *window = gtk_widget_get_root (GTK_WIDGET (view));
selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
data->uri = nautilus_file_get_uri (selection->data);
data->is_update = FALSE;
g_autofree gchar *uri = nautilus_file_get_uri (selection->data);
nautilus_files_view_preview (view, data);
nautilus_previewer_call_show_file (uri, window, TRUE);
}
static void
@ -1872,12 +1824,10 @@ select_pattern (NautilusFilesView *view)
{
g_autoptr (GtkBuilder) builder = NULL;
GtkWidget *dialog;
NautilusWindow *window;
GtkWidget *example;
GtkWidget *entry, *select_button;
char *example_pattern;
window = nautilus_files_view_get_window (view);
builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/ui/nautilus-files-view-select-items.ui");
dialog = GTK_WIDGET (gtk_builder_get_object (builder, "select_items_dialog"));
@ -1887,7 +1837,8 @@ select_pattern (NautilusFilesView *view)
"*.png, file\?\?.txt, pict*.\?\?\?");
gtk_label_set_markup (GTK_LABEL (example), example_pattern);
g_free (example_pattern);
gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (window));
gtk_window_set_transient_for (GTK_WINDOW (dialog),
GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (view))));
entry = GTK_WIDGET (gtk_builder_get_object (builder, "pattern_entry"));
select_button = GTK_WIDGET (gtk_builder_get_object (builder, "select_button"));
@ -2423,7 +2374,7 @@ void
nautilus_files_view_new_file_with_initial_contents (NautilusFilesView *view,
const char *parent_uri,
const char *filename,
const char *initial_contents,
const void *initial_contents,
gsize length)
{
NewFolderData *data;
@ -3201,14 +3152,14 @@ slot_active_changed (NautilusWindowSlot *slot,
schedule_update_context_menus (view);
gtk_widget_insert_action_group (GTK_WIDGET (nautilus_files_view_get_window (view)),
gtk_widget_insert_action_group (GTK_WIDGET (gtk_widget_get_root (GTK_WIDGET (view))),
"view",
G_ACTION_GROUP (priv->view_action_group));
}
else
{
remove_update_context_menus_timeout_callback (view);
gtk_widget_insert_action_group (GTK_WIDGET (nautilus_files_view_get_window (view)),
gtk_widget_insert_action_group (GTK_WIDGET (gtk_widget_get_root (GTK_WIDGET (view))),
"view",
NULL);
}
@ -3530,6 +3481,15 @@ nautilus_files_view_display_selection_info (NautilusFilesView *view)
g_return_if_fail (NAUTILUS_IS_FILES_VIEW (view));
NautilusFilesViewPrivate *priv = nautilus_files_view_get_instance_private (view);
if (priv->list_base != NULL && NAUTILUS_IS_NETWORK_VIEW (priv->list_base))
{
/* Selection info is not relevant on this view and visually clashes with
* the action bar. */
return;
}
selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
folder_item_count_known = TRUE;
@ -3858,6 +3818,12 @@ real_check_empty_states (NautilusFilesView *view)
adw_status_page_set_title (status_page, _("No Recent Files"));
adw_status_page_set_description (status_page, NULL);
}
else if (g_file_has_uri_scheme (priv->location, SCHEME_NETWORK_VIEW))
{
adw_status_page_set_icon_name (status_page, "network-computer-symbolic");
adw_status_page_set_title (status_page, _("No Known Connections"));
adw_status_page_set_description (status_page, _("Enter an address to connect to a network location."));
}
else
{
adw_status_page_set_icon_name (status_page, "folder-symbolic");
@ -4465,13 +4431,12 @@ static void
display_pending_files (NautilusFilesView *view)
{
NautilusFilesViewPrivate *priv = nautilus_files_view_get_instance_private (view);
g_autoptr (GtkBitset) selection = NULL;
gboolean no_selection = FALSE;
search_transition_emit_delayed_signals_if_pending (view);
selection = gtk_selection_model_get_selection (GTK_SELECTION_MODEL (priv->model));
no_selection = gtk_bitset_is_empty (selection);
/* Get selection after delayed signals are emitted. */
g_autoptr (GtkBitset) selection = gtk_selection_model_get_selection (GTK_SELECTION_MODEL (priv->model));
gboolean no_selection = gtk_bitset_is_empty (selection);
process_pending_files (view);
@ -5475,8 +5440,9 @@ add_script_to_scripts_menus (NautilusFilesView *view,
if ((shortcut = g_hash_table_lookup (script_accels, name)))
{
nautilus_application_set_accelerator (g_application_get_default (),
detailed_action_name, shortcut);
gtk_shortcut_controller_add_shortcut (priv->shortcuts,
gtk_shortcut_new (gtk_shortcut_trigger_parse_string (shortcut),
gtk_named_action_new (detailed_action_name)));
}
g_free (action_name);
@ -6102,7 +6068,7 @@ copy_or_move_selection (NautilusFilesView *view,
gtk_file_dialog_set_initial_folder (dialog, location);
gtk_file_dialog_select_folder (dialog,
GTK_WINDOW (nautilus_files_view_get_window (view)),
GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (view))),
NULL,
(GAsyncReadyCallback) on_destination_dialog_response,
copy_data);
@ -6254,9 +6220,8 @@ real_action_rename (NautilusFilesView *view)
/* If there is more than one file selected, invoke a batch renamer */
if (selection->next != NULL)
{
NautilusWindow *window;
GtkRoot *window = gtk_widget_get_root (GTK_WIDGET (view));
window = nautilus_files_view_get_window (view);
gtk_widget_set_cursor_from_name (GTK_WIDGET (window), "progress");
dialog = nautilus_batch_rename_dialog_new (selection,
@ -6489,7 +6454,7 @@ extract_files_to_chosen_location (NautilusFilesView *view,
data->files = nautilus_file_list_copy (files);
gtk_file_dialog_select_folder (dialog,
GTK_WINDOW (nautilus_files_view_get_window (view)),
GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (view))),
NULL,
(GAsyncReadyCallback) on_extract_destination_dialog_response,
data);
@ -6815,9 +6780,12 @@ file_mount_callback (NautilusFile *file,
GError *error,
gpointer callback_data)
{
NautilusFilesView *view;
g_autoptr (NautilusFilesView) self = NAUTILUS_FILES_VIEW (callback_data);
NautilusFilesViewPrivate *priv = nautilus_files_view_get_instance_private (self);
NautilusViewItem *item = nautilus_view_model_get_item_for_file (priv->model, file);
view = NAUTILUS_FILES_VIEW (callback_data);
nautilus_file_invalidate_attributes (file, NAUTILUS_FILE_ATTRIBUTE_MOUNT);
nautilus_view_item_set_loading (item, FALSE);
if (error != NULL &&
(error->domain != G_IO_ERROR ||
@ -6830,7 +6798,7 @@ file_mount_callback (NautilusFile *file,
nautilus_file_get_display_name (file));
show_dialog (text,
error->message,
GTK_WINDOW (nautilus_files_view_get_window (view)),
GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self))),
GTK_MESSAGE_ERROR);
}
}
@ -6841,10 +6809,11 @@ file_unmount_callback (NautilusFile *file,
GError *error,
gpointer callback_data)
{
NautilusFilesView *view;
g_autoptr (NautilusFilesView) self = NAUTILUS_FILES_VIEW (callback_data);
NautilusFilesViewPrivate *priv = nautilus_files_view_get_instance_private (self);
NautilusViewItem *item = nautilus_view_model_get_item_for_file (priv->model, file);
view = NAUTILUS_FILES_VIEW (callback_data);
g_object_unref (view);
nautilus_view_item_set_loading (item, FALSE);
if (error != NULL &&
(error->domain != G_IO_ERROR ||
@ -6856,7 +6825,7 @@ file_unmount_callback (NautilusFile *file,
nautilus_file_get_display_name (file));
show_dialog (text,
error->message,
GTK_WINDOW (nautilus_files_view_get_window (view)),
GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self))),
GTK_MESSAGE_ERROR);
}
}
@ -6867,10 +6836,7 @@ file_eject_callback (NautilusFile *file,
GError *error,
gpointer callback_data)
{
NautilusFilesView *view;
view = NAUTILUS_FILES_VIEW (callback_data);
g_object_unref (view);
g_autoptr (NautilusFilesView) self = NAUTILUS_FILES_VIEW (callback_data);
if (error != NULL &&
(error->domain != G_IO_ERROR ||
@ -6882,7 +6848,7 @@ file_eject_callback (NautilusFile *file,
nautilus_file_get_display_name (file));
show_dialog (text,
error->message,
GTK_WINDOW (nautilus_files_view_get_window (view)),
GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self))),
GTK_MESSAGE_ERROR);
}
}
@ -6893,9 +6859,7 @@ file_stop_callback (NautilusFile *file,
GError *error,
gpointer callback_data)
{
NautilusFilesView *view;
view = NAUTILUS_FILES_VIEW (callback_data);
g_autoptr (NautilusFilesView) self = NAUTILUS_FILES_VIEW (callback_data);
if (error != NULL &&
(error->domain != G_IO_ERROR ||
@ -6904,7 +6868,7 @@ file_stop_callback (NautilusFile *file,
{
show_dialog (_("Unable to stop drive"),
error->message,
GTK_WINDOW (nautilus_files_view_get_window (view)),
GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self))),
GTK_MESSAGE_ERROR);
}
}
@ -6914,13 +6878,12 @@ action_mount_volume (GSimpleAction *action,
GVariant *state,
gpointer user_data)
{
NautilusFilesView *view = NAUTILUS_FILES_VIEW (user_data);
NautilusFilesViewPrivate *priv = nautilus_files_view_get_instance_private (view);
NautilusFile *file;
GList *selection, *l;
NautilusFilesView *view;
GMountOperation *mount_op;
view = NAUTILUS_FILES_VIEW (user_data);
selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
for (l = selection; l != NULL; l = l->next)
{
@ -6928,11 +6891,14 @@ action_mount_volume (GSimpleAction *action,
if (nautilus_file_can_mount (file))
{
NautilusViewItem *item = nautilus_view_model_get_item_for_file (priv->model, file);
nautilus_view_item_set_loading (item, TRUE);
mount_op = gtk_mount_operation_new (nautilus_files_view_get_containing_window (view));
g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION);
nautilus_file_mount (file, mount_op, NULL,
file_mount_callback,
view);
g_object_ref (view));
g_object_unref (mount_op);
}
}
@ -6944,12 +6910,11 @@ action_unmount_volume (GSimpleAction *action,
GVariant *state,
gpointer user_data)
{
NautilusFilesView *view = NAUTILUS_FILES_VIEW (user_data);
NautilusFilesViewPrivate *priv = nautilus_files_view_get_instance_private (view);
NautilusFile *file;
g_autolist (NautilusFile) selection = NULL;
GList *l;
NautilusFilesView *view;
view = NAUTILUS_FILES_VIEW (user_data);
selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
@ -6959,6 +6924,9 @@ action_unmount_volume (GSimpleAction *action,
if (nautilus_file_can_unmount (file))
{
GMountOperation *mount_op;
NautilusViewItem *item = nautilus_view_model_get_item_for_file (priv->model, file);
nautilus_view_item_set_loading (item, TRUE);
mount_op = gtk_mount_operation_new (nautilus_files_view_get_containing_window (view));
nautilus_file_unmount (file, mount_op, NULL,
file_unmount_callback, g_object_ref (view));
@ -7016,7 +6984,7 @@ file_start_callback (NautilusFile *file,
g_autofree char *text = g_strdup_printf (_("Unable to start “%s”"), name);
show_dialog (text,
error->message,
GTK_WINDOW (nautilus_files_view_get_window (view)),
GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (view))),
GTK_MESSAGE_ERROR);
}
}
@ -7071,7 +7039,7 @@ action_stop_volume (GSimpleAction *action,
GMountOperation *mount_op;
mount_op = gtk_mount_operation_new (nautilus_files_view_get_containing_window (view));
nautilus_file_stop (file, mount_op, NULL,
file_stop_callback, view);
file_stop_callback, g_object_ref (view));
g_object_unref (mount_op);
}
}
@ -7101,6 +7069,37 @@ action_detect_media (GSimpleAction *action,
}
}
static void
action_copy_network_address (GSimpleAction *action,
GVariant *state,
gpointer user_data)
{
NautilusFilesView *self = NAUTILUS_FILES_VIEW (user_data);
g_autolist (NautilusFile) selection = nautilus_view_get_selection (NAUTILUS_VIEW (self));
g_return_if_fail (selection != NULL && selection->next == NULL);
g_autofree char *address = nautilus_file_get_activation_uri (NAUTILUS_FILE (selection->data));
gdk_clipboard_set_text (gtk_widget_get_clipboard (GTK_WIDGET (self)), address);
}
static void
action_remove_recent_server (GSimpleAction *action,
GVariant *state,
gpointer user_data)
{
NautilusFilesView *self = NAUTILUS_FILES_VIEW (user_data);
g_autolist (NautilusFile) selection = nautilus_view_get_selection (NAUTILUS_VIEW (self));
for (GList *l = selection; l != NULL; l = l->next)
{
g_autofree char *address = nautilus_file_get_activation_uri (NAUTILUS_FILE (selection->data));
nautilus_remove_recent_server (address);
}
}
const GActionEntry view_entries[] =
{
/* Toolbar menu */
@ -7173,6 +7172,9 @@ const GActionEntry view_entries[] =
{ .name = "start-volume", .activate = action_start_volume },
{ .name = "stop-volume", .activate = action_stop_volume },
{ .name = "detect-media", .activate = action_detect_media },
/* Only in Network View */
{ .name = "copy-network-address", .activate = action_copy_network_address },
{ .name = "remove-recent-server", .activate = action_remove_recent_server },
/* Only accesible by shorcuts */
{ .name = "select-pattern", .activate = action_select_pattern },
{ .name = "invert-selection", .activate = action_invert_selection },
@ -7516,10 +7518,11 @@ nautilus_handles_all_files_to_extract (GList *files)
static void
real_update_actions_state (NautilusFilesView *view)
{
NautilusFilesViewPrivate *priv;
NautilusFilesViewPrivate *priv = nautilus_files_view_get_instance_private (view);
g_autolist (NautilusFile) selection = NULL;
GList *l;
gint selection_count;
gboolean is_network_view = NAUTILUS_IS_NETWORK_VIEW (priv->list_base);
gboolean selection_contains_home_dir;
gboolean selection_contains_recent;
gboolean selection_contains_search;
@ -7555,8 +7558,6 @@ real_update_actions_state (NautilusFilesView *view)
gboolean show_unstar;
g_autoptr (GAppInfo) app_info_mailto = NULL;
priv = nautilus_files_view_get_instance_private (view);
view_action_group = priv->view_action_group;
selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
@ -7765,7 +7766,8 @@ real_update_actions_state (NautilusFilesView *view)
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
!selection_contains_recent &&
!selection_contains_search &&
!selection_contains_starred);
!selection_contains_starred &&
!is_network_view);
/* Drive menu */
show_mount = (selection != NULL);
@ -7837,7 +7839,8 @@ real_update_actions_state (NautilusFilesView *view)
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
!selection_contains_recent &&
!selection_contains_search &&
!selection_contains_starred);
!selection_contains_starred &&
!is_network_view);
action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
"new-folder");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), can_create_files);
@ -7879,16 +7882,20 @@ real_update_actions_state (NautilusFilesView *view)
action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
"properties");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
selection_count != 0 ||
(!selection_contains_recent &&
!selection_contains_search &&
!selection_contains_starred));
(is_network_view ?
(selection_count == 1 &&
nautilus_file_can_unmount (selection->data)) :
(selection_count != 0 ||
(!selection_contains_recent &&
!selection_contains_search &&
!selection_contains_starred))));
action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
"current-directory-properties");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
!selection_contains_recent &&
!selection_contains_search &&
!selection_contains_starred);
!selection_contains_starred &&
!is_network_view);
/* Actions that are related to the clipboard need request, request the data
* and update them once we have the data */
@ -7950,6 +7957,32 @@ real_update_actions_state (NautilusFilesView *view)
action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
"unstar");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), show_unstar && selection_contains_starred);
/* Network view actions */
gboolean can_remove_recent_server = is_network_view;
for (l = selection; l != NULL && can_remove_recent_server; l = l->next)
{
NautilusFile *file = NAUTILUS_FILE (l->data);
g_autoptr (GFile) location = nautilus_file_get_location (NAUTILUS_FILE (l->data));
/* Only recent servers have x-network-view: scheme */
if (!g_file_has_uri_scheme (location, SCHEME_NETWORK_VIEW) || nautilus_file_can_unmount (file))
{
can_remove_recent_server = FALSE;
}
}
action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
"copy-network-address");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
(is_network_view &&
selection_count == 1 &&
nautilus_file_has_activation_uri (selection->data)));
action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
"remove-recent-server");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), can_remove_recent_server);
}
/* Convenience function to be called when updating menus,
@ -8247,6 +8280,20 @@ update_selection_menu (NautilusFilesView *view,
nautilus_g_menu_replace_string_in_item (G_MENU (object), i,
"hidden-when",
(!show_scripts) ? "action-missing" : NULL);
if (NAUTILUS_IS_NETWORK_VIEW (priv->list_base))
{
object = gtk_builder_get_object (builder, "move-copy-section");
g_menu_remove_all (G_MENU (object));
object = gtk_builder_get_object (builder, "file-actions-section");
g_menu_remove_all (G_MENU (object));
}
else
{
object = gtk_builder_get_object (builder, "network-view-section");
g_menu_remove_all (G_MENU (object));
}
}
static void
@ -8370,12 +8417,9 @@ nautilus_files_view_reset_view_menu (NautilusFilesView *view)
void
nautilus_files_view_update_toolbar_menus (NautilusFilesView *view)
{
NautilusWindow *window;
NautilusFilesViewPrivate *priv;
g_assert (NAUTILUS_IS_FILES_VIEW (view));
priv = nautilus_files_view_get_instance_private (view);
NautilusFilesViewPrivate *priv = nautilus_files_view_get_instance_private (view);
/* Don't update after destroy (#349551),
* or if we are not active.
@ -8385,8 +8429,6 @@ nautilus_files_view_update_toolbar_menus (NautilusFilesView *view)
{
return;
}
window = nautilus_files_view_get_window (view);
nautilus_window_reset_menus (window);
nautilus_files_view_update_actions_state (view);
nautilus_files_view_reset_view_menu (view);
@ -8594,6 +8636,7 @@ nautilus_files_view_notify_selection_changed (NautilusFilesView *view)
view);
}
nautilus_files_view_update_actions_state (view);
schedule_update_context_menus (view);
}
@ -8715,15 +8758,17 @@ load_directory (NautilusFilesView *view,
priv = nautilus_files_view_get_instance_private (view);
nautilus_files_view_stop_loading (view);
if (NAUTILUS_IS_SEARCH_DIRECTORY (directory) || NAUTILUS_IS_SEARCH_DIRECTORY (priv->directory))
/* To make search feel fast and smooth as if it were filtering the current
* view, avoid blanking the view temporarily in the following cases:
* 1- Going from a search to a search
* 2- Going from a location to local search
*/
if (NAUTILUS_IS_SEARCH_DIRECTORY (directory) &&
(NAUTILUS_IS_SEARCH_DIRECTORY (priv->directory) ||
(priv->search_query != NULL && !nautilus_query_is_global (priv->search_query))))
{
if (priv->search_query != NULL &&
!nautilus_query_is_global (priv->search_query))
{
/* To make search feel fast and smooth as if it were filtering the
* current view, avoid blanking the view temporarily. */
search_transition_schedule_delayed_signals (view);
}
search_transition_schedule_delayed_signals (view);
}
emit_clear (view);
@ -9261,7 +9306,6 @@ on_parent_changed (GObject *object,
gpointer user_data)
{
GtkWidget *widget;
NautilusWindow *window;
NautilusFilesView *view;
NautilusFilesViewPrivate *priv;
GtkWidget *parent;
@ -9271,14 +9315,13 @@ on_parent_changed (GObject *object,
priv = nautilus_files_view_get_instance_private (view);
parent = gtk_widget_get_parent (widget);
window = nautilus_files_view_get_window (view);
if (parent != NULL)
{
if (priv->slot == nautilus_window_get_active_slot (window))
if (nautilus_window_slot_get_active (priv->slot))
{
priv->active = TRUE;
gtk_widget_insert_action_group (GTK_WIDGET (nautilus_files_view_get_window (view)),
gtk_widget_insert_action_group (GTK_WIDGET (gtk_widget_get_root (widget)),
"view",
G_ACTION_GROUP (priv->view_action_group));
}
@ -9292,7 +9335,7 @@ on_parent_changed (GObject *object,
*/
if (priv->active)
{
gtk_widget_insert_action_group (GTK_WIDGET (nautilus_files_view_get_window (view)),
gtk_widget_insert_action_group (GTK_WIDGET (gtk_widget_get_root (GTK_WIDGET (priv->slot))),
"view",
NULL);
}
@ -9623,28 +9666,6 @@ nautilus_files_view_init (NautilusFilesView *view)
GtkShortcut *shortcut;
gchar *templates_uri;
GdkClipboard *clipboard;
GApplication *app;
const gchar *zoom_in_accels[] =
{
"<control>equal",
"<control>plus",
"<control>KP_Add",
"ZoomIn",
NULL
};
const gchar *zoom_out_accels[] =
{
"<control>minus",
"<control>KP_Subtract",
"ZoomOut",
NULL
};
const gchar *zoom_standard_accels[] =
{
"<control>0",
"<control>KP_0",
NULL
};
priv = nautilus_files_view_get_instance_private (view);
@ -9753,30 +9774,39 @@ nautilus_files_view_init (NautilusFilesView *view)
g_signal_connect_object (priv->view_action_group, "action-state-changed::sort",
G_CALLBACK (on_sort_action_state_changed), view, 0);
app = g_application_get_default ();
/* NOTE: Please do not add any key here that could interfere with
* the rest of the app's use of those keys. Some example of keys set here
* that broke keynav include Enter/Return, Menu, F2 and Delete keys.
* The accelerators below are set on the whole app level for the sole purpose
* The accelerators below are set on the window level for the sole purpose
* of making it more convenient when you don't have the focus exactly on the
* files view, but some keys are used in a contextual way, and those should
* should be added in nautilus_files_view_class_init() above instead of a
* global accelerator, unless it really makes sense to have them globally
* managed accelerator, unless it really makes sense to have them managed
* (e.g. Zoom in/out shortcuts).
*/
nautilus_application_set_accelerators (app, "view.zoom-in", zoom_in_accels);
nautilus_application_set_accelerators (app, "view.zoom-out", zoom_out_accels);
nautilus_application_set_accelerator (app, "view.show-hidden-files", "<control>h");
#define ADD_SHORTCUT_FOR_ACTION(controller, action, trigger) \
(gtk_shortcut_controller_add_shortcut ((controller), \
gtk_shortcut_new (gtk_shortcut_trigger_parse_string ((trigger)), \
gtk_named_action_new ((action)))))
priv->shortcuts = GTK_SHORTCUT_CONTROLLER (gtk_shortcut_controller_new ());
gtk_shortcut_controller_set_scope (priv->shortcuts, GTK_SHORTCUT_SCOPE_MANAGED);
gtk_widget_add_controller (GTK_WIDGET (view), GTK_EVENT_CONTROLLER (priv->shortcuts));
ADD_SHORTCUT_FOR_ACTION (priv->shortcuts, "view.zoom-in", "<control>equal|<control>plus|<control>KP_Add|ZoomIn");
ADD_SHORTCUT_FOR_ACTION (priv->shortcuts, "view.zoom-out", "<control>minus|<control>KP_Subtract|ZoomOut");
ADD_SHORTCUT_FOR_ACTION (priv->shortcuts, "view.show-hidden-files", "<control>h");
/* Despite putting copy/cut at the widget scope instead of the global one,
* we're putting paste globally so that it's easy to switch between apps
* we're putting paste "managed" so that it's easy to switch between apps
* with e.g. Alt+Tab and paste directly the copied file without having to
* make sure the focus is on the files view.
*/
nautilus_application_set_accelerator (app, "view.paste_accel", "<control>v");
nautilus_application_set_accelerator (app, "view.new-folder", "<control><shift>n");
nautilus_application_set_accelerator (app, "view.select-pattern", "<control>s");
nautilus_application_set_accelerators (app, "view.zoom-standard", zoom_standard_accels);
ADD_SHORTCUT_FOR_ACTION (priv->shortcuts, "view.paste_accel", "<control>v");
ADD_SHORTCUT_FOR_ACTION (priv->shortcuts, "view.new-folder", "<control><shift>n");
ADD_SHORTCUT_FOR_ACTION (priv->shortcuts, "view.select-pattern", "<control>s");
ADD_SHORTCUT_FOR_ACTION (priv->shortcuts, "view.zoom-standard", "<control>0|<control>KP_0");
#undef ADD_SHORTCUT_FOR_ACTION
/* This one should have been a keybinding, because it should trigger only
* when the view is focused. Unfortunately, children can override bindings,
@ -9821,6 +9851,12 @@ create_inner_view (NautilusFilesView *self,
}
break;
case NAUTILUS_VIEW_NETWORK_ID:
{
priv->list_base = NAUTILUS_LIST_BASE (nautilus_network_view_new ());
}
break;
default:
{
g_critical ("Unknown view type ID: %d. Falling back to list.", id);

View File

@ -30,7 +30,6 @@
#include "nautilus-directory.h"
#include "nautilus-file.h"
#include "nautilus-window.h"
#include "nautilus-view.h"
#include "nautilus-window-slot.h"
@ -149,7 +148,7 @@ void nautilus_file_view_save_image_from_texture (NautilusFilesVi
void nautilus_files_view_new_file_with_initial_contents (NautilusFilesView *view,
const char *parent_uri,
const char *filename,
const char *initial_contents,
const void *initial_contents,
gsize length);
/* selection handling */
void nautilus_files_view_activate_selection (NautilusFilesView *view,

View File

@ -109,15 +109,10 @@ navigation_button_press_cb (GtkGestureClick *gesture,
gdouble y,
gpointer user_data)
{
NautilusHistoryControls *self;
NautilusWindow *window;
GtkWidget *widget;
guint button;
NautilusHistoryControls *self = NAUTILUS_HISTORY_CONTROLS (user_data);
self = NAUTILUS_HISTORY_CONTROLS (user_data);
button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
window = NAUTILUS_WINDOW (gtk_widget_get_root (GTK_WIDGET (self)));
GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
guint button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
if (button == GDK_BUTTON_PRIMARY)
{
@ -128,11 +123,19 @@ navigation_button_press_cb (GtkGestureClick *gesture,
else if (button == GDK_BUTTON_MIDDLE)
{
NautilusNavigationDirection direction;
GtkRoot *window = gtk_widget_get_root (GTK_WIDGET (self));
if (!NAUTILUS_IS_WINDOW (window))
{
/* Only NautilusWindow offers special behavior for this event. */
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
return;
}
direction = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget),
"nav-direction"));
nautilus_window_back_or_forward_in_new_tab (window, direction);
nautilus_window_back_or_forward_in_new_tab (NAUTILUS_WINDOW (window), direction);
}
else if (button == GDK_BUTTON_SECONDARY)
{

View File

@ -0,0 +1,205 @@
/*
* Copyright (C) 2024 GNOME Foundation Inc.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Original Author: António Fernandes <antoniof@gnome.org>
*/
#include "nautilus-internal-place-file.h"
#include <glib/gi18n.h>
#include <gio/gio.h>
#include "nautilus-file-private.h"
#include "nautilus-scheme.h"
#include "nautilus-network-directory.h"
#include "nautilus-starred-directory.h"
struct _NautilusInternalPlaceFile
{
NautilusFile parent_instance;
GList *callbacks;
GCancellable *network_mount_cancellable;
};
G_DEFINE_TYPE (NautilusInternalPlaceFile, nautilus_internal_place_file, NAUTILUS_TYPE_FILE);
static void
real_monitor_add (NautilusFile *file,
gconstpointer client,
NautilusFileAttributes attributes)
{
/* Internal place attributes are static, so there is nothing to monitor. */
}
static void
real_monitor_remove (NautilusFile *file,
gconstpointer client)
{
}
typedef struct
{
NautilusFileCallback callback;
gpointer callback_data;
} InternalPlaceFileCallback;
static void
network_mount_callback (GObject *source_object,
GAsyncResult *result,
gpointer data)
{
g_autoptr (GError) error = NULL;
if (!g_file_mount_enclosing_volume_finish (G_FILE (source_object), result, &error) &&
!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_ALREADY_MOUNTED))
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
{
g_warning ("Could not mount '%s': %s", SCHEME_NETWORK ":///", error->message);
}
return;
}
NautilusInternalPlaceFile *self = NAUTILUS_INTERNAL_PLACE_FILE (data);
/* Clear cancellable and steal callbacks list because call_when_ready() may
* be called again inside the `for` loop. */
g_clear_object (&self->network_mount_cancellable);
GList *callbacks = g_steal_pointer (&self->callbacks);
for (GList *l = callbacks; l != NULL; l = l->next)
{
InternalPlaceFileCallback *callback = l->data;
(*callback->callback)(NAUTILUS_FILE (self), callback->callback_data);
}
g_list_free_full (callbacks, g_free);
}
static void
real_call_when_ready (NautilusFile *file,
NautilusFileAttributes file_attributes,
NautilusFileCallback callback,
gpointer callback_data)
{
NautilusInternalPlaceFile *self = NAUTILUS_INTERNAL_PLACE_FILE (file);
if (NAUTILUS_IS_NETWORK_DIRECTORY (file->details->directory))
{
/* WORKAROUND:
* We must ensure network:/// is mounted before calling it "ready",
* otherwise GDaemonFile makes sync D-Bus calls to mount network://
* when the view tries do add a monitor, blocking the main thread and
* freezing the UI.
* See: https://gitlab.gnome.org/GNOME/gvfs/-/issues/455
*/
if (callback != NULL)
{
InternalPlaceFileCallback data = {callback, callback_data};
self->callbacks = g_list_prepend (self->callbacks,
g_memdup2 (&data, sizeof (data)));
}
/* If there is a cancellable, we are already mounting */
if (self->network_mount_cancellable == NULL)
{
g_autoptr (GFile) network_backend = g_file_new_for_uri (SCHEME_NETWORK ":///");
self->network_mount_cancellable = g_cancellable_new ();
g_file_mount_enclosing_volume (network_backend,
G_MOUNT_MOUNT_NONE,
NULL,
self->network_mount_cancellable,
network_mount_callback, self);
}
}
else if (callback != NULL)
{
/* Internal place attributes are static, so its always ready. */
(*callback)(file, callback_data);
}
}
static void
real_cancel_call_when_ready (NautilusFile *file,
NautilusFileCallback callback,
gpointer callback_data)
{
NautilusInternalPlaceFile *self = NAUTILUS_INTERNAL_PLACE_FILE (file);
g_clear_list (&self->callbacks, g_free);
g_cancellable_cancel (self->network_mount_cancellable);
g_clear_object (&self->network_mount_cancellable);
}
static gboolean
real_check_if_ready (NautilusFile *file,
NautilusFileAttributes attributes)
{
/* Internal place attributes are static, so its always ready. */
return TRUE;
}
static void
nautilus_internal_place_file_init (NautilusInternalPlaceFile *self)
{
}
static void
nautilus_internal_place_file_constructed (GObject *object)
{
G_OBJECT_CLASS (nautilus_internal_place_file_parent_class)->constructed (object);
NautilusInternalPlaceFile *self = NAUTILUS_INTERNAL_PLACE_FILE (object);
NautilusFile *file = NAUTILUS_FILE (self);
file->details->mime_type = g_ref_string_new_intern ("inode/directory");
file->details->size = 0;
if (NAUTILUS_IS_NETWORK_DIRECTORY (file->details->directory))
{
nautilus_file_set_display_name (file, _("Network"), NULL, TRUE);
}
else if (NAUTILUS_IS_STARRED_DIRECTORY (file->details->directory))
{
nautilus_file_set_display_name (file, _("Starred"), NULL, TRUE);
}
file->details->got_file_info = TRUE;
file->details->file_info_is_up_to_date = TRUE;
}
static void
nautilus_internal_place_file_dispose (GObject *object)
{
NautilusInternalPlaceFile *self = NAUTILUS_INTERNAL_PLACE_FILE (object);
g_clear_list (&self->callbacks, g_free);
g_cancellable_cancel (self->network_mount_cancellable);
g_clear_object (&self->network_mount_cancellable);
G_OBJECT_CLASS (nautilus_internal_place_file_parent_class)->dispose (object);
}
static void
nautilus_internal_place_file_class_init (NautilusInternalPlaceFileClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
NautilusFileClass *file_class = NAUTILUS_FILE_CLASS (klass);
/* We need to know the parent directory, which is a construction property.*/
object_class->constructed = nautilus_internal_place_file_constructed;
object_class->dispose = nautilus_internal_place_file_dispose;
file_class->default_file_type = G_FILE_TYPE_DIRECTORY;
file_class->monitor_add = real_monitor_add;
file_class->monitor_remove = real_monitor_remove;
file_class->call_when_ready = real_call_when_ready;
file_class->cancel_call_when_ready = real_cancel_call_when_ready;
file_class->check_if_ready = real_check_if_ready;
}

View File

@ -0,0 +1,16 @@
/*
* Copyright (C) 2024 GNOME Foundation Inc.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Original Author: António Fernandes <antoniof@gnome.org>
*/
#pragma once
#include "nautilus-file.h"
#define NAUTILUS_TYPE_INTERNAL_PLACE_FILE nautilus_internal_place_file_get_type ()
G_DECLARE_FINAL_TYPE (NautilusInternalPlaceFile, nautilus_internal_place_file,
NAUTILUS, INTERNAL_PLACE_FILE,
NautilusFile)

View File

@ -1263,8 +1263,8 @@ nautilus_list_base_class_init (NautilusListBaseClass *klass)
G_TYPE_VALUE, GDK_TYPE_DRAG_ACTION, G_TYPE_FILE);
signals[POPUP_BACKGROUND_CONTEXT_MENU] = g_signal_new ("popup-background-context-menu",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NautilusListBaseClass, popup_background_context_menu),
NULL, NULL,
NULL,
G_TYPE_NONE, 2,

View File

@ -38,6 +38,9 @@ struct _NautilusListBaseClass
int new_zoom_level);
/* Subclasses may override base implementation. */
void (*popup_background_context_menu) (NautilusListBase *self,
double x,
double y);
NautilusViewItem *(*get_backing_item) (NautilusListBase *self);
void (*preview_selection_event) (NautilusListBase *self,
GtkDirectionType direction);

View File

@ -1056,7 +1056,7 @@ setup_view_columns (NautilusListView *self)
static void
nautilus_list_view_reload (NautilusListView *self)
{
gtk_widget_activate_action (GTK_WIDGET (self), "win.reload", NULL);
gtk_widget_activate_action (GTK_WIDGET (self), "slot.reload", NULL);
}
static void

View File

@ -32,7 +32,6 @@
#include "nautilus-application.h"
#include "nautilus-scheme.h"
#include "nautilus-window.h"
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <glib/gi18n.h>
@ -677,7 +676,7 @@ nautilus_location_entry_class_init (NautilusLocationEntryClass *class)
G_SIGNAL_RUN_LAST, 0,
NULL, NULL,
g_cclosure_marshal_generic,
G_TYPE_NONE, 1, G_TYPE_OBJECT);
G_TYPE_NONE, 1, G_TYPE_FILE);
shortcut = gtk_shortcut_new (gtk_keyval_trigger_new (GDK_KEY_Escape, 0),
gtk_signal_action_new ("cancel"));

View File

@ -0,0 +1,394 @@
/*
* Copyright (C) 2015 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
* Copyright (C) 2022 António Fernandes <antoniof@gnome.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "nautilus-network-address-bar.h"
#include <glib/gi18n.h>
#include <adwaita.h>
#include "nautilus-recent-servers.h"
struct _NautilusNetworkAddressBar
{
GtkBox parent_instance;
GtkWidget *address_entry;
GtkWidget *connect_button;
GtkWidget *available_protocols_grid;
gboolean should_open_location;
gboolean should_pulse_entry;
gboolean connecting_to_server;
guint entry_pulse_timeout_id;
GCancellable *cancellable;
};
G_DEFINE_TYPE (NautilusNetworkAddressBar, nautilus_network_address_bar, GTK_TYPE_BOX)
const char *unsupported_protocols[] =
{
"afc", "archive", "burn", "computer", "file", "http", "localtest", "obex", "recent", "trash", NULL
};
static void
show_error_message (NautilusNetworkAddressBar *self,
const gchar *primary,
const gchar *secondary)
{
GtkRoot *window = gtk_widget_get_root (GTK_WIDGET (self));
GtkWidget *dialog = adw_message_dialog_new (GTK_WINDOW (window), primary, secondary);
adw_message_dialog_add_response (ADW_MESSAGE_DIALOG (dialog), "close", _("_Close"));
gtk_window_present (GTK_WINDOW (dialog));
}
static void
server_mount_ready_cb (GObject *source_file,
GAsyncResult *res,
gpointer user_data)
{
g_autoptr (NautilusNetworkAddressBar) self = NAUTILUS_NETWORK_ADDRESS_BAR (user_data);
gboolean should_show = TRUE;
g_autoptr (GError) error = NULL;
GFile *location = G_FILE (source_file);
g_file_mount_enclosing_volume_finish (location, res, &error);
if (error != NULL)
{
should_show = FALSE;
if (error->code == G_IO_ERROR_ALREADY_MOUNTED)
{
/*
* Already mounted volume is not a critical error
* and we can still continue with the operation.
*/
should_show = TRUE;
}
else if (error->domain != G_IO_ERROR ||
(error->code != G_IO_ERROR_CANCELLED &&
error->code != G_IO_ERROR_FAILED_HANDLED))
{
/* if it wasn't cancelled show a dialog */
show_error_message (self, _("Unable to access location"), error->message);
}
/* The operation got cancelled by the user or dispose() and or the error
* has been handled already. */
}
self->should_pulse_entry = FALSE;
gtk_entry_set_progress_fraction (GTK_ENTRY (self->address_entry), 0);
/* Restore from Cancel to Connect */
gtk_button_set_label (GTK_BUTTON (self->connect_button), _("Con_nect"));
gtk_widget_set_sensitive (self->address_entry, TRUE);
self->connecting_to_server = FALSE;
if (should_show)
{
nautilus_add_recent_server (location);
/*
* Only clear the entry if it successfully connects to the server.
* Otherwise, the user would lost the typed address even if it fails
* to connect.
*/
gtk_editable_set_text (GTK_EDITABLE (self->address_entry), "");
if (self->should_open_location)
{
g_autofree char *uri_to_open = NULL;
g_autoptr (GMount) mount = g_file_find_enclosing_mount (location, self->cancellable, NULL);
/*
* If the mount is not found at this point, it is probably user-
* invisible, which happens e.g for smb-browse, but the location
* should be opened anyway...
*/
if (mount != NULL)
{
g_autoptr (GFile) root = g_mount_get_default_location (mount);
uri_to_open = g_file_get_uri (root);
}
else
{
uri_to_open = g_file_get_uri (location);
}
gtk_widget_activate_action (GTK_WIDGET (self),
"win.open-location", "s", uri_to_open);
}
}
}
static gboolean
pulse_entry_cb (gpointer user_data)
{
NautilusNetworkAddressBar *self = NAUTILUS_NETWORK_ADDRESS_BAR (user_data);
if (self->should_pulse_entry)
{
gtk_entry_progress_pulse (GTK_ENTRY (self->address_entry));
return G_SOURCE_CONTINUE;
}
else
{
gtk_entry_set_progress_fraction (GTK_ENTRY (self->address_entry), 0);
self->entry_pulse_timeout_id = 0;
return G_SOURCE_REMOVE;
}
}
static void
mount_server (NautilusNetworkAddressBar *self,
GFile *location)
{
GtkWidget *toplevel = GTK_WIDGET (gtk_widget_get_root (GTK_WIDGET (self)));
g_autoptr (GMountOperation) operation = gtk_mount_operation_new (GTK_WINDOW (toplevel));
g_cancellable_cancel (self->cancellable);
g_clear_object (&self->cancellable);
/* User cliked when the operation was ongoing, so wanted to cancel it */
if (self->connecting_to_server)
{
return;
}
self->cancellable = g_cancellable_new ();
self->should_pulse_entry = TRUE;
gtk_entry_set_progress_pulse_step (GTK_ENTRY (self->address_entry), 0.1);
gtk_entry_set_progress_fraction (GTK_ENTRY (self->address_entry), 0.1);
/* Allow to cancel the operation */
gtk_button_set_label (GTK_BUTTON (self->connect_button), _("Cance_l"));
gtk_widget_set_sensitive (self->address_entry, FALSE);
self->connecting_to_server = TRUE;
if (self->entry_pulse_timeout_id == 0)
{
self->entry_pulse_timeout_id = g_timeout_add (100, (GSourceFunc) pulse_entry_cb, self);
}
g_mount_operation_set_password_save (operation, G_PASSWORD_SAVE_FOR_SESSION);
/* make sure we keep the view around for as long as we are running */
g_file_mount_enclosing_volume (location,
0,
operation,
self->cancellable,
server_mount_ready_cb,
g_object_ref (self));
}
static void
on_connect_button_clicked (NautilusNetworkAddressBar *self)
{
/* Since the 'Connect' button is updated whenever the typed
* address changes, it is sufficient to check if it's sensitive
* or not, in order to determine if the given address is valid.
*/
if (!gtk_widget_get_sensitive (self->connect_button))
{
return;
}
const char *uri = gtk_editable_get_text (GTK_EDITABLE (self->address_entry));
if (uri != NULL && uri[0] != '\0')
{
g_autoptr (GFile) file = g_file_new_for_commandline_arg (uri);
self->should_open_location = TRUE;
mount_server (self, file);
}
else
{
show_error_message (self, _("Unable to get remote server location"), NULL);
}
}
static void
on_entry_icon_press (GtkEntry *entry,
GtkEntryIconPosition icon_pos,
gpointer user_data)
{
g_return_if_fail (icon_pos == GTK_ENTRY_ICON_SECONDARY);
gtk_editable_set_text (GTK_EDITABLE (entry), "");
}
static void
on_address_entry_text_changed (NautilusNetworkAddressBar *self)
{
const char * const *supported_protocols = g_vfs_get_supported_uri_schemes (g_vfs_get_default ());
const char *address = gtk_editable_get_text (GTK_EDITABLE (self->address_entry));
g_autofree char *scheme = g_uri_parse_scheme (address);
gboolean is_empty = (address == NULL || *address == '\0');
gboolean supported = FALSE;
if (supported_protocols != NULL && scheme != NULL)
{
supported = g_strv_contains (supported_protocols, scheme) &&
!g_strv_contains (unsupported_protocols, scheme);
}
gtk_entry_set_icon_from_icon_name (GTK_ENTRY (self->address_entry),
GTK_ENTRY_ICON_SECONDARY,
is_empty ? NULL : "edit-clear-symbolic");
gtk_widget_set_sensitive (self->connect_button, supported);
if (scheme != NULL && !supported)
{
gtk_widget_add_css_class (self->address_entry, "error");
}
else
{
gtk_widget_remove_css_class (self->address_entry, "error");
}
}
static void
nautilus_network_address_bar_map (GtkWidget *widget)
{
NautilusNetworkAddressBar *self = NAUTILUS_NETWORK_ADDRESS_BAR (widget);
gtk_editable_set_text (GTK_EDITABLE (self->address_entry), "");
GTK_WIDGET_CLASS (nautilus_network_address_bar_parent_class)->map (widget);
}
static void
attach_protocol_row_to_grid (GtkGrid *grid,
const char *protocol_name,
const char *protocol_prefix)
{
GtkWidget *name_label = gtk_label_new (protocol_name);
GtkWidget *prefix_label = gtk_label_new (protocol_prefix);
gtk_widget_set_halign (name_label, GTK_ALIGN_START);
gtk_grid_attach_next_to (grid, name_label, NULL, GTK_POS_BOTTOM, 1, 1);
gtk_widget_set_halign (prefix_label, GTK_ALIGN_START);
gtk_grid_attach_next_to (grid, prefix_label, name_label, GTK_POS_RIGHT, 1, 1);
}
static void
populate_available_protocols_grid (GtkGrid *grid)
{
const char * const *supported_protocols = g_vfs_get_supported_uri_schemes (g_vfs_get_default ());
gboolean has_any = FALSE;
if (g_strv_contains (supported_protocols, "afp"))
{
attach_protocol_row_to_grid (grid, _("AppleTalk"), "afp://");
has_any = TRUE;
}
if (g_strv_contains (supported_protocols, "ftp"))
{
attach_protocol_row_to_grid (grid, _("File Transfer Protocol"),
/* Translators: do not translate ftp:// and ftps:// */
_("ftp:// or ftps://"));
has_any = TRUE;
}
if (g_strv_contains (supported_protocols, "nfs"))
{
attach_protocol_row_to_grid (grid, _("Network File System"), "nfs://");
has_any = TRUE;
}
if (g_strv_contains (supported_protocols, "smb"))
{
attach_protocol_row_to_grid (grid, _("Samba"), "smb://");
has_any = TRUE;
}
if (g_strv_contains (supported_protocols, "ssh"))
{
attach_protocol_row_to_grid (grid, _("SSH File Transfer Protocol"),
/* Translators: do not translate sftp:// and ssh:// */
_("sftp:// or ssh://"));
has_any = TRUE;
}
if (g_strv_contains (supported_protocols, "dav"))
{
attach_protocol_row_to_grid (grid, _("WebDAV"),
/* Translators: do not translate dav:// and davs:// */
_("dav:// or davs://"));
has_any = TRUE;
}
if (!has_any)
{
gtk_widget_set_visible (GTK_WIDGET (grid), FALSE);
}
}
static void
nautilus_network_address_bar_dispose (GObject *object)
{
NautilusNetworkAddressBar *self = NAUTILUS_NETWORK_ADDRESS_BAR (object);
g_cancellable_cancel (self->cancellable);
g_clear_object (&self->cancellable);
g_clear_handle_id (&self->entry_pulse_timeout_id, g_source_remove);
G_OBJECT_CLASS (nautilus_network_address_bar_parent_class)->dispose (object);
}
static void
nautilus_network_address_bar_finalize (GObject *object)
{
G_OBJECT_CLASS (nautilus_network_address_bar_parent_class)->finalize (object);
}
static void
nautilus_network_address_bar_init (NautilusNetworkAddressBar *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
g_signal_connect (self->address_entry, "icon-press", G_CALLBACK (on_entry_icon_press), NULL);
populate_available_protocols_grid (GTK_GRID (self->available_protocols_grid));
}
static void
nautilus_network_address_bar_class_init (NautilusNetworkAddressBarClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->finalize = nautilus_network_address_bar_finalize;
object_class->dispose = nautilus_network_address_bar_dispose;
widget_class->map = nautilus_network_address_bar_map;
/* Bind class to template */
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/nautilus/ui/nautilus-network-address-bar.ui");
gtk_widget_class_bind_template_child (widget_class, NautilusNetworkAddressBar, address_entry);
gtk_widget_class_bind_template_child (widget_class, NautilusNetworkAddressBar, connect_button);
gtk_widget_class_bind_template_child (widget_class, NautilusNetworkAddressBar, available_protocols_grid);
gtk_widget_class_bind_template_callback (widget_class, on_address_entry_text_changed);
gtk_widget_class_bind_template_callback (widget_class, on_connect_button_clicked);
}
NautilusNetworkAddressBar *
nautilus_network_address_bar_new (void)
{
return g_object_new (NAUTILUS_TYPE_NETWORK_ADDRESS_BAR, NULL);
}

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2022 António Fernandes <antoniof@gnome.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define NAUTILUS_TYPE_NETWORK_ADDRESS_BAR (nautilus_network_address_bar_get_type())
G_DECLARE_FINAL_TYPE (NautilusNetworkAddressBar, nautilus_network_address_bar, NAUTILUS, NETWORK_ADDRESS_BAR, GtkBox)
NautilusNetworkAddressBar * nautilus_network_address_bar_new (void);
G_END_DECLS

145
src/nautilus-network-cell.c Normal file
View File

@ -0,0 +1,145 @@
/*
* Copyright (C) 2024 The GNOME project contributors
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "nautilus-network-cell.h"
#include <glib/gi18n.h>
#include "nautilus-directory.h"
#include "nautilus-file-utilities.h"
#include "nautilus-scheme.h"
struct _NautilusNetworkCell
{
NautilusViewCell parent_instance;
GSignalGroup *item_signal_group;
GtkWidget *icon;
GtkWidget *target_uri;
GtkWidget *unmount_button;
};
G_DEFINE_TYPE (NautilusNetworkCell, nautilus_network_cell, NAUTILUS_TYPE_VIEW_CELL)
static void
update_labels (NautilusNetworkCell *self)
{
g_autoptr (NautilusViewItem) item = nautilus_view_cell_get_item (NAUTILUS_VIEW_CELL (self));
g_return_if_fail (item != NULL);
NautilusFile *file = nautilus_view_item_get_file (item);
g_autofree char *target_uri = nautilus_file_get_activation_uri (file);
if (g_str_has_prefix (target_uri, SCHEME_COMPUTER ":///"))
{
/* Online accounts do not currently have a target URI. */
g_set_str (&target_uri, _("Online Account"));
}
gtk_label_set_label (GTK_LABEL (self->target_uri), target_uri);
}
static void
update_icon (NautilusNetworkCell *self)
{
g_autoptr (NautilusViewItem) item = nautilus_view_cell_get_item (NAUTILUS_VIEW_CELL (self));
g_return_if_fail (item != NULL);
g_autoptr (GIcon) icon = nautilus_file_get_gicon (nautilus_view_item_get_file (item),
NAUTILUS_FILE_ICON_FLAGS_NONE);
gtk_image_set_from_gicon (GTK_IMAGE (self->icon), icon);
}
static void
on_file_changed (NautilusNetworkCell *self)
{
g_autoptr (NautilusViewItem) item = nautilus_view_cell_get_item (NAUTILUS_VIEW_CELL (self));
g_return_if_fail (item != NULL);
update_icon (self);
update_labels (self);
NautilusFile *file = nautilus_view_item_get_file (item);
gtk_widget_set_visible (self->unmount_button, nautilus_file_can_unmount (file));
}
static void
on_unmount_clicked (NautilusNetworkCell *self)
{
/* Select item first, because view.unmount-volume acts on selection. */
gtk_widget_activate_action (GTK_WIDGET (self), "listitem.select", "(bb)", FALSE, FALSE);
gtk_widget_activate_action (GTK_WIDGET (self), "view.unmount-volume", NULL);
}
static void
nautilus_network_cell_init (NautilusNetworkCell *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
/* Connect automatically to an item. */
self->item_signal_group = g_signal_group_new (NAUTILUS_TYPE_VIEW_ITEM);
g_signal_group_connect_swapped (self->item_signal_group, "notify::loading",
(GCallback) on_file_changed, self);
g_signal_group_connect_swapped (self->item_signal_group, "file-changed",
(GCallback) on_file_changed, self);
g_signal_connect_object (self->item_signal_group, "bind",
(GCallback) on_file_changed, self,
G_CONNECT_SWAPPED);
g_object_bind_property (self, "item",
self->item_signal_group, "target",
G_BINDING_SYNC_CREATE);
}
static void
nautilus_network_cell_dispose (GObject *object)
{
NautilusNetworkCell *self = (NautilusNetworkCell *) object;
gtk_widget_dispose_template (GTK_WIDGET (self), NAUTILUS_TYPE_NETWORK_CELL);
G_OBJECT_CLASS (nautilus_network_cell_parent_class)->dispose (object);
}
static void
nautilus_network_cell_finalize (GObject *object)
{
NautilusNetworkCell *self = (NautilusNetworkCell *) object;
g_clear_object (&self->item_signal_group);
G_OBJECT_CLASS (nautilus_network_cell_parent_class)->finalize (object);
}
static void
nautilus_network_cell_class_init (NautilusNetworkCellClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = nautilus_network_cell_dispose;
object_class->finalize = nautilus_network_cell_finalize;
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/nautilus/ui/nautilus-network-cell.ui");
gtk_widget_class_bind_template_child (widget_class, NautilusNetworkCell, icon);
gtk_widget_class_bind_template_child (widget_class, NautilusNetworkCell, target_uri);
gtk_widget_class_bind_template_child (widget_class, NautilusNetworkCell, unmount_button);
gtk_widget_class_bind_template_callback (widget_class, on_unmount_clicked);
}
NautilusViewCell *
nautilus_network_cell_new (NautilusListBase *view)
{
return NAUTILUS_VIEW_CELL (g_object_new (NAUTILUS_TYPE_NETWORK_CELL,
"view", view,
NULL));
}

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2024 António Fernandes <antoniof@gnome.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include "nautilus-view-cell.h"
G_BEGIN_DECLS
#define NAUTILUS_TYPE_NETWORK_CELL (nautilus_network_cell_get_type())
G_DECLARE_FINAL_TYPE (NautilusNetworkCell, nautilus_network_cell, NAUTILUS, NETWORK_CELL, NautilusViewCell)
NautilusViewCell * nautilus_network_cell_new (NautilusListBase *view);
G_END_DECLS

View File

@ -0,0 +1,627 @@
/*
* Copyright (C) 2024 António Fernandes <antoniof@gnome.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "nautilus-network-directory.h"
#include <gio/gio.h>
#include "nautilus-directory-private.h"
#include "nautilus-file-private.h"
#include "nautilus-file-utilities.h"
#include "nautilus-internal-place-file.h"
#include "nautilus-recent-servers.h"
#include "nautilus-scheme.h"
struct _NautilusNetworkDirectory
{
NautilusDirectory parent_slot;
NautilusDirectory *computer_backend_directory;
gboolean computer_backend_done_loading;
NautilusDirectory *network_backend_directory;
gboolean network_backend_done_loading;
NautilusRecentServers *recent_servers;
GList *recent_server_files;
gboolean recent_servers_done_loading;
GList /*<owned NetworkCallback>*/ *callback_list;
};
G_DEFINE_TYPE_WITH_CODE (NautilusNetworkDirectory, nautilus_network_directory, NAUTILUS_TYPE_DIRECTORY,
nautilus_ensure_extension_points ();
/* It looks like youre implementing an extension point.
* Did you modify nautilus_ensure_extension_builtins() accordingly?
*
* Yes
* Doing it right now
*/
g_io_extension_point_implement (NAUTILUS_DIRECTORY_PROVIDER_EXTENSION_POINT_NAME,
g_define_type_id,
NAUTILUS_NETWORK_DIRECTORY_PROVIDER_NAME,
0));
typedef struct
{
NautilusNetworkDirectory *self;
NautilusDirectoryCallback callback;
gpointer callback_data;
gboolean computer_backend_ready;
gboolean network_backend_ready;
} NetworkCallback;
static gboolean
mountable_file_is_remote (NautilusFile *file)
{
g_autoptr (GIcon) icon = nautilus_file_get_gicon (file, NAUTILUS_FILE_ICON_FLAGS_NONE);
/* HACK: It would be nice to have a "mountable::remote" attribute or
* something like that. Until then, rely on icon name to guess. */
if (G_IS_THEMED_ICON (icon))
{
const gchar * const *names = g_themed_icon_get_names (G_THEMED_ICON (icon));
for (gsize i = 0; names[i] != NULL; i++)
{
if (strstr (names[i], "network") || strstr (names[i], "remote"))
{
return TRUE;
}
}
}
return FALSE;
}
static GList *
get_remote_mountables (GList *mountable_files)
{
GList *remotes = NULL;
for (GList *l = mountable_files; l != NULL; l = l->next)
{
NautilusFile *file = NAUTILUS_FILE (l->data);
if (mountable_file_is_remote (file))
{
remotes = g_list_prepend (remotes, g_object_ref (file));
}
}
return remotes;
}
static gboolean
real_are_all_files_seen (NautilusDirectory *directory)
{
NautilusNetworkDirectory *self = NAUTILUS_NETWORK_DIRECTORY (directory);
return (nautilus_directory_are_all_files_seen (self->computer_backend_directory) &&
nautilus_directory_are_all_files_seen (self->network_backend_directory) &&
self->recent_servers_done_loading);
}
static gboolean
real_contains_file (NautilusDirectory *directory,
NautilusFile *file)
{
NautilusNetworkDirectory *self = NAUTILUS_NETWORK_DIRECTORY (directory);
if (nautilus_file_get_directory (file) == directory)
{
/* Recent server files are directly owned by NautilusNetworkDirectory. */
return TRUE;
}
if (nautilus_directory_contains_file (self->network_backend_directory, file))
{
return TRUE;
}
if (nautilus_directory_contains_file (self->computer_backend_directory, file))
{
return mountable_file_is_remote (file);
}
return FALSE;
}
static void
on_backend_directory_done_loading (NautilusDirectory *backend_directory,
gpointer callback_data)
{
NautilusNetworkDirectory *self = callback_data;
if (backend_directory == self->computer_backend_directory)
{
self->computer_backend_done_loading = TRUE;
}
else if (backend_directory == self->network_backend_directory)
{
self->network_backend_done_loading = TRUE;
}
else
{
/* Called from on_recent_servers_loading_changed () */
g_assert (backend_directory == (NautilusDirectory *) self &&
self->recent_servers_done_loading);
}
if (self->computer_backend_done_loading &&
self->network_backend_done_loading &&
self->recent_servers_done_loading)
{
nautilus_directory_emit_done_loading (NAUTILUS_DIRECTORY (self));
}
}
static void
real_force_reload (NautilusDirectory *directory)
{
NautilusNetworkDirectory *self = NAUTILUS_NETWORK_DIRECTORY (directory);
self->computer_backend_done_loading = FALSE;
nautilus_directory_force_reload (self->computer_backend_directory);
self->network_backend_done_loading = FALSE;
nautilus_directory_force_reload (self->network_backend_directory);
self->recent_servers_done_loading = FALSE;
nautilus_recent_servers_force_reload (self->recent_servers);
}
static void
on_backend_directory_ready (NautilusDirectory *backend_directory,
GList *unused_parameter,
gpointer callback_data)
{
NetworkCallback *network_callback = callback_data;
NautilusNetworkDirectory *self = network_callback->self;
if (backend_directory == self->computer_backend_directory)
{
network_callback->computer_backend_ready = TRUE;
}
else if (backend_directory == self->network_backend_directory)
{
network_callback->network_backend_ready = TRUE;
}
else
{
g_assert (backend_directory == (NautilusDirectory *) self &&
network_callback->self->recent_servers_done_loading);
}
if (network_callback->computer_backend_ready &&
network_callback->network_backend_ready &&
network_callback->self->recent_servers_done_loading)
{
g_autolist (NautilusFile) files = nautilus_directory_get_file_list (NAUTILUS_DIRECTORY (self));
/* Invoke ready callback */
(*network_callback->callback)(NAUTILUS_DIRECTORY (self), files, network_callback->callback_data);
/* Remove it from pending callbacks list and free it */
self->callback_list = g_list_remove (self->callback_list, network_callback);
g_free (network_callback);
}
}
static void
on_recent_servers_loading_changed (GObject *object,
GParamSpec *pspec,
gpointer user_data)
{
NautilusNetworkDirectory *self = NAUTILUS_NETWORK_DIRECTORY (user_data);
NautilusRecentServers *recent_servers = NAUTILUS_RECENT_SERVERS (object);
gboolean is_loading = nautilus_recent_servers_get_loading (recent_servers);
self->recent_servers_done_loading = !is_loading;
if (self->recent_servers_done_loading)
{
NautilusDirectory *self_as_directory = NAUTILUS_DIRECTORY (self);
on_backend_directory_done_loading (self_as_directory, self);
for (GList *l = self->callback_list; l != NULL; l = l->next)
{
on_backend_directory_ready (self_as_directory, NULL, l->data);
}
}
}
static void
on_computer_backend_directory_files_added (NautilusNetworkDirectory *self,
GList *added_files)
{
g_autolist (NautilusFile) files = get_remote_mountables (added_files);
if (files == NULL)
{
return;
}
nautilus_directory_emit_files_added (NAUTILUS_DIRECTORY (self), files);
}
static void
on_computer_backend_directory_files_changed (NautilusNetworkDirectory *self,
GList *changed_files)
{
g_autolist (NautilusFile) files = get_remote_mountables (changed_files);
if (files == NULL)
{
return;
}
nautilus_directory_emit_files_changed (NAUTILUS_DIRECTORY (self), files);
}
static NautilusFile *
get_recent_server_file (NautilusDirectory *directory,
GFileInfo *server_info)
{
g_autofree char *uri = g_strconcat (SCHEME_NETWORK_VIEW ":///",
g_file_info_get_name (server_info),
NULL);
g_autoptr (NautilusFile) file = nautilus_file_get_by_uri (uri);
nautilus_file_update_info (file, server_info);
return g_steal_pointer (&file);
}
static void
on_recent_servers_added (NautilusNetworkDirectory *self,
GList *servers)
{
NautilusDirectory *dir = NAUTILUS_DIRECTORY (self);
g_autolist (NautilusFile) added_files = NULL;
for (GList *l = servers; l != NULL; l = l->next)
{
GFileInfo *server_info = l->data;
g_autoptr (NautilusFile) file = get_recent_server_file (dir, server_info);
self->recent_server_files = g_list_prepend (self->recent_server_files,
g_object_ref (file));
added_files = g_list_prepend (added_files, g_steal_pointer (&file));
}
nautilus_directory_emit_files_added (dir, added_files);
}
static void
on_recent_servers_changed (NautilusNetworkDirectory *self,
GList *servers)
{
g_autolist (NautilusFile) changed_files = NULL;
for (GList *l = servers; l != NULL; l = l->next)
{
GFileInfo *server_info = l->data;
NautilusFile *file = nautilus_directory_find_file_by_name (NAUTILUS_DIRECTORY (self),
g_file_info_get_name (server_info));
if (file == NULL)
{
g_critical ("Notified change on recent server whose random GUID name was not known yet");
continue;
}
nautilus_file_update_info (file, server_info);
changed_files = g_list_prepend (changed_files, g_object_ref (file));
}
nautilus_directory_emit_files_changed (NAUTILUS_DIRECTORY (self), changed_files);
}
static void
on_recent_servers_removed (NautilusNetworkDirectory *self,
GList *servers)
{
g_autolist (NautilusFile) removed_files = NULL;
for (GList *l = servers; l != NULL; l = l->next)
{
GFileInfo *server_info = l->data;
NautilusFile *file = nautilus_directory_find_file_by_name (NAUTILUS_DIRECTORY (self),
g_file_info_get_name (server_info));
if (file == NULL)
{
g_critical ("Notified removal of recent server whose random GUID name was not known yet");
continue;
}
nautilus_file_mark_gone (file);
/* Steal file from self->recent_server_files */
GList *link = g_list_find (self->recent_server_files, file);
self->recent_server_files = g_list_remove_link (self->recent_server_files, link);
removed_files = g_list_concat (link, removed_files);
}
nautilus_directory_emit_files_changed (NAUTILUS_DIRECTORY (self), removed_files);
}
static NetworkCallback *
network_callback_find (NautilusNetworkDirectory *self,
NautilusDirectoryCallback callback,
gpointer callback_data)
{
for (GList *l = self->callback_list; l != NULL; l = l->next)
{
NetworkCallback *network_callback = l->data;
if (network_callback->callback == callback &&
network_callback->callback_data == callback_data)
{
return network_callback;
}
}
return NULL;
}
static void
real_call_when_ready (NautilusDirectory *directory,
NautilusFileAttributes file_attributes,
gboolean wait_for_file_list,
NautilusDirectoryCallback callback,
gpointer callback_data)
{
NautilusNetworkDirectory *self = NAUTILUS_NETWORK_DIRECTORY (directory);
NetworkCallback *network_callback;
network_callback = network_callback_find (self, callback, callback_data);
if (network_callback != NULL)
{
g_warning ("tried to add a new callback while an old one was pending");
return;
}
network_callback = g_new0 (NetworkCallback, 1);
network_callback->self = self;
network_callback->callback = callback;
network_callback->callback_data = callback_data;
self->callback_list = g_list_prepend (self->callback_list, network_callback);
nautilus_directory_call_when_ready (self->computer_backend_directory,
file_attributes,
wait_for_file_list,
on_backend_directory_ready, network_callback);
nautilus_directory_call_when_ready (self->network_backend_directory,
file_attributes,
wait_for_file_list,
on_backend_directory_ready, network_callback);
}
static void
real_cancel_callback (NautilusDirectory *directory,
NautilusDirectoryCallback callback,
gpointer callback_data)
{
NautilusNetworkDirectory *self = NAUTILUS_NETWORK_DIRECTORY (directory);
NetworkCallback *network_callback;
network_callback = network_callback_find (self, callback, callback_data);
if (network_callback == NULL)
{
/* No warning needed, because nautilus_directory_cancel_callback() is
* meant to be used unconditionally as cleanup. */
return;
}
if (!network_callback->computer_backend_ready)
{
nautilus_directory_cancel_callback (self->computer_backend_directory, on_backend_directory_ready, network_callback);
}
if (!network_callback->network_backend_ready)
{
nautilus_directory_cancel_callback (self->network_backend_directory, on_backend_directory_ready, network_callback);
}
self->callback_list = g_list_remove (self->callback_list, network_callback);
g_free (network_callback);
}
static void
real_file_monitor_add (NautilusDirectory *directory,
gconstpointer client,
gboolean monitor_hidden_files,
NautilusFileAttributes file_attributes,
NautilusDirectoryCallback callback,
gpointer callback_data)
{
NautilusNetworkDirectory *self = NAUTILUS_NETWORK_DIRECTORY (directory);
nautilus_directory_file_monitor_add (self->computer_backend_directory,
client,
monitor_hidden_files,
file_attributes,
NULL, NULL);
nautilus_directory_file_monitor_add (self->network_backend_directory,
client,
monitor_hidden_files,
file_attributes,
NULL, NULL);
if (callback != NULL)
{
g_autolist (NautilusFile) files = nautilus_directory_get_file_list (directory);
(*callback)(directory, files, callback_data);
}
}
static void
real_file_monitor_remove (NautilusDirectory *directory,
gconstpointer client)
{
NautilusNetworkDirectory *self = NAUTILUS_NETWORK_DIRECTORY (directory);
nautilus_directory_file_monitor_remove (self->computer_backend_directory, client);
nautilus_directory_file_monitor_remove (self->network_backend_directory, client);
}
static GList *
real_get_file_list (NautilusDirectory *directory)
{
NautilusNetworkDirectory *self = NAUTILUS_NETWORK_DIRECTORY (directory);
g_autolist (NautilusFile) computer_list = nautilus_directory_get_file_list (self->computer_backend_directory);
g_autolist (NautilusFile) network_list = nautilus_directory_get_file_list (self->network_backend_directory);
g_autolist (NautilusFile) recent_servers = nautilus_file_list_copy (self->recent_server_files);
return g_list_concat (get_remote_mountables (computer_list),
g_list_concat (g_steal_pointer (&recent_servers),
g_steal_pointer (&network_list)));
}
static gboolean
real_is_not_empty (NautilusDirectory *directory)
{
NautilusNetworkDirectory *self = NAUTILUS_NETWORK_DIRECTORY (directory);
if (self->recent_server_files != NULL ||
nautilus_directory_is_not_empty (self->network_backend_directory))
{
return TRUE;
}
if (nautilus_directory_is_not_empty (self->computer_backend_directory))
{
g_autolist (NautilusFile) computer_list = nautilus_directory_get_file_list (self->computer_backend_directory);
g_autolist (NautilusFile) remote_mountables = get_remote_mountables (computer_list);
if (remote_mountables != NULL)
{
return TRUE;
}
}
return FALSE;
}
static gboolean
real_is_editable (NautilusDirectory *directory)
{
return FALSE;
}
static gboolean
real_handles_location (GFile *location)
{
return g_file_has_uri_scheme (location, SCHEME_NETWORK_VIEW);
}
static NautilusFile *
real_new_file_from_filename (NautilusDirectory *directory,
const char *filename,
gboolean self_owned)
{
if (!self_owned)
{
/* Children are regular vfs locations. */
return NAUTILUS_DIRECTORY_CLASS (nautilus_network_directory_parent_class)->new_file_from_filename (directory, filename, self_owned);
}
return NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_INTERNAL_PLACE_FILE,
"directory", directory,
NULL));
}
static void
nautilus_network_directory_dispose (GObject *object)
{
NautilusNetworkDirectory *self = NAUTILUS_NETWORK_DIRECTORY (object);
g_clear_list (&self->recent_server_files, g_object_unref);
g_clear_list (&self->callback_list, g_free);
G_OBJECT_CLASS (nautilus_network_directory_parent_class)->dispose (object);
}
static void
nautilus_network_directory_finalize (GObject *object)
{
NautilusNetworkDirectory *self = NAUTILUS_NETWORK_DIRECTORY (object);
g_clear_object (&self->computer_backend_directory);
g_clear_object (&self->network_backend_directory);
g_clear_object (&self->recent_servers);
G_OBJECT_CLASS (nautilus_network_directory_parent_class)->finalize (object);
}
static void
nautilus_network_directory_init (NautilusNetworkDirectory *self)
{
self->computer_backend_directory = nautilus_directory_get_by_uri (SCHEME_COMPUTER ":///");
g_signal_connect_object (self->computer_backend_directory, "files-added",
G_CALLBACK (on_computer_backend_directory_files_added), self, G_CONNECT_SWAPPED);
g_signal_connect_object (self->computer_backend_directory, "files-changed",
G_CALLBACK (on_computer_backend_directory_files_changed), self, G_CONNECT_SWAPPED);
g_signal_connect_object (self->computer_backend_directory, "done-loading",
G_CALLBACK (on_backend_directory_done_loading), self, G_CONNECT_DEFAULT);
g_signal_connect_object (self->computer_backend_directory, "load-error",
G_CALLBACK (nautilus_directory_emit_load_error), self, G_CONNECT_SWAPPED);
self->network_backend_directory = nautilus_directory_get_by_uri (SCHEME_NETWORK ":///");
g_signal_connect_object (self->network_backend_directory, "files-added",
G_CALLBACK (nautilus_directory_emit_files_added), self, G_CONNECT_SWAPPED);
g_signal_connect_object (self->network_backend_directory, "files-changed",
G_CALLBACK (nautilus_directory_emit_files_changed), self, G_CONNECT_SWAPPED);
g_signal_connect_object (self->network_backend_directory, "done-loading",
G_CALLBACK (on_backend_directory_done_loading), self, G_CONNECT_DEFAULT);
g_signal_connect_object (self->network_backend_directory, "load-error",
G_CALLBACK (nautilus_directory_emit_load_error), self, G_CONNECT_SWAPPED);
self->recent_servers = nautilus_recent_servers_new ();
g_signal_connect_object (self->recent_servers, "notify::loading",
G_CALLBACK (on_recent_servers_loading_changed), self, G_CONNECT_DEFAULT);
g_signal_connect_object (self->recent_servers, "added",
G_CALLBACK (on_recent_servers_added), self, G_CONNECT_SWAPPED);
g_signal_connect_object (self->recent_servers, "changed",
G_CALLBACK (on_recent_servers_changed), self, G_CONNECT_SWAPPED);
g_signal_connect_object (self->recent_servers, "removed",
G_CALLBACK (on_recent_servers_removed), self, G_CONNECT_SWAPPED);
}
static void
nautilus_network_directory_class_init (NautilusNetworkDirectoryClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
NautilusDirectoryClass *directory_class = NAUTILUS_DIRECTORY_CLASS (klass);
object_class->finalize = nautilus_network_directory_finalize;
object_class->dispose = nautilus_network_directory_dispose;
directory_class->are_all_files_seen = real_are_all_files_seen;
directory_class->contains_file = real_contains_file;
directory_class->force_reload = real_force_reload;
directory_class->call_when_ready = real_call_when_ready;
directory_class->cancel_callback = real_cancel_callback;
directory_class->file_monitor_add = real_file_monitor_add;
directory_class->file_monitor_remove = real_file_monitor_remove;
directory_class->get_file_list = real_get_file_list;
directory_class->is_not_empty = real_is_not_empty;
directory_class->is_editable = real_is_editable;
directory_class->handles_location = real_handles_location;
directory_class->new_file_from_filename = real_new_file_from_filename;
}
NautilusNetworkDirectory *
nautilus_network_directory_new (void)
{
g_autoptr (GFile) location = g_file_new_for_uri (SCHEME_NETWORK_VIEW ":///");
return g_object_new (NAUTILUS_TYPE_NETWORK_DIRECTORY,
"location", location,
NULL);
}

View File

@ -0,0 +1,22 @@
/*
* Copyright (C) 2024 António Fernandes <antoniof@gnome.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include "nautilus-directory.h"
G_BEGIN_DECLS
#define NAUTILUS_NETWORK_DIRECTORY_PROVIDER_NAME "network-directory-provider"
#define NAUTILUS_TYPE_NETWORK_DIRECTORY (nautilus_network_directory_get_type ())
G_DECLARE_FINAL_TYPE (NautilusNetworkDirectory, nautilus_network_directory, NAUTILUS, NETWORK_DIRECTORY, NautilusDirectory);
NautilusNetworkDirectory* nautilus_network_directory_new (void);
G_END_DECLS

394
src/nautilus-network-view.c Normal file
View File

@ -0,0 +1,394 @@
/*
* Copyright (C) 2024 The GNOME project contributors
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "nautilus-list-base-private.h"
#include "nautilus-network-view.h"
#include <glib/gi18n.h>
#include "nautilus-global-preferences.h"
#include "nautilus-network-cell.h"
#include "nautilus-scheme.h"
struct _NautilusNetworkView
{
NautilusListBase parent_instance;
GtkListView *view_ui;
};
G_DEFINE_TYPE (NautilusNetworkView, nautilus_network_view, NAUTILUS_TYPE_LIST_BASE)
#define get_view_item(li) \
(NAUTILUS_VIEW_ITEM (gtk_tree_list_row_get_item (GTK_TREE_LIST_ROW (gtk_list_item_get_item (li)))))
static const NautilusViewInfo network_view_info =
{
.view_id = NAUTILUS_VIEW_NETWORK_ID,
.zoom_level_min = NAUTILUS_LIST_ZOOM_LEVEL_SMALL,
.zoom_level_max = NAUTILUS_LIST_ZOOM_LEVEL_SMALL,
.zoom_level_standard = NAUTILUS_LIST_ZOOM_LEVEL_SMALL,
};
static NautilusViewInfo
real_get_view_info (NautilusListBase *list_base)
{
return network_view_info;
}
enum
{
SECTION_CONNECTED,
SECTION_PREVIOUS,
SECTION_AVAILABLE,
};
static inline gint
get_section (NautilusViewItem *item)
{
NautilusFile *file = nautilus_view_item_get_file (item);
if (nautilus_file_can_unmount (file))
{
return SECTION_CONNECTED;
}
g_autoptr (GFile) location = nautilus_file_get_location (file);
if (g_file_has_uri_scheme (location, SCHEME_NETWORK))
{
return SECTION_AVAILABLE;
}
else
{
return SECTION_PREVIOUS;
}
}
static gint
sort_network_sections (gconstpointer a,
gconstpointer b,
gpointer user_data)
{
GtkTreeListRow *row_a = GTK_TREE_LIST_ROW ((gpointer) a);
GtkTreeListRow *row_b = GTK_TREE_LIST_ROW ((gpointer) b);
g_autoptr (NautilusViewItem) item_a = NAUTILUS_VIEW_ITEM (gtk_tree_list_row_get_item (row_a));
g_autoptr (NautilusViewItem) item_b = NAUTILUS_VIEW_ITEM (gtk_tree_list_row_get_item (row_b));
return get_section (item_a) - get_section (item_b);
}
static gint
sort_network_items (gconstpointer a,
gconstpointer b,
gpointer user_data)
{
NautilusViewItem *item_a = NAUTILUS_VIEW_ITEM ((gpointer) a);
NautilusViewItem *item_b = NAUTILUS_VIEW_ITEM ((gpointer) b);
NautilusFile *file_a = nautilus_view_item_get_file (item_a);
NautilusFile *file_b = nautilus_view_item_get_file (item_b);
if (get_section (item_a) == SECTION_PREVIOUS &&
get_section (item_a) == SECTION_PREVIOUS)
{
return nautilus_file_compare_for_sort (file_a, file_b,
NAUTILUS_FILE_SORT_BY_ATIME,
FALSE, TRUE /* reversed */);
}
return nautilus_file_compare_for_sort (file_a, file_b,
NAUTILUS_FILE_SORT_BY_DISPLAY_NAME,
FALSE, FALSE);
}
static void
real_set_zoom_level (NautilusListBase *list_base,
int new_level)
{
g_warn_if_fail (new_level == network_view_info.zoom_level_standard);
}
/* We only care about the keyboard activation part that GtkListView provides,
* but we don't need any special filtering here. Indeed, we ask GtkListView
* to not activate on single click, and we get to handle double clicks before
* GtkListView does (as one of widget subclassing's goal is to modify the parent
* class's behavior), while claiming the click gestures, so it means GtkListView
* will never react to a click event to emit this signal. So we should be pretty
* safe here with regards to our custom item click handling.
*/
static void
on_list_view_item_activated (GtkListView *list_view,
guint position,
gpointer user_data)
{
NautilusNetworkView *self = NAUTILUS_NETWORK_VIEW (user_data);
nautilus_list_base_activate_selection (NAUTILUS_LIST_BASE (self), FALSE);
}
static void
real_popup_background_context_menu (NautilusListBase *self,
double x,
double y)
{
g_signal_stop_emission_by_name (G_OBJECT (self), "popup-background-context-menu");
}
static guint
real_get_icon_size (NautilusListBase *list_base_view)
{
return NAUTILUS_LIST_ICON_SIZE_SMALL;
}
static GtkWidget *
real_get_view_ui (NautilusListBase *list_base_view)
{
NautilusNetworkView *self = NAUTILUS_NETWORK_VIEW (list_base_view);
return GTK_WIDGET (self->view_ui);
}
static int
real_get_zoom_level (NautilusListBase *list_base_view)
{
return network_view_info.zoom_level_standard;
}
static void
real_scroll_to (NautilusListBase *list_base_view,
guint position,
GtkListScrollFlags flags,
GtkScrollInfo *scroll)
{
NautilusNetworkView *self = NAUTILUS_NETWORK_VIEW (list_base_view);
gtk_list_view_scroll_to (self->view_ui, position, flags, scroll);
}
static GVariant *
real_get_sort_state (NautilusListBase *list_base)
{
return g_variant_take_ref (g_variant_new ("(sb)", "invalid", FALSE));
}
static void
real_set_sort_state (NautilusListBase *list_base,
GVariant *value)
{
/* No op */
}
static void
nautilus_network_view_dispose (GObject *object)
{
G_OBJECT_CLASS (nautilus_network_view_parent_class)->dispose (object);
}
static void
nautilus_network_view_finalize (GObject *object)
{
G_OBJECT_CLASS (nautilus_network_view_parent_class)->finalize (object);
}
static void
bind_cell (GtkSignalListItemFactory *factory,
GtkListItem *listitem,
gpointer user_data)
{
GtkWidget *cell = gtk_list_item_get_child (listitem);
g_autoptr (NautilusViewItem) item = get_view_item (listitem);
nautilus_view_item_set_item_ui (item, cell);
}
static void
unbind_cell (GtkSignalListItemFactory *factory,
GtkListItem *listitem,
gpointer user_data)
{
g_autoptr (NautilusViewItem) item = get_view_item (listitem);
/* item may be NULL when row has just been destroyed. */
if (item != NULL)
{
nautilus_view_item_set_item_ui (item, NULL);
}
}
static void
setup_cell (GtkSignalListItemFactory *factory,
GtkListItem *listitem,
gpointer user_data)
{
NautilusNetworkView *self = NAUTILUS_NETWORK_VIEW (user_data);
NautilusViewCell *cell;
GtkExpression *expression;
cell = nautilus_network_cell_new (NAUTILUS_LIST_BASE (self));
gtk_list_item_set_child (listitem, GTK_WIDGET (cell));
setup_cell_common (G_OBJECT (listitem), cell);
setup_cell_hover (cell);
g_object_bind_property (self, "icon-size",
cell, "icon-size",
G_BINDING_SYNC_CREATE);
/* Use file display name as accessible label. Explaining in pseudo-code:
* listitem:accessible-name :- listitem:item:item:file:display-name */
expression = gtk_property_expression_new (GTK_TYPE_LIST_ITEM, NULL, "item");
expression = gtk_property_expression_new (GTK_TYPE_TREE_LIST_ROW, expression, "item");
expression = gtk_property_expression_new (NAUTILUS_TYPE_VIEW_ITEM, expression, "file");
expression = gtk_property_expression_new (NAUTILUS_TYPE_FILE, expression, "display-name");
gtk_expression_bind (expression, listitem, "accessible-label", listitem);
}
static void
bind_header (GtkSignalListItemFactory *factory,
GtkListHeader *listheader,
gpointer user_data)
{
GtkWidget *label = gtk_list_header_get_child (listheader);
GtkTreeListRow *row = GTK_TREE_LIST_ROW (gtk_list_header_get_item (listheader));
g_autoptr (NautilusViewItem) item = NAUTILUS_VIEW_ITEM (gtk_tree_list_row_get_item (row));
switch (get_section (item))
{
case SECTION_CONNECTED:
{
/* Translators: This refers to network places which are currently mounted */
gtk_label_set_label (GTK_LABEL (label), _("Connected"));
}
break;
case SECTION_PREVIOUS:
{
/* Translators: This refers to network servers the user has previously connected to */
gtk_label_set_label (GTK_LABEL (label), _("Previous"));
}
break;
case SECTION_AVAILABLE:
{
gtk_label_set_label (GTK_LABEL (label), _("Available on Current Network"));
/* TODO: Use network name from NMClient:primary-connection:id to
* match design mockup: "Available on Network1234"
*/
}
break;
default:
{
g_assert_not_reached ();
}
}
}
static void
setup_header (GtkSignalListItemFactory *factory,
GtkListHeader *listheader,
gpointer user_data)
{
GtkWidget *label = gtk_label_new (NULL);
gtk_widget_add_css_class (label, "heading");
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_list_header_set_child (listheader, label);
}
static void
on_model_changed (NautilusNetworkView *self)
{
NautilusViewModel *model = nautilus_list_base_get_model (NAUTILUS_LIST_BASE (self));
if (model != NULL)
{
g_autoptr (GtkCustomSorter) sorter = gtk_custom_sorter_new (sort_network_items, self, NULL);
g_autoptr (GtkCustomSorter) sections_sorter = gtk_custom_sorter_new (sort_network_sections, self, NULL);
nautilus_view_model_set_sorter (model, GTK_SORTER (sorter));
nautilus_view_model_set_section_sorter (model, GTK_SORTER (sections_sorter));
}
gtk_list_view_set_model (self->view_ui, GTK_SELECTION_MODEL (model));
}
static GtkListView *
create_view_ui (NautilusNetworkView *self)
{
g_autoptr (GtkListItemFactory) factory = gtk_signal_list_item_factory_new ();
g_autoptr (GtkListItemFactory) header_factory = gtk_signal_list_item_factory_new ();
GtkListView *list_view;
g_signal_connect (factory, "setup", G_CALLBACK (setup_cell), self);
g_signal_connect (factory, "bind", G_CALLBACK (bind_cell), self);
g_signal_connect (factory, "unbind", G_CALLBACK (unbind_cell), self);
list_view = GTK_LIST_VIEW (gtk_list_view_new (NULL, g_steal_pointer (&factory)));
g_signal_connect (header_factory, "setup", G_CALLBACK (setup_header), self);
g_signal_connect (header_factory, "bind", G_CALLBACK (bind_header), self);
gtk_list_view_set_header_factory (list_view, header_factory);
/* We don't use the built-in child activation feature for clicks because it
* doesn't fill all our needs nor does it match our expected behavior.
* Instead, we roll our own event handling and double/single click mode.
* However, GtkListView:single-click-activate has other effects besides
* activation, as it affects the selection behavior as well (e.g. selects on
* hover). Setting it to FALSE gives us the expected behavior. */
gtk_list_view_set_single_click_activate (list_view, FALSE);
gtk_list_view_set_enable_rubberband (list_view, FALSE);
gtk_list_view_set_tab_behavior (list_view, GTK_LIST_TAB_ITEM);
/* While we don't want to use GTK's click activation, we'll let it handle
* the key activation part (with Enter). */
g_signal_connect (list_view, "activate", G_CALLBACK (on_list_view_item_activated), self);
return list_view;
}
static void
nautilus_network_view_class_init (NautilusNetworkViewClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
NautilusListBaseClass *list_base_view_class = NAUTILUS_LIST_BASE_CLASS (klass);
object_class->dispose = nautilus_network_view_dispose;
object_class->finalize = nautilus_network_view_finalize;
list_base_view_class->get_icon_size = real_get_icon_size;
list_base_view_class->get_sort_state = real_get_sort_state;
list_base_view_class->get_view_info = real_get_view_info;
list_base_view_class->get_view_ui = real_get_view_ui;
list_base_view_class->get_zoom_level = real_get_zoom_level;
list_base_view_class->popup_background_context_menu = real_popup_background_context_menu;
list_base_view_class->scroll_to = real_scroll_to;
list_base_view_class->set_sort_state = real_set_sort_state;
list_base_view_class->set_zoom_level = real_set_zoom_level;
}
static void
nautilus_network_view_init (NautilusNetworkView *self)
{
GtkWidget *scrolled_window = nautilus_list_base_get_scrolled_window (NAUTILUS_LIST_BASE (self));
gtk_widget_add_css_class (GTK_WIDGET (self), "nautilus-network-view");
self->view_ui = create_view_ui (self);
nautilus_list_base_setup_gestures (NAUTILUS_LIST_BASE (self));
g_signal_connect_swapped (self, "notify::model", G_CALLBACK (on_model_changed), self);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolled_window),
GTK_WIDGET (self->view_ui));
nautilus_list_base_set_zoom_level (NAUTILUS_LIST_BASE (self), network_view_info.zoom_level_standard);
}
NautilusNetworkView *
nautilus_network_view_new (void)
{
return g_object_new (NAUTILUS_TYPE_NETWORK_VIEW, NULL);
}

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2024 The GNOME project contributors
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include "nautilus-list-base.h"
G_BEGIN_DECLS
#define NAUTILUS_TYPE_NETWORK_VIEW (nautilus_network_view_get_type())
G_DECLARE_FINAL_TYPE (NautilusNetworkView, nautilus_network_view, NAUTILUS, NETWORK_VIEW, NautilusListBase)
NautilusNetworkView *nautilus_network_view_new (void);
G_END_DECLS

View File

@ -25,7 +25,6 @@
#include "nautilus-pathbar.h"
#include "nautilus-properties-window.h"
#include "nautilus-application.h"
#include "nautilus-dnd.h"
#include "nautilus-enums.h"
#include "nautilus-enum-types.h"
@ -36,7 +35,6 @@
#include "nautilus-scheme.h"
#include "nautilus-trash-monitor.h"
#include "nautilus-ui-utilities.h"
#include "nautilus-window.h"
#ifdef GDK_WINDOWING_X11
#include <gdk/x11/gdkx.h>
@ -51,7 +49,6 @@ enum
typedef enum
{
NORMAL_BUTTON,
OTHER_LOCATIONS_BUTTON,
ROOT_BUTTON,
ADMIN_ROOT_BUTTON,
HOME_BUTTON,
@ -59,12 +56,22 @@ typedef enum
RECENT_BUTTON,
MOUNT_BUTTON,
TRASH_BUTTON,
NETWORK_BUTTON,
} ButtonType;
#define BUTTON_DATA(x) ((ButtonData *) (x))
static guint path_bar_signals[LAST_SIGNAL] = { 0 };
enum
{
PROP_0,
PROP_WINDOW_SLOT,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
#define NAUTILUS_PATH_BAR_BUTTON_ELLIPSIZE_MINIMUM_CHARS 7
typedef struct
@ -115,6 +122,8 @@ struct _NautilusPathBar
GMenu *button_menu;
gchar *os_name;
NautilusWindowSlot *slot;
};
G_DEFINE_TYPE (NautilusPathBar, nautilus_path_bar, GTK_TYPE_BOX);
@ -335,6 +344,8 @@ nautilus_path_bar_finalize (GObject *object)
g_clear_object (&self->current_view_menu_popover);
g_free (self->os_name);
g_clear_weak_pointer (&self->slot);
unschedule_pop_up_context_menu (NAUTILUS_PATH_BAR (object));
G_OBJECT_CLASS (nautilus_path_bar_parent_class)->finalize (object);
@ -381,16 +392,6 @@ get_dir_name (ButtonData *button_data)
return _("Home");
}
case OTHER_LOCATIONS_BUTTON:
{
return _("Other Locations");
}
case STARRED_BUTTON:
{
return _("Starred");
}
default:
{
return button_data->dir_name;
@ -413,6 +414,29 @@ button_data_free (ButtonData *button_data)
g_free (button_data);
}
static void
nautilus_path_bar_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
NautilusPathBar *self = NAUTILUS_PATH_BAR (object);
switch (property_id)
{
case PROP_WINDOW_SLOT:
{
g_set_weak_pointer (&self->slot, g_value_get_object (value));
}
break;
default:
{
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
break;
}
}
static void
nautilus_path_bar_class_init (NautilusPathBarClass *path_bar_class)
@ -423,6 +447,7 @@ nautilus_path_bar_class_init (NautilusPathBarClass *path_bar_class)
gobject_class->finalize = nautilus_path_bar_finalize;
gobject_class->dispose = nautilus_path_bar_dispose;
gobject_class->set_property = nautilus_path_bar_set_property;
path_bar_signals [OPEN_LOCATION] =
g_signal_new ("open-location",
@ -433,6 +458,13 @@ nautilus_path_bar_class_init (NautilusPathBarClass *path_bar_class)
G_TYPE_NONE, 2,
G_TYPE_FILE,
NAUTILUS_TYPE_OPEN_FLAGS);
properties [PROP_WINDOW_SLOT] =
g_param_spec_object ("window-slot", NULL, NULL,
NAUTILUS_TYPE_WINDOW_SLOT,
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
}
void
@ -698,22 +730,19 @@ on_click_gesture_pressed (GtkGestureClick *gesture,
static void
switch_location (ButtonData *button_data)
{
GFile *location;
GtkRoot *window;
if (button_data->file == NULL)
{
return;
}
window = gtk_widget_get_root (button_data->button);
g_assert (NAUTILUS_IS_WINDOW (window));
NautilusPathBar *self = button_data->path_bar;
g_autoptr (GFile) location = nautilus_file_get_location (button_data->file);
location = nautilus_file_get_location (button_data->file);
nautilus_application_open_location_full (NAUTILUS_APPLICATION (g_application_get_default ()),
g_return_if_fail (self->slot != NULL);
nautilus_window_slot_open_location_full (self->slot,
location, NAUTILUS_OPEN_FLAG_DONT_MAKE_ACTIVE,
NULL, NAUTILUS_WINDOW (window), NULL);
g_object_unref (location);
NULL);
}
static gboolean
@ -807,23 +836,20 @@ on_drag_drop (GtkDropTarget *target,
gdouble y,
gpointer user_data)
{
GtkRoot *window;
NautilusWindowSlot *target_slot;
ButtonData *button_data = user_data;
NautilusPathBar *self = button_data->path_bar;
NautilusFilesView *target_view;
g_autoptr (GFile) target_location = NULL;
ButtonData *button_data = user_data;
GdkDragAction action;
window = gtk_widget_get_root (button_data->button);
g_assert (NAUTILUS_IS_WINDOW (window));
g_return_if_fail (self->slot != NULL);
target_slot = nautilus_window_get_active_slot (NAUTILUS_WINDOW (window));
target_location = nautilus_file_get_location (button_data->file);
target_view = NAUTILUS_FILES_VIEW (nautilus_window_slot_get_current_view (target_slot));
target_view = NAUTILUS_FILES_VIEW (nautilus_window_slot_get_current_view (self->slot));
action = gdk_drop_get_actions (gtk_drop_target_get_current_drop (target));
#ifdef GDK_WINDOWING_X11
if (GDK_IS_X11_DISPLAY (gtk_widget_get_display (GTK_WIDGET (window))))
if (GDK_IS_X11_DISPLAY (gtk_widget_get_display (GTK_WIDGET (self))))
{
/* Temporary workaround until the below GTK MR (or equivalent fix)
* is merged. Without this fix, the preferred action isn't set correctly.
@ -885,16 +911,16 @@ get_gicon (ButtonData *button_data)
return g_themed_icon_new ("document-open-recent-symbolic");
}
case OTHER_LOCATIONS_BUTTON:
{
return g_themed_icon_new ("list-add-symbolic");
}
case TRASH_BUTTON:
{
return nautilus_trash_monitor_get_symbolic_icon ();
}
case NETWORK_BUTTON:
{
return g_themed_icon_new ("folder-remote-symbolic");
}
default:
{
return NULL;
@ -1005,11 +1031,6 @@ setup_button_type (ButtonData *button_data,
button_data->type = MOUNT_BUTTON;
button_data->is_root = TRUE;
}
else if (g_file_has_uri_scheme (location, SCHEME_OTHER_LOCATIONS))
{
button_data->type = OTHER_LOCATIONS_BUTTON;
button_data->is_root = TRUE;
}
else if (nautilus_is_root_for_scheme (location, SCHEME_ADMIN))
{
button_data->type = ADMIN_ROOT_BUTTON;
@ -1020,6 +1041,11 @@ setup_button_type (ButtonData *button_data,
button_data->type = TRASH_BUTTON;
button_data->is_root = TRUE;
}
else if (nautilus_is_root_for_scheme (location, SCHEME_NETWORK_VIEW))
{
button_data->type = NETWORK_BUTTON;
button_data->is_root = TRUE;
}
else
{
button_data->type = NORMAL_BUTTON;
@ -1157,7 +1183,7 @@ make_button_data (NautilusPathBar *self,
case TRASH_BUTTON:
case RECENT_BUTTON:
case STARRED_BUTTON:
case OTHER_LOCATIONS_BUTTON:
case NETWORK_BUTTON:
{
button_data->label = gtk_label_new (NULL);
child = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);

View File

@ -1,406 +0,0 @@
/* nautilus-places-view.c
*
* Copyright (C) 2015 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <adwaita.h>
#include <glib/gi18n.h>
#include "nautilus-mime-actions.h"
#include "nautilus-places-view.h"
#include "gtk/nautilusgtkplacesviewprivate.h"
#include "nautilus-application.h"
#include "nautilus-file.h"
#include "nautilus-scheme.h"
#include "nautilus-toolbar-menu-sections.h"
#include "nautilus-view.h"
#include "nautilus-window-slot.h"
typedef struct
{
GFile *location;
NautilusQuery *search_query;
GtkWidget *places_view;
} NautilusPlacesViewPrivate;
struct _NautilusPlacesView
{
GtkFrameClass parent;
};
static void nautilus_places_view_iface_init (NautilusViewInterface *iface);
G_DEFINE_TYPE_WITH_CODE (NautilusPlacesView, nautilus_places_view, GTK_TYPE_BOX,
G_ADD_PRIVATE (NautilusPlacesView)
G_IMPLEMENT_INTERFACE (NAUTILUS_TYPE_VIEW, nautilus_places_view_iface_init));
enum
{
PROP_0,
PROP_LOCATION,
PROP_SEARCH_QUERY,
PROP_LOADING,
PROP_SEARCHING,
PROP_SELECTION,
PROP_EXTENSIONS_BACKGROUND_MENU,
PROP_TEMPLATES_MENU,
LAST_PROP
};
static void
open_location_cb (NautilusPlacesView *view,
GFile *location,
NautilusGtkPlacesOpenFlags open_flags)
{
NautilusOpenFlags flags;
GtkWidget *slot;
slot = gtk_widget_get_ancestor (GTK_WIDGET (view), NAUTILUS_TYPE_WINDOW_SLOT);
switch (open_flags)
{
case NAUTILUS_GTK_PLACES_OPEN_NEW_TAB:
{
flags = NAUTILUS_OPEN_FLAG_NEW_TAB |
NAUTILUS_OPEN_FLAG_DONT_MAKE_ACTIVE;
}
break;
case NAUTILUS_GTK_PLACES_OPEN_NEW_WINDOW:
{
flags = NAUTILUS_OPEN_FLAG_NEW_WINDOW;
}
break;
case NAUTILUS_GTK_PLACES_OPEN_NORMAL: /* fall-through */
default:
{
flags = 0;
}
break;
}
if (slot)
{
NautilusFile *file;
GtkRoot *window;
char *path;
path = SCHEME_OTHER_LOCATIONS ":///";
file = nautilus_file_get (location);
window = gtk_widget_get_root (GTK_WIDGET (view));
nautilus_mime_activate_file (GTK_WINDOW (window),
NAUTILUS_WINDOW_SLOT (slot),
file,
path,
flags);
nautilus_file_unref (file);
}
}
static void
loading_cb (NautilusView *view)
{
g_object_notify (G_OBJECT (view), "loading");
}
static void
show_error_message_cb (NautilusGtkPlacesView *view,
const gchar *primary,
const gchar *secondary)
{
GtkWidget *dialog;
GtkRoot *window;
window = gtk_widget_get_root (GTK_WIDGET (view));
dialog = adw_message_dialog_new (GTK_WINDOW (window), primary, secondary);
adw_message_dialog_add_response (ADW_MESSAGE_DIALOG (dialog),
"close", _("_Close"));
gtk_window_present (GTK_WINDOW (dialog));
}
static void
nautilus_places_view_finalize (GObject *object)
{
NautilusPlacesView *self = (NautilusPlacesView *) object;
NautilusPlacesViewPrivate *priv = nautilus_places_view_get_instance_private (self);
g_clear_object (&priv->location);
g_clear_object (&priv->search_query);
G_OBJECT_CLASS (nautilus_places_view_parent_class)->finalize (object);
}
static void
nautilus_places_view_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
NautilusView *view = NAUTILUS_VIEW (object);
switch (prop_id)
{
case PROP_LOCATION:
{
g_value_set_object (value, nautilus_view_get_location (view));
}
break;
case PROP_SEARCH_QUERY:
{
g_value_set_object (value, nautilus_view_get_search_query (view));
}
break;
/* Collect all unused properties and do nothing. Ideally, this wouldnt
* have to be done in the first place.
*/
case PROP_SEARCHING:
case PROP_SELECTION:
case PROP_EXTENSIONS_BACKGROUND_MENU:
case PROP_TEMPLATES_MENU:
{
}
break;
default:
{
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
}
static void
nautilus_places_view_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
NautilusView *view = NAUTILUS_VIEW (object);
switch (prop_id)
{
case PROP_LOCATION:
{
nautilus_view_set_location (view, g_value_get_object (value));
}
break;
case PROP_SEARCH_QUERY:
{
nautilus_view_set_search_query (view, g_value_get_object (value));
}
break;
default:
{
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
}
static GFile *
nautilus_places_view_get_location (NautilusView *view)
{
NautilusPlacesViewPrivate *priv;
priv = nautilus_places_view_get_instance_private (NAUTILUS_PLACES_VIEW (view));
return priv->location;
}
static void
nautilus_places_view_set_location (NautilusView *view,
GFile *location)
{
NautilusPlacesViewPrivate *priv = nautilus_places_view_get_instance_private (NAUTILUS_PLACES_VIEW (view));
if (location != NULL &&
!g_file_has_uri_scheme (location, SCHEME_OTHER_LOCATIONS))
{
/*
* If it's not trying to open the places view itself, simply
* delegates the location to application, which takes care of
* selecting the appropriate view.
*/
nautilus_application_open_location_full (NAUTILUS_APPLICATION (g_application_get_default ()),
location, 0, NULL, NULL, NULL);
return;
}
g_set_object (&priv->location, location);
}
static GList *
nautilus_places_view_get_selection (NautilusView *view)
{
/* STUB */
return NULL;
}
static void
nautilus_places_view_set_selection (NautilusView *view,
GList *selection)
{
/* STUB */
}
static NautilusQuery *
nautilus_places_view_get_search_query (NautilusView *view)
{
NautilusPlacesViewPrivate *priv;
priv = nautilus_places_view_get_instance_private (NAUTILUS_PLACES_VIEW (view));
return priv->search_query;
}
static void
nautilus_places_view_set_search_query (NautilusView *view,
NautilusQuery *query)
{
NautilusPlacesViewPrivate *priv;
gchar *text;
priv = nautilus_places_view_get_instance_private (NAUTILUS_PLACES_VIEW (view));
g_set_object (&priv->search_query, query);
text = query ? nautilus_query_get_text (query) : NULL;
nautilus_gtk_places_view_set_search_query (NAUTILUS_GTK_PLACES_VIEW (priv->places_view), text);
g_free (text);
}
static NautilusToolbarMenuSections *
nautilus_places_view_get_toolbar_menu_sections (NautilusView *view)
{
return NULL;
}
static gboolean
nautilus_places_view_is_loading (NautilusView *view)
{
NautilusPlacesViewPrivate *priv;
priv = nautilus_places_view_get_instance_private (NAUTILUS_PLACES_VIEW (view));
return nautilus_gtk_places_view_get_loading (NAUTILUS_GTK_PLACES_VIEW (priv->places_view));
}
static gboolean
nautilus_places_view_is_searching (NautilusView *view)
{
NautilusPlacesViewPrivate *priv;
priv = nautilus_places_view_get_instance_private (NAUTILUS_PLACES_VIEW (view));
return priv->search_query != NULL;
}
static guint
nautilus_places_view_get_view_id (NautilusView *view)
{
return NAUTILUS_VIEW_OTHER_LOCATIONS_ID;
}
static void
nautilus_places_view_iface_init (NautilusViewInterface *iface)
{
iface->get_location = nautilus_places_view_get_location;
iface->set_location = nautilus_places_view_set_location;
iface->get_selection = nautilus_places_view_get_selection;
iface->set_selection = nautilus_places_view_set_selection;
iface->get_search_query = nautilus_places_view_get_search_query;
iface->set_search_query = nautilus_places_view_set_search_query;
iface->get_toolbar_menu_sections = nautilus_places_view_get_toolbar_menu_sections;
iface->is_loading = nautilus_places_view_is_loading;
iface->is_searching = nautilus_places_view_is_searching;
iface->get_view_id = nautilus_places_view_get_view_id;
}
static void
nautilus_places_view_class_init (NautilusPlacesViewClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = nautilus_places_view_finalize;
object_class->get_property = nautilus_places_view_get_property;
object_class->set_property = nautilus_places_view_set_property;
g_object_class_override_property (object_class, PROP_LOADING, "loading");
g_object_class_override_property (object_class, PROP_SEARCHING, "searching");
g_object_class_override_property (object_class, PROP_LOCATION, "location");
g_object_class_override_property (object_class, PROP_SELECTION, "selection");
g_object_class_override_property (object_class, PROP_SEARCH_QUERY, "search-query");
g_object_class_override_property (object_class,
PROP_EXTENSIONS_BACKGROUND_MENU,
"extensions-background-menu");
g_object_class_override_property (object_class,
PROP_TEMPLATES_MENU,
"templates-menu");
}
static void
nautilus_places_view_init (NautilusPlacesView *self)
{
NautilusPlacesViewPrivate *priv;
priv = nautilus_places_view_get_instance_private (self);
/* Location */
priv->location = g_file_new_for_uri (SCHEME_OTHER_LOCATIONS ":///");
/* Places view */
priv->places_view = nautilus_gtk_places_view_new ();
nautilus_gtk_places_view_set_open_flags (NAUTILUS_GTK_PLACES_VIEW (priv->places_view),
NAUTILUS_OPEN_FLAG_NEW_TAB | NAUTILUS_OPEN_FLAG_NEW_WINDOW | NAUTILUS_OPEN_FLAG_NORMAL);
gtk_widget_set_hexpand (priv->places_view, TRUE);
gtk_widget_set_vexpand (priv->places_view, TRUE);
gtk_widget_set_visible (priv->places_view, TRUE);
gtk_box_append (GTK_BOX (self), priv->places_view);
g_signal_connect_object (priv->places_view, "notify::loading",
G_CALLBACK (loading_cb), self, G_CONNECT_SWAPPED);
g_signal_connect_object (priv->places_view, "open-location",
G_CALLBACK (open_location_cb), self, G_CONNECT_SWAPPED);
g_signal_connect_object (priv->places_view, "show-error-message",
G_CALLBACK (show_error_message_cb), self, G_CONNECT_SWAPPED);
}
NautilusPlacesView *
nautilus_places_view_new (void)
{
NautilusPlacesView *view;
view = g_object_new (NAUTILUS_TYPE_PLACES_VIEW, NULL);
if (g_object_is_floating (view))
{
g_object_ref_sink (view);
}
return view;
}

View File

@ -1,32 +0,0 @@
/* nautilus-places-view.h
*
* Copyright (C) 2015 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <glib-object.h>
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define NAUTILUS_TYPE_PLACES_VIEW (nautilus_places_view_get_type())
G_DECLARE_FINAL_TYPE (NautilusPlacesView, nautilus_places_view, NAUTILUS, PLACES_VIEW, GtkBox)
NautilusPlacesView* nautilus_places_view_new (void);
G_END_DECLS

View File

@ -31,6 +31,13 @@
#include <gio/gio.h>
#ifdef GDK_WINDOWING_WAYLAND
#include <gdk/wayland/gdkwayland.h>
#endif
#ifdef GDK_WINDOWING_X11
#include <gdk/x11/gdkx.h>
#endif
#define PREVIEWER2_DBUS_IFACE "org.gnome.NautilusPreviewer2"
static const char *previewer_dbus_name = "org.gnome.NautilusPreviewer" PROFILE;
@ -43,7 +50,12 @@ static guint subscription_id = 0;
static GCancellable *cancellable = NULL;
static GtkRoot *current_window = NULL; /* weak ref */
static gchar *exported_window_handle = NULL;
static void real_call_show_file (const gchar *uri,
const gchar *window_handle,
gboolean close_if_already_visible);
static void create_new_bus (void);
static void previewer_selection_event (GDBusConnection *connection,
const gchar *sender_name,
@ -53,6 +65,61 @@ static void previewer_selection_event (GDBusConnection *connection,
GVariant *parameters,
gpointer user_data);
#ifdef GDK_WINDOWING_WAYLAND
typedef struct
{
gchar *uri;
gboolean close_if_already_visible;
} PreviewExportData;
static void
preview_export_data_free (gpointer _data)
{
PreviewExportData *data = _data;
g_free (data->uri);
g_free (data);
}
G_DEFINE_AUTOPTR_CLEANUP_FUNC (PreviewExportData, preview_export_data_free)
static void
wayland_window_handle_exported (GdkToplevel *toplevel,
const char *wayland_handle_str,
gpointer user_data)
{
PreviewExportData *data = user_data;
g_autofree char *wayland_handle = g_strdup_printf ("wayland:%s", wayland_handle_str);
real_call_show_file (data->uri, wayland_handle, data->close_if_already_visible);
}
#endif
static void
clear_exported_window_handle (void)
{
if (exported_window_handle == NULL)
{
return;
}
#ifdef GDK_WINDOWING_WAYLAND
if (current_window != NULL &&
GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (GTK_WIDGET (current_window))))
{
GdkSurface *gdk_surface = gtk_native_get_surface (GTK_NATIVE (current_window));
if (GDK_IS_WAYLAND_TOPLEVEL (gdk_surface) &&
g_str_has_prefix (exported_window_handle, "wayland:"))
{
gdk_wayland_toplevel_drop_exported_handle (GDK_WAYLAND_TOPLEVEL (gdk_surface),
exported_window_handle + strlen ("wayland:"));
}
}
#endif
g_free (exported_window_handle);
exported_window_handle = NULL;
}
static void
on_ping_finished (GObject *object,
GAsyncResult *res,
@ -173,10 +240,65 @@ previewer2_method_ready_cb (GObject *source,
void
nautilus_previewer_call_show_file (const gchar *uri,
const gchar *window_handle,
guint xid,
GtkRoot *window,
gboolean close_if_already_visible)
{
/* Reuse existing handle if called again for the same window. */
if (current_window == window &&
exported_window_handle != NULL)
{
real_call_show_file (uri, exported_window_handle, close_if_already_visible);
return;
}
/* Otherwise, obtain a new window handle. */
clear_exported_window_handle ();
g_set_weak_pointer (&current_window, window);
GdkSurface *gdk_surface = gtk_native_get_surface (GTK_NATIVE (window));
#ifdef GDK_WINDOWING_X11
if (GDK_IS_X11_DISPLAY (gtk_widget_get_display (GTK_WIDGET (window))))
{
guint xid = (guint) gdk_x11_surface_get_xid (gdk_surface);
g_autofree char *window_handle = g_strdup_printf ("x11:%x", xid);
real_call_show_file (uri, window_handle, close_if_already_visible);
return;
}
#endif
#ifdef GDK_WINDOWING_WAYLAND
if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (GTK_WIDGET (window))))
{
g_autoptr (PreviewExportData) data = g_new0 (PreviewExportData, 1);
data->uri = g_strdup (uri);
data->close_if_already_visible = close_if_already_visible;
if (gdk_wayland_toplevel_export_handle (GDK_WAYLAND_TOPLEVEL (gdk_surface),
wayland_window_handle_exported,
data,
preview_export_data_free))
{
/* Don't let autoptr free data successfully taken by the call. */
(void) g_steal_pointer (&data);
return;
}
}
#endif
g_warning ("Couldn't export handle, unsupported windowing system");
/* Let's use a fallback, so at least a preview will be displayed */
real_call_show_file (uri, "x11:0", close_if_already_visible);
}
static void
real_call_show_file (const gchar *uri,
const gchar *window_handle,
gboolean close_if_already_visible)
{
g_set_str (&exported_window_handle, window_handle);
if (!ensure_previewer_proxy ())
{
return;
@ -271,6 +393,8 @@ nautilus_previewer_teardown (GDBusConnection *connection)
g_cancellable_cancel (cancellable);
g_clear_object (&cancellable);
g_clear_object (&previewer_proxy);
clear_exported_window_handle ();
g_clear_weak_pointer (&current_window);
}
gboolean

View File

@ -24,13 +24,13 @@
#include <gio/gio.h>
#include <glib.h>
#include <gtk/gtk.h>
G_BEGIN_DECLS
void nautilus_previewer_call_show_file (const gchar *uri,
const gchar *window_handle,
guint xid,
gboolean close_if_already_visible);
GtkRoot *window,
gboolean close_if_already_visible);
void nautilus_previewer_call_close (void);
gboolean nautilus_previewer_is_visible (void);

View File

@ -27,7 +27,6 @@
#include "nautilus-icon-info.h"
#include "nautilus-scheme.h"
#include "nautilus-ui-utilities.h"
#include "nautilus-window.h"
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <gio/gio.h>

View File

@ -372,7 +372,7 @@ on_canceled (GCancellable *cancellable,
NautilusProgressInfo *info)
{
G_LOCK (progress_info);
set_details (info, _("Canceled"));
set_details (info, _("Cancelled"));
info->cancel_at_idle = TRUE;
g_timer_stop (info->progress_timer);
queue_idle (info, TRUE);

View File

@ -137,6 +137,7 @@ struct _NautilusPropertiesWindow
GtkWidget *permissions_navigation_row;
GtkWidget *permissions_value_label;
GtkWidget *extension_models_group;
GtkWidget *extension_models_list_box;
/* Permissions page */
@ -172,7 +173,7 @@ struct _NautilusPropertiesWindow
OwnerChange *owner_change;
GList *permission_rows;
GList *change_permission_drop_downs;
GList *change_permission_combo_rows;
GHashTable *initial_permissions;
gboolean has_recursive_apply;
@ -544,7 +545,8 @@ get_image_for_properties_window (NautilusPropertiesWindow *self,
if (!icon)
{
g_autoptr (GIcon) gicon = g_themed_icon_new ("application-x-generic");
g_autoptr (GIcon) gicon = g_themed_icon_new_from_names ((char *[]){"application-x-generic",
"text-x-generic"}, 2);
icon = nautilus_icon_info_lookup (gicon, NAUTILUS_GRID_ICON_SIZE_MEDIUM, icon_scale);
}
@ -3039,7 +3041,7 @@ update_permission_row (AdwComboRow *row,
}
static void
setup_permissions_drop_down (GtkDropDown *drop_down,
setup_permissions_combo_row (AdwComboRow *combo_row,
PermissionType type,
FilterType filter_type)
{
@ -3047,13 +3049,13 @@ setup_permissions_drop_down (GtkDropDown *drop_down,
g_autoptr (GtkExpression) expression = NULL;
store = g_list_store_new (NAUTILUS_TYPE_PERMISSION_ENTRY);
gtk_drop_down_set_model (drop_down, G_LIST_MODEL (store));
adw_combo_row_set_model (combo_row, G_LIST_MODEL (store));
expression = gtk_property_expression_new (NAUTILUS_TYPE_PERMISSION_ENTRY, NULL, "name");
gtk_drop_down_set_expression (drop_down, expression);
adw_combo_row_set_expression (combo_row, expression);
g_object_set_data (G_OBJECT (drop_down), "filter-type", GINT_TO_POINTER (filter_type));
g_object_set_data (G_OBJECT (drop_down), "permission-type", GINT_TO_POINTER (type));
g_object_set_data (G_OBJECT (combo_row), "filter-type", GINT_TO_POINTER (filter_type));
g_object_set_data (G_OBJECT (combo_row), "permission-type", GINT_TO_POINTER (type));
if (filter_type == FOLDERS_ONLY)
{
@ -3246,7 +3248,7 @@ on_change_permissions_response_cancel (AdwWindow *dialog,
NautilusPropertiesWindow *self =
NAUTILUS_PROPERTIES_WINDOW (gtk_window_get_transient_for (GTK_WINDOW (dialog)));
g_clear_pointer (&self->change_permission_drop_downs, g_list_free);
g_clear_pointer (&self->change_permission_combo_rows, g_list_free);
gtk_window_destroy (GTK_WINDOW (dialog));
}
@ -3266,18 +3268,18 @@ on_change_permissions_response_change (AdwWindow *dialog,
int mask;
/* Simple mode, minus exec checkbox */
for (l = self->change_permission_drop_downs; l != NULL; l = l->next)
for (l = self->change_permission_combo_rows; l != NULL; l = l->next)
{
GtkDropDown *drop_down = l->data;
NautilusPermissionEntry *selected = gtk_drop_down_get_selected_item (drop_down);
AdwComboRow *combo_row = l->data;
NautilusPermissionEntry *selected = adw_combo_row_get_selected_item (combo_row);
if (selected == NULL)
{
continue;
}
type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (drop_down), "permission-type"));
filter_type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (drop_down), "filter-type"));
type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo_row), "permission-type"));
filter_type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo_row), "filter-type"));
vfs_new_perm = permission_to_vfs (type, selected->permission_value);
@ -3323,16 +3325,16 @@ on_change_permissions_response_change (AdwWindow *dialog,
self);
}
}
g_clear_pointer (&self->change_permission_drop_downs, g_list_free);
g_clear_pointer (&self->change_permission_combo_rows, g_list_free);
gtk_window_destroy (GTK_WINDOW (dialog));
}
static void
set_active_from_umask (GtkDropDown *drop_down,
set_active_from_umask (AdwComboRow *combo_row,
PermissionType type,
FilterType filter_type)
{
GListModel *model = gtk_drop_down_get_model (drop_down);
GListModel *model = adw_combo_row_get_model (combo_row);
mode_t initial;
mode_t mask;
mode_t p;
@ -3430,7 +3432,7 @@ set_active_from_umask (GtkDropDown *drop_down,
if (entry->permission_value == perm)
{
gtk_drop_down_set_selected (drop_down, i);
adw_combo_row_set_selected (combo_row, i);
break;
}
}
@ -3450,7 +3452,7 @@ static void
on_change_permissions_clicked (NautilusPropertiesWindow *self)
{
GtkWidget *dialog;
GtkDropDown *drop_down;
AdwComboRow *combo_row;
GtkButton *cancel_button, *change_button;
GtkShortcut *esc_shortcut;
GtkShortcutAction *cb_action;
@ -3462,43 +3464,43 @@ on_change_permissions_clicked (NautilusPropertiesWindow *self)
gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (self));
/* Owner Permissions */
drop_down = GTK_DROP_DOWN (gtk_builder_get_object (change_permissions_builder, "file_owner_drop_down"));
setup_permissions_drop_down (drop_down, PERMISSION_USER, FILES_ONLY);
self->change_permission_drop_downs = g_list_prepend (self->change_permission_drop_downs,
drop_down);
set_active_from_umask (drop_down, PERMISSION_USER, FILES_ONLY);
combo_row = ADW_COMBO_ROW (gtk_builder_get_object (change_permissions_builder, "file_owner_combo_row"));
setup_permissions_combo_row (combo_row, PERMISSION_USER, FILES_ONLY);
self->change_permission_combo_rows = g_list_prepend (self->change_permission_combo_rows,
combo_row);
set_active_from_umask (combo_row, PERMISSION_USER, FILES_ONLY);
drop_down = GTK_DROP_DOWN (gtk_builder_get_object (change_permissions_builder, "folder_owner_drop_down"));
setup_permissions_drop_down (drop_down, PERMISSION_USER, FOLDERS_ONLY);
self->change_permission_drop_downs = g_list_prepend (self->change_permission_drop_downs,
drop_down);
set_active_from_umask (drop_down, PERMISSION_USER, FOLDERS_ONLY);
combo_row = ADW_COMBO_ROW (gtk_builder_get_object (change_permissions_builder, "folder_owner_combo_row"));
setup_permissions_combo_row (combo_row, PERMISSION_USER, FOLDERS_ONLY);
self->change_permission_combo_rows = g_list_prepend (self->change_permission_combo_rows,
combo_row);
set_active_from_umask (combo_row, PERMISSION_USER, FOLDERS_ONLY);
/* Group Permissions */
drop_down = GTK_DROP_DOWN (gtk_builder_get_object (change_permissions_builder, "file_group_drop_down"));
setup_permissions_drop_down (drop_down, PERMISSION_GROUP, FILES_ONLY);
self->change_permission_drop_downs = g_list_prepend (self->change_permission_drop_downs,
drop_down);
set_active_from_umask (drop_down, PERMISSION_GROUP, FILES_ONLY);
combo_row = ADW_COMBO_ROW (gtk_builder_get_object (change_permissions_builder, "file_group_combo_row"));
setup_permissions_combo_row (combo_row, PERMISSION_GROUP, FILES_ONLY);
self->change_permission_combo_rows = g_list_prepend (self->change_permission_combo_rows,
combo_row);
set_active_from_umask (combo_row, PERMISSION_GROUP, FILES_ONLY);
drop_down = GTK_DROP_DOWN (gtk_builder_get_object (change_permissions_builder, "folder_group_drop_down"));
setup_permissions_drop_down (drop_down, PERMISSION_GROUP, FOLDERS_ONLY);
self->change_permission_drop_downs = g_list_prepend (self->change_permission_drop_downs,
drop_down);
set_active_from_umask (drop_down, PERMISSION_GROUP, FOLDERS_ONLY);
combo_row = ADW_COMBO_ROW (gtk_builder_get_object (change_permissions_builder, "folder_group_combo_row"));
setup_permissions_combo_row (combo_row, PERMISSION_GROUP, FOLDERS_ONLY);
self->change_permission_combo_rows = g_list_prepend (self->change_permission_combo_rows,
combo_row);
set_active_from_umask (combo_row, PERMISSION_GROUP, FOLDERS_ONLY);
/* Others Permissions */
drop_down = GTK_DROP_DOWN (gtk_builder_get_object (change_permissions_builder, "file_other_drop_down"));
setup_permissions_drop_down (drop_down, PERMISSION_OTHER, FILES_ONLY);
self->change_permission_drop_downs = g_list_prepend (self->change_permission_drop_downs,
drop_down);
set_active_from_umask (drop_down, PERMISSION_OTHER, FILES_ONLY);
combo_row = ADW_COMBO_ROW (gtk_builder_get_object (change_permissions_builder, "file_other_combo_row"));
setup_permissions_combo_row (combo_row, PERMISSION_OTHER, FILES_ONLY);
self->change_permission_combo_rows = g_list_prepend (self->change_permission_combo_rows,
combo_row);
set_active_from_umask (combo_row, PERMISSION_OTHER, FILES_ONLY);
drop_down = GTK_DROP_DOWN (gtk_builder_get_object (change_permissions_builder, "folder_other_drop_down"));
setup_permissions_drop_down (drop_down, PERMISSION_OTHER, FOLDERS_ONLY);
self->change_permission_drop_downs = g_list_prepend (self->change_permission_drop_downs,
drop_down);
set_active_from_umask (drop_down, PERMISSION_OTHER, FOLDERS_ONLY);
combo_row = ADW_COMBO_ROW (gtk_builder_get_object (change_permissions_builder, "folder_other_combo_row"));
setup_permissions_combo_row (combo_row, PERMISSION_OTHER, FOLDERS_ONLY);
self->change_permission_combo_rows = g_list_prepend (self->change_permission_combo_rows,
combo_row);
set_active_from_umask (combo_row, PERMISSION_OTHER, FOLDERS_ONLY);
cancel_button = GTK_BUTTON (gtk_builder_get_object (change_permissions_builder, "cancel_button"));
change_button = GTK_BUTTON (gtk_builder_get_object (change_permissions_builder, "change_button"));
@ -3587,7 +3589,7 @@ refresh_extension_model_pages (NautilusPropertiesWindow *self)
g_list_store_append (extensions_list, NAUTILUS_PROPERTIES_MODEL (l->data));
}
gtk_widget_set_visible (self->extension_models_list_box,
gtk_widget_set_visible (self->extension_models_group,
g_list_model_get_n_items (G_LIST_MODEL (extensions_list)) > 0);
gtk_list_box_bind_model (GTK_LIST_BOX (self->extension_models_list_box),
@ -3995,7 +3997,7 @@ real_dispose (GObject *object)
g_clear_list (&self->permission_rows, NULL);
g_clear_list (&self->change_permission_drop_downs, NULL);
g_clear_list (&self->change_permission_combo_rows, NULL);
g_clear_pointer (&self->initial_permissions, g_hash_table_destroy);
@ -4163,6 +4165,7 @@ nautilus_properties_window_class_init (NautilusPropertiesWindowClass *klass)
gtk_widget_class_bind_template_child (widget_class, NautilusPropertiesWindow, accessed_row);
gtk_widget_class_bind_template_child (widget_class, NautilusPropertiesWindow, permissions_navigation_row);
gtk_widget_class_bind_template_child (widget_class, NautilusPropertiesWindow, permissions_value_label);
gtk_widget_class_bind_template_child (widget_class, NautilusPropertiesWindow, extension_models_group);
gtk_widget_class_bind_template_child (widget_class, NautilusPropertiesWindow, extension_models_list_box);
gtk_widget_class_bind_template_child (widget_class, NautilusPropertiesWindow, free_space_value_label);
gtk_widget_class_bind_template_child (widget_class, NautilusPropertiesWindow, permissions_stack);

View File

@ -91,8 +91,7 @@ update_fts_sensitivity (NautilusQueryEditor *editor)
{
g_autoptr (NautilusFile) file = nautilus_file_get (editor->location);
fts_sensitive = !nautilus_file_is_other_locations (file) &&
!g_file_has_uri_scheme (editor->location, SCHEME_NETWORK) &&
fts_sensitive = !g_file_has_uri_scheme (editor->location, SCHEME_NETWORK) &&
!(nautilus_file_is_remote (file) &&
location_settings_search_get_recursive_for_location (editor->location) == NAUTILUS_QUERY_RECURSIVE_NEVER);
nautilus_search_popover_set_fts_sensitive (NAUTILUS_SEARCH_POPOVER (editor->popover),

View File

@ -0,0 +1,449 @@
/* nautilusgtkplacesview.c
*
* Copyright (C) 2015 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "config.h"
#include <glib/gi18n.h>
#include <gio/gio.h>
#include "nautilus-recent-servers.h"
struct _NautilusRecentServers
{
GObject parent_instance;
GHashTable *server_infos;
GFileMonitor *server_list_monitor;
guint idle_reload_id;
guint loading : 1;
};
static void nautilus_recent_servers_set_loading (NautilusRecentServers *self,
gboolean loading);
G_DEFINE_TYPE (NautilusRecentServers, nautilus_recent_servers, G_TYPE_OBJECT)
enum
{
PROP_0,
PROP_LOADING,
LAST_PROP
};
enum
{
ADDED,
CHANGED,
REMOVED,
LAST_SIGNAL
};
static GParamSpec *properties[LAST_PROP];
static guint signals[LAST_SIGNAL];
static void
ensure_monitor (NautilusRecentServers *self)
{
if (self->server_list_monitor != NULL)
{
return;
}
g_autofree char *filename = g_build_filename (g_get_user_config_dir (), "gtk-4.0", "servers", NULL);
g_autoptr (GFile) server_list_file = g_file_new_for_path (filename);
g_autoptr (GError) error = NULL;
self->server_list_monitor = g_file_monitor_file (server_list_file,
G_FILE_MONITOR_NONE,
NULL,
&error);
if (error != NULL)
{
g_warning ("Cannot monitor server file: %s", error->message);
}
else
{
g_signal_connect_object (self->server_list_monitor, "changed",
G_CALLBACK (nautilus_recent_servers_force_reload), self,
G_CONNECT_SWAPPED);
}
}
static GBookmarkFile *
server_list_load (void)
{
GBookmarkFile *bookmarks;
GError *error = NULL;
char *datadir;
char *filename;
bookmarks = g_bookmark_file_new ();
datadir = g_build_filename (g_get_user_config_dir (), "gtk-4.0", NULL);
filename = g_build_filename (datadir, "servers", NULL);
g_mkdir_with_parents (datadir, 0700);
g_bookmark_file_load_from_file (bookmarks, filename, &error);
if (error)
{
if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
{
/* only warn if the file exists */
g_warning ("Unable to open server bookmarks: %s", error->message);
g_clear_pointer (&bookmarks, g_bookmark_file_free);
}
g_clear_error (&error);
}
g_free (datadir);
g_free (filename);
return bookmarks;
}
static void
server_list_save (GBookmarkFile *bookmarks)
{
char *filename;
filename = g_build_filename (g_get_user_config_dir (), "gtk-4.0", "servers", NULL);
g_bookmark_file_to_file (bookmarks, filename, NULL);
g_free (filename);
}
void
nautilus_add_recent_server (GFile *file)
{
GBookmarkFile *bookmarks;
GFileInfo *info;
GError *error;
char *title;
char *uri;
GDateTime *now;
error = NULL;
bookmarks = server_list_load ();
if (!bookmarks)
{
return;
}
uri = g_file_get_uri (file);
info = g_file_query_info (file,
G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
G_FILE_QUERY_INFO_NONE,
NULL,
&error);
title = g_file_info_get_attribute_as_string (info, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME);
g_bookmark_file_set_title (bookmarks, uri, title);
now = g_date_time_new_now_utc ();
g_bookmark_file_set_visited_date_time (bookmarks, uri, now);
g_date_time_unref (now);
g_bookmark_file_add_application (bookmarks, uri, NULL, NULL);
server_list_save (bookmarks);
g_bookmark_file_free (bookmarks);
g_clear_object (&info);
g_free (title);
g_free (uri);
}
void
nautilus_remove_recent_server (const char *uri)
{
GBookmarkFile *bookmarks;
bookmarks = server_list_load ();
if (!bookmarks)
{
return;
}
g_bookmark_file_remove_item (bookmarks, uri, NULL);
server_list_save (bookmarks);
g_bookmark_file_free (bookmarks);
}
static void
nautilus_recent_servers_finalize (GObject *object)
{
NautilusRecentServers *self = (NautilusRecentServers *) object;
g_clear_object (&self->server_list_monitor);
g_clear_pointer (&self->server_infos, g_hash_table_destroy);
G_OBJECT_CLASS (nautilus_recent_servers_parent_class)->finalize (object);
}
static void
nautilus_recent_servers_dispose (GObject *object)
{
NautilusRecentServers *self = (NautilusRecentServers *) object;
g_clear_handle_id (&self->idle_reload_id, g_source_remove);
G_OBJECT_CLASS (nautilus_recent_servers_parent_class)->dispose (object);
}
static void
nautilus_recent_servers_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
NautilusRecentServers *self = NAUTILUS_RECENT_SERVERS (object);
switch (prop_id)
{
case PROP_LOADING:
{
g_value_set_boolean (value, nautilus_recent_servers_get_loading (self));
break;
}
default:
{
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
}
static GFileInfo *
server_file_info_new (const char *uri)
{
GFileInfo *info = g_file_info_new ();
g_autofree char *random_name = g_dbus_generate_guid ();
g_autoptr (GIcon) icon = g_themed_icon_new ("folder-remote");
g_autoptr (GIcon) symbolic_icon = g_themed_icon_new ("folder-remote-symbolic");
g_file_info_set_name (info, random_name);
g_file_info_set_icon (info, icon);
g_file_info_set_symbolic_icon (info, symbolic_icon);
g_file_info_set_content_type (info, "inode/directory");
g_file_info_set_file_type (info, G_FILE_TYPE_SHORTCUT);
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_STANDARD_IS_VIRTUAL, TRUE);
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, FALSE);
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME, FALSE);
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, FALSE);
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, FALSE);
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI, uri);
return info;
}
static int
_date_time_equal_steal_1st (GDateTime *date_time1__to_be_stolen,
GDateTime *date_time2)
{
g_autoptr (GDateTime) date_time1 = date_time1__to_be_stolen;
return ((date_time1 == NULL && date_time2 == NULL) ||
g_date_time_equal (date_time1, date_time2));
}
static void
populate_servers_on_idle (gpointer user_data)
{
NautilusRecentServers *self = NAUTILUS_RECENT_SERVERS (user_data);
GBookmarkFile *server_list;
char **uris;
gsize num_uris;
self->idle_reload_id = 0;
server_list = server_list_load ();
if (!server_list)
{
return;
}
/* Monitor the file in case it's modified outside this code */
ensure_monitor (self);
uris = g_bookmark_file_get_uris (server_list, &num_uris);
if (!uris)
{
g_bookmark_file_free (server_list);
nautilus_recent_servers_set_loading (self, FALSE);
return;
}
g_autoptr (GList) old_infos = g_hash_table_get_values (self->server_infos);
g_autoptr (GList) new_infos = NULL;
g_autoptr (GList) changed_infos = NULL;
for (gsize i = 0; i < num_uris; i++)
{
const gchar *uri = uris[i];
GFileInfo *info = g_hash_table_lookup (self->server_infos, uri);
gboolean new = FALSE;
if (info != NULL)
{
old_infos = g_list_remove (old_infos, info);
}
else
{
new = TRUE;
info = server_file_info_new (uri);
g_hash_table_insert (self->server_infos, g_strdup (uri), info);
new_infos = g_list_prepend (new_infos, info);
}
g_autofree char *name = g_bookmark_file_get_title (server_list, uri, NULL);
GDateTime *added = g_bookmark_file_get_added_date_time (server_list, uri, NULL);
GDateTime *visited = g_bookmark_file_get_visited_date_time (server_list, uri, NULL);
GDateTime *modified = g_bookmark_file_get_modified_date_time (server_list, uri, NULL);
if (new ||
g_strcmp0 (g_file_info_get_display_name (info), name) != 0 ||
!_date_time_equal_steal_1st (g_file_info_get_creation_date_time (info), added) ||
!_date_time_equal_steal_1st (g_file_info_get_access_date_time (info), visited) ||
!_date_time_equal_steal_1st (g_file_info_get_modification_date_time (info), modified))
{
g_file_info_set_display_name (info, name);
g_file_info_set_creation_date_time (info, added);
g_file_info_set_access_date_time (info, visited);
g_file_info_set_modification_date_time (info, modified);
if (!new)
{
changed_infos = g_list_prepend (changed_infos, info);
}
}
}
if (old_infos != NULL)
{
g_signal_emit (self, signals[REMOVED], 0, old_infos);
}
if (changed_infos != NULL)
{
g_signal_emit (self, signals[CHANGED], 0, changed_infos);
}
if (new_infos != NULL)
{
g_signal_emit (self, signals[ADDED], 0, new_infos);
}
for (GList *l = old_infos; l != NULL; l = l->next)
{
const char *old_uri = g_file_info_get_attribute_string (l->data, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI);
g_hash_table_remove (self->server_infos, old_uri);
}
nautilus_recent_servers_set_loading (self, FALSE);
g_strfreev (uris);
g_bookmark_file_free (server_list);
}
static void
nautilus_recent_servers_class_init (NautilusRecentServersClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = nautilus_recent_servers_finalize;
object_class->dispose = nautilus_recent_servers_dispose;
object_class->get_property = nautilus_recent_servers_get_property;
properties[PROP_LOADING] =
g_param_spec_boolean ("loading",
"Loading",
"Whether the view is loading locations",
FALSE,
G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
g_object_class_install_properties (object_class, LAST_PROP, properties);
signals[ADDED] = g_signal_new ("added",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST, 0, NULL, NULL,
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE, 1, G_TYPE_POINTER);
signals[CHANGED] = g_signal_new ("changed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST, 0, NULL, NULL,
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE, 1, G_TYPE_POINTER);
signals[REMOVED] = g_signal_new ("removed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST, 0, NULL, NULL,
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE, 1, G_TYPE_POINTER);
}
static void
nautilus_recent_servers_init (NautilusRecentServers *self)
{
self->server_infos = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
}
NautilusRecentServers *
nautilus_recent_servers_new (void)
{
return g_object_new (NAUTILUS_TYPE_RECENT_SERVERS, NULL);
}
void
nautilus_recent_servers_force_reload (NautilusRecentServers *self)
{
if (self->idle_reload_id == 0)
{
self->idle_reload_id = g_idle_add_once (populate_servers_on_idle, self);
nautilus_recent_servers_set_loading (self, TRUE);
}
}
/* Returns: (transfer full): List of server infos. */
GList *
nautilus_recent_servers_get_infos (NautilusRecentServers *self)
{
g_return_val_if_fail (NAUTILUS_IS_RECENT_SERVERS (self), FALSE);
GList *server_infos = g_hash_table_get_values (self->server_infos);
g_list_foreach (server_infos, (GFunc) g_object_ref, NULL);
return server_infos;
}
gboolean
nautilus_recent_servers_get_loading (NautilusRecentServers *self)
{
g_return_val_if_fail (NAUTILUS_IS_RECENT_SERVERS (self), FALSE);
return self->loading;
}
static void
nautilus_recent_servers_set_loading (NautilusRecentServers *self,
gboolean loading)
{
g_return_if_fail (NAUTILUS_IS_RECENT_SERVERS (self));
if (self->loading != loading)
{
self->loading = loading;
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_LOADING]);
}
}

View File

@ -0,0 +1,27 @@
/*
* Copyright (C) 2024 António Fernandes <antoniof@gnome.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include <gio/gio.h>
G_BEGIN_DECLS
#define NAUTILUS_TYPE_RECENT_SERVERS (nautilus_recent_servers_get_type ())
G_DECLARE_FINAL_TYPE (NautilusRecentServers, nautilus_recent_servers, NAUTILUS, RECENT_SERVERS, GObject);
NautilusRecentServers* nautilus_recent_servers_new (void);
void nautilus_recent_servers_force_reload (NautilusRecentServers *self);
GList * nautilus_recent_servers_get_infos (NautilusRecentServers *self);
gboolean nautilus_recent_servers_get_loading (NautilusRecentServers *self);
void nautilus_add_recent_server (GFile *file);
void nautilus_remove_recent_server (const char *uri);
G_END_DECLS

View File

@ -12,8 +12,8 @@ gboolean
nautilus_scheme_is_internal (const char *scheme)
{
return g_str_equal (scheme, SCHEME_BURN) ||
g_str_equal (scheme, SCHEME_OTHER_LOCATIONS) ||
g_str_equal (scheme, SCHEME_NETWORK) ||
g_str_equal (scheme, SCHEME_NETWORK_VIEW) ||
g_str_equal (scheme, SCHEME_RECENT) ||
g_str_equal (scheme, SCHEME_SEARCH) ||
g_str_equal (scheme, SCHEME_STARRED) ||

View File

@ -10,9 +10,10 @@
#define SCHEME_ADMIN "admin"
#define SCHEME_BURN "burn"
#define SCHEME_COMPUTER "computer"
#define SCHEME_SEARCH "x-nautilus-search"
#define SCHEME_OTHER_LOCATIONS "other-locations"
#define SCHEME_NETWORK "network"
#define SCHEME_NETWORK_VIEW "x-network-view"
#define SCHEME_RECENT "recent"
#define SCHEME_STARRED "starred"
#define SCHEME_TRASH "trash"

View File

@ -171,12 +171,6 @@ search_directory_file_get_deep_counts (NautilusFile *file,
return NAUTILUS_REQUEST_DONE;
}
static char *
search_directory_file_get_where_string (NautilusFile *file)
{
return g_strdup (_("Search"));
}
static void
search_directory_file_set_metadata (NautilusFile *file,
const char *key,
@ -303,7 +297,6 @@ nautilus_search_directory_file_class_init (NautilusSearchDirectoryFileClass *kla
file_class->check_if_ready = search_directory_file_check_if_ready;
file_class->get_item_count = search_directory_file_get_item_count;
file_class->get_deep_counts = search_directory_file_get_deep_counts;
file_class->get_where_string = search_directory_file_get_where_string;
file_class->set_metadata = search_directory_file_set_metadata;
file_class->set_metadata_as_list = search_directory_file_set_metadata_as_list;
}

View File

@ -691,6 +691,24 @@ search_engine_finished (NautilusSearchEngine *engine,
}
}
static NautilusFile *
search_new_file_from_filename (NautilusDirectory *directory,
const char *filename,
gboolean self_owned)
{
if (!self_owned)
{
/* This doesn't normally happen, unless the user somehow types in a uri
* that references a file like this.
* See https://bugzilla.gnome.org/show_bug.cgi?id=349840 */
return NAUTILUS_DIRECTORY_CLASS (nautilus_search_directory_parent_class)->new_file_from_filename (directory, filename, self_owned);
}
return NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_SEARCH_DIRECTORY_FILE,
"directory", directory,
NULL));
}
static void
search_force_reload (NautilusDirectory *directory)
{
@ -929,6 +947,8 @@ nautilus_search_directory_class_init (NautilusSearchDirectoryClass *class)
oclass->get_property = search_get_property;
oclass->set_property = search_set_property;
directory_class->new_file_from_filename = search_new_file_from_filename;
directory_class->are_all_files_seen = search_are_all_files_seen;
directory_class->contains_file = search_contains_file;
directory_class->force_reload = search_force_reload;

View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 2024 GNOME Foundation Inc.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "nautilus-shortcut-manager.h"
/**
* NautilusShortcutManager:
*
* A bin container to limit the scope of GTK_SHORTCUT_SCOPE_MANAGED shortcuts.
*
* The primary use case is to prevent keyboard shortcuts from being triggered
* while `AdwDialog`s are presented. This assumes an implementation detail: that
* `AdwDialog`s are internally children of `AdwWindow`/`AdwApplicationWindow`,
* but not children of `AdwWindow:child`/`AdwApplicationWindow:child`.
*
* This is simply an AdwBin augmented with the GtkShortcutManager interface. The
* default implementation of the interface is sufficient for the purpose.
*/
struct _NautilusShortcutManager
{
AdwBin parent_instance;
};
static void
nautilus_shortcut_manager_interface_init (GtkShortcutManagerInterface *iface)
{
}
G_DEFINE_TYPE_WITH_CODE (NautilusShortcutManager, nautilus_shortcut_manager, ADW_TYPE_BIN,
G_IMPLEMENT_INTERFACE (GTK_TYPE_SHORTCUT_MANAGER,
nautilus_shortcut_manager_interface_init))
static void
nautilus_shortcut_manager_class_init (NautilusShortcutManagerClass *klass)
{
}
static void
nautilus_shortcut_manager_init (NautilusShortcutManager *self)
{
}
NautilusShortcutManager *
nautilus_shortcut_manager_new (void)
{
return g_object_new (NAUTILUS_TYPE_SHORTCUT_MANAGER, NULL);
}

View File

@ -0,0 +1,20 @@
/*
* Copyright (C) 2024 GNOME Foundation Inc.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include <gtk/gtk.h>
#include <adwaita.h>
G_BEGIN_DECLS
#define NAUTILUS_TYPE_SHORTCUT_MANAGER (nautilus_shortcut_manager_get_type())
G_DECLARE_FINAL_TYPE (NautilusShortcutManager, nautilus_shortcut_manager, NAUTILUS, SHORTCUT_MANAGER, AdwBin)
NautilusShortcutManager * nautilus_shortcut_manager_new (void);
G_END_DECLS

View File

@ -17,9 +17,12 @@
*/
#include "nautilus-starred-directory.h"
#include "nautilus-tag-manager.h"
#include "nautilus-file-utilities.h"
#include "nautilus-directory-private.h"
#include "nautilus-file-private.h"
#include "nautilus-file-utilities.h"
#include "nautilus-internal-place-file.h"
#include "nautilus-tag-manager.h"
#include "nautilus-scheme.h"
#include <glib/gi18n.h>
@ -176,6 +179,22 @@ on_starred_files_changed (NautilusTagManager *tag_manager,
nautilus_starred_directory_update_files (self, changed_files);
}
static NautilusFile *
real_new_file_from_filename (NautilusDirectory *directory,
const char *filename,
gboolean self_owned)
{
if (!self_owned)
{
g_warning ("Creating a file within starred://. This shouldn't happen.");
return NAUTILUS_DIRECTORY_CLASS (nautilus_starred_directory_parent_class)->new_file_from_filename (directory, filename, self_owned);
}
return NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_INTERNAL_PLACE_FILE,
"directory", directory,
NULL));
}
static gboolean
real_contains_file (NautilusDirectory *directory,
NautilusFile *file)
@ -499,6 +518,7 @@ nautilus_starred_directory_class_init (NautilusFavoriteDirectoryClass *klass)
oclass->finalize = nautilus_starred_directory_finalize;
oclass->dispose = nautilus_starred_directory_dispose;
directory_class->new_file_from_filename = real_new_file_from_filename;
directory_class->handles_location = real_handles_location;
directory_class->contains_file = real_contains_file;
directory_class->is_editable = real_is_editable;

View File

@ -719,6 +719,17 @@ nautilus_tag_manager_can_star_contents (NautilusTagManager *self,
return g_file_has_prefix (directory, self->home) || g_file_equal (directory, self->home);
}
gboolean
nautilus_tag_manager_can_star_location (NautilusTagManager *self,
GFile *directory)
{
/* We only allow files to be starred inside the home directory for now.
* This avoids the starred files database growing too big.
* See https://gitlab.gnome.org/GNOME/nautilus/-/merge_requests/553#note_903108
*/
return g_file_has_prefix (directory, self->home);
}
static void
update_moved_uris_callback (GObject *object,
GAsyncResult *result,
@ -944,7 +955,7 @@ child_watch_cb (GPid pid,
static void
export_tracker2_data (NautilusTagManager *self)
{
gchar *argv[] = {"tracker3", "export", "--2to3", "files-starred", "--keyfile", NULL};
gchar *argv[] = {"tinysparql3", "export", "--2to3", "files-starred", "--keyfile", NULL};
gint stdout_fd;
GPid child_pid;
g_autoptr (GError) error = NULL;
@ -968,7 +979,7 @@ export_tracker2_data (NautilusTagManager *self)
&error);
if (!success)
{
g_warning ("Tracker 2 migration: Couldn't run `tracker3`: %s", error->message);
g_warning ("Tracker 2 migration: Couldn't run `tinysparql3`: %s", error->message);
return;
}

View File

@ -52,6 +52,9 @@ gboolean nautilus_tag_manager_file_is_starred (NautilusTagManager *
gboolean nautilus_tag_manager_can_star_contents (NautilusTagManager *self,
GFile *directory);
gboolean nautilus_tag_manager_can_star_location (NautilusTagManager *self,
GFile *directory);
void nautilus_tag_manager_update_moved_uris (NautilusTagManager *tag_manager,
GFile *src,
GFile *dest);

View File

@ -33,18 +33,14 @@
#include "nautilus-pathbar.h"
#include "nautilus-view-controls.h"
#include "nautilus-ui-utilities.h"
#include "nautilus-window.h"
struct _NautilusToolbar
{
AdwBin parent_instance;
NautilusWindow *window;
GtkWidget *history_controls_stack;
GtkWidget *history_controls;
GtkWidget *history_controls_placeholder;
GtkWidget *path_bar_container;
GtkWidget *location_entry_container;
GtkWidget *search_container;
GtkWidget *toolbar_switcher;
@ -55,6 +51,7 @@ struct _NautilusToolbar
GtkWidget *search_button_placeholder;
gboolean show_location_entry;
GtkWidget *focus_before_location_entry;
GtkWidget *sidebar_button;
gboolean show_sidebar_button;
@ -62,8 +59,6 @@ struct _NautilusToolbar
gboolean show_toolbar_children;
GtkWidget *location_entry_close_button;
/* active slot & bindings */
NautilusWindowSlot *window_slot;
};
@ -71,7 +66,6 @@ struct _NautilusToolbar
enum
{
PROP_0,
PROP_SHOW_LOCATION_ENTRY,
PROP_WINDOW_SLOT,
PROP_SHOW_SIDEBAR_BUTTON,
PROP_SIDEBAR_BUTTON_ACTIVE,
@ -117,11 +111,70 @@ toolbar_update_appearance (NautilusToolbar *self)
search_global ? self->history_controls_placeholder : self->history_controls);
}
static void
on_location_entry_close (GtkWidget *close_button,
NautilusToolbar *self)
void
nautilus_toolbar_open_location_entry (NautilusToolbar *self,
const char *special_text)
{
nautilus_toolbar_set_show_location_entry (self, FALSE);
if (self->show_location_entry)
{
return;
}
/* Remember focus widget. */
GtkRoot *root = gtk_widget_get_root (GTK_WIDGET (self));
GtkWidget *focus_widget = (root != NULL) ? gtk_root_get_focus (root) : NULL;
g_set_weak_pointer (&self->focus_before_location_entry, focus_widget);
self->show_location_entry = TRUE;
toolbar_update_appearance (self);
gtk_widget_grab_focus (self->location_entry);
if (special_text != NULL)
{
nautilus_location_entry_set_special_text (NAUTILUS_LOCATION_ENTRY (self->location_entry),
special_text);
gtk_editable_set_position (GTK_EDITABLE (self->location_entry), -1);
}
}
static void
nautilus_toolbar_close_location_entry (NautilusToolbar *self)
{
if (!self->show_location_entry)
{
return;
}
self->show_location_entry = FALSE;
toolbar_update_appearance (self);
if (self->focus_before_location_entry != NULL)
{
/* Restore focus widget. */
gtk_widget_grab_focus (self->focus_before_location_entry);
g_clear_weak_pointer (&self->focus_before_location_entry);
}
}
static void
on_path_bar_open_location (NautilusPathBar *path_bar,
GFile *location,
NautilusOpenFlags open_flags,
gpointer user_data)
{
NautilusToolbar *self = NAUTILUS_TOOLBAR (user_data);
if (open_flags & (NAUTILUS_OPEN_FLAG_NEW_WINDOW | NAUTILUS_OPEN_FLAG_NEW_TAB))
{
nautilus_application_open_location_full (NAUTILUS_APPLICATION (g_application_get_default ()),
location, open_flags, NULL, NULL, NULL);
}
else
{
nautilus_window_slot_open_location_full (self->window_slot, location, open_flags, NULL);
}
}
static void
@ -149,39 +202,18 @@ on_location_entry_focus_leave (GtkEventControllerFocus *controller,
return;
}
nautilus_toolbar_set_show_location_entry (toolbar, FALSE);
nautilus_toolbar_close_location_entry (toolbar);
}
static void
nautilus_toolbar_constructed (GObject *object)
on_location_entry_location_changed (NautilusLocationEntry *entry,
GFile *location,
gpointer user_data)
{
NautilusToolbar *self = NAUTILUS_TOOLBAR (object);
GtkEventController *controller;
NautilusToolbar *self = NAUTILUS_TOOLBAR (user_data);
self->path_bar = GTK_WIDGET (g_object_new (NAUTILUS_TYPE_PATH_BAR, NULL));
gtk_box_append (GTK_BOX (self->path_bar_container),
self->path_bar);
self->location_entry = nautilus_location_entry_new ();
gtk_box_append (GTK_BOX (self->location_entry_container),
self->location_entry);
self->location_entry_close_button = gtk_button_new_from_icon_name ("window-close-symbolic");
gtk_widget_set_tooltip_text (self->location_entry_close_button, _("Cancel"));
gtk_box_append (GTK_BOX (self->location_entry_container),
self->location_entry_close_button);
g_signal_connect (self->location_entry_close_button, "clicked",
G_CALLBACK (on_location_entry_close), self);
controller = gtk_event_controller_focus_new ();
gtk_widget_add_controller (self->location_entry, controller);
g_signal_connect (controller, "leave",
G_CALLBACK (on_location_entry_focus_leave), self);
/* Setting a max width on one entry to effectively set a max expansion for
* the whole title widget. */
gtk_editable_set_max_width_chars (GTK_EDITABLE (self->location_entry), 88);
toolbar_update_appearance (self);
nautilus_toolbar_close_location_entry (self);
nautilus_window_slot_open_location_full (self->window_slot, location, 0, NULL);
}
static void
@ -189,8 +221,34 @@ nautilus_toolbar_init (NautilusToolbar *self)
{
g_type_ensure (NAUTILUS_TYPE_HISTORY_CONTROLS);
g_type_ensure (NAUTILUS_TYPE_VIEW_CONTROLS);
g_type_ensure (NAUTILUS_TYPE_PATH_BAR);
g_type_ensure (NAUTILUS_TYPE_LOCATION_ENTRY);
gtk_widget_init_template (GTK_WIDGET (self));
/* Setup path bar */
g_signal_connect_object (self->path_bar, "open-location",
G_CALLBACK (on_path_bar_open_location), self,
G_CONNECT_DEFAULT);
/* Setup location entry */
GtkEventController *controller = gtk_event_controller_focus_new ();
gtk_widget_add_controller (self->location_entry, controller);
g_signal_connect (controller, "leave",
G_CALLBACK (on_location_entry_focus_leave), self);
/* Setting a max width on one entry to effectively set a max expansion for
* the whole title widget. */
gtk_editable_set_max_width_chars (GTK_EDITABLE (self->location_entry), 88);
g_signal_connect_object (self->location_entry, "location-changed",
G_CALLBACK (on_location_entry_location_changed), self,
G_CONNECT_DEFAULT);
g_signal_connect_object (self->location_entry, "cancel",
G_CALLBACK (nautilus_toolbar_close_location_entry), self,
G_CONNECT_SWAPPED);
toolbar_update_appearance (self);
}
static void
@ -203,12 +261,6 @@ nautilus_toolbar_get_property (GObject *object,
switch (property_id)
{
case PROP_SHOW_LOCATION_ENTRY:
{
g_value_set_boolean (value, self->show_location_entry);
}
break;
case PROP_WINDOW_SLOT:
{
g_value_set_object (value, self->window_slot);
@ -262,12 +314,6 @@ nautilus_toolbar_set_property (GObject *object,
switch (property_id)
{
case PROP_SHOW_LOCATION_ENTRY:
{
nautilus_toolbar_set_show_location_entry (self, g_value_get_boolean (value));
}
break;
case PROP_WINDOW_SLOT:
{
nautilus_toolbar_set_window_slot (self, g_value_get_object (value));
@ -316,6 +362,8 @@ nautilus_toolbar_finalize (GObject *obj)
{
NautilusToolbar *self = NAUTILUS_TOOLBAR (obj);
g_clear_weak_pointer (&self->focus_before_location_entry);
g_signal_handlers_disconnect_by_func (nautilus_preferences,
toolbar_update_appearance, self);
@ -342,14 +390,6 @@ nautilus_toolbar_class_init (NautilusToolbarClass *klass)
oclass->set_property = nautilus_toolbar_set_property;
oclass->dispose = nautilus_toolbar_dispose;
oclass->finalize = nautilus_toolbar_finalize;
oclass->constructed = nautilus_toolbar_constructed;
properties[PROP_SHOW_LOCATION_ENTRY] =
g_param_spec_boolean ("show-location-entry",
"Whether to show the location entry",
"Whether to show the location entry instead of the pathbar",
FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
properties [PROP_WINDOW_SLOT] =
g_param_spec_object ("window-slot",
@ -379,12 +419,14 @@ nautilus_toolbar_class_init (NautilusToolbarClass *klass)
gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, history_controls_placeholder);
gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, toolbar_switcher);
gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, search_container);
gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, path_bar_container);
gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, location_entry_container);
gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, path_bar);
gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, location_entry);
gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, search_button_stack);
gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, search_button);
gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, search_button_placeholder);
gtk_widget_class_bind_template_callback (widget_class, nautilus_toolbar_close_location_entry);
gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_TOOLBAR);
}
@ -395,31 +437,6 @@ nautilus_toolbar_new (void)
NULL);
}
GtkWidget *
nautilus_toolbar_get_path_bar (NautilusToolbar *self)
{
return self->path_bar;
}
GtkWidget *
nautilus_toolbar_get_location_entry (NautilusToolbar *self)
{
return self->location_entry;
}
void
nautilus_toolbar_set_show_location_entry (NautilusToolbar *self,
gboolean show_location_entry)
{
if (show_location_entry != self->show_location_entry)
{
self->show_location_entry = show_location_entry;
toolbar_update_appearance (self);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SHOW_LOCATION_ENTRY]);
}
}
static void
box_remove_all_children (GtkBox *box)
{
@ -430,6 +447,22 @@ box_remove_all_children (GtkBox *box)
}
}
static void
on_slot_location_changed (NautilusToolbar *self)
{
g_assert (self->window_slot != NULL);
GFile *location = nautilus_window_slot_get_location (self->window_slot);
if (location == NULL)
{
return;
}
nautilus_location_entry_set_location (NAUTILUS_LOCATION_ENTRY (self->location_entry), location);
nautilus_path_bar_set_path (NAUTILUS_PATH_BAR (self->path_bar), location);
}
static void
slot_on_extensions_background_menu_changed (NautilusToolbar *self,
GParamSpec *param,
@ -454,6 +487,12 @@ slot_on_templates_menu_changed (NautilusToolbar *self,
menu);
}
void
nautilus_toolbar_show_current_location_menu (NautilusToolbar *self)
{
nautilus_path_bar_show_current_location_menu (NAUTILUS_PATH_BAR (self->path_bar));
}
/* Called from on_window_slot_destroyed(), since bindings and signal handlers
* are automatically removed once the slot goes away.
*/
@ -461,8 +500,6 @@ static void
nautilus_toolbar_set_window_slot_real (NautilusToolbar *self,
NautilusWindowSlot *slot)
{
g_autoptr (GList) children = NULL;
self->window_slot = slot;
if (self->window_slot != NULL)
@ -471,6 +508,10 @@ nautilus_toolbar_set_window_slot_real (NautilusToolbar *self,
on_window_slot_destroyed,
self);
on_slot_location_changed (self);
g_signal_connect_swapped (self->window_slot, "notify::location",
G_CALLBACK (on_slot_location_changed), self);
g_signal_connect_swapped (self->window_slot, "notify::extensions-background-menu",
G_CALLBACK (slot_on_extensions_background_menu_changed), self);
g_signal_connect_swapped (self->window_slot, "notify::templates-menu",

View File

@ -36,11 +36,10 @@ G_DECLARE_FINAL_TYPE (NautilusToolbar, nautilus_toolbar, NAUTILUS, TOOLBAR, AdwB
GtkWidget *nautilus_toolbar_new (void);
GtkWidget *nautilus_toolbar_get_path_bar (NautilusToolbar *self);
GtkWidget *nautilus_toolbar_get_location_entry (NautilusToolbar *self);
void nautilus_toolbar_show_current_location_menu (NautilusToolbar *self);
void nautilus_toolbar_set_show_location_entry (NautilusToolbar *self,
gboolean show_location_entry);
void nautilus_toolbar_open_location_entry (NautilusToolbar *self,
const char *special_text);
void nautilus_toolbar_set_active_slot (NautilusToolbar *toolbar,
NautilusWindowSlot *slot);

View File

@ -223,80 +223,6 @@ vfs_file_set_metadata_as_list (NautilusFile *file,
nautilus_file_ref (file));
}
static GDateTime *
vfs_file_get_date (NautilusFile *file,
NautilusDateType date_type)
{
time_t file_time_raw = 0;
switch (date_type)
{
case NAUTILUS_DATE_TYPE_ACCESSED:
{
file_time_raw = nautilus_file_get_atime (file);
}
break;
case NAUTILUS_DATE_TYPE_MODIFIED:
{
file_time_raw = nautilus_file_get_mtime (file);
}
break;
case NAUTILUS_DATE_TYPE_CREATED:
{
file_time_raw = nautilus_file_get_btime (file);
}
break;
case NAUTILUS_DATE_TYPE_TRASHED:
{
file_time_raw = nautilus_file_get_trash_time (file);
}
break;
case NAUTILUS_DATE_TYPE_RECENCY:
{
file_time_raw = nautilus_file_get_recency (file);
}
break;
}
/* Before we have info on a file, the date is unknown. */
if (file_time_raw == 0)
{
return NULL;
}
else
{
return g_date_time_new_from_unix_local (file_time_raw);
}
}
static char *
vfs_file_get_where_string (NautilusFile *file)
{
GFile *activation_location;
NautilusFile *location;
char *where_string;
if (!nautilus_file_is_in_recent (file))
{
location = nautilus_file_ref (file);
}
else
{
activation_location = nautilus_file_get_activation_location (file);
location = nautilus_file_get (activation_location);
g_object_unref (activation_location);
}
where_string = nautilus_file_get_parent_uri_for_display (location);
nautilus_file_unref (location);
return where_string;
}
static void
vfs_file_mount_callback (GObject *source_object,
GAsyncResult *res,
@ -677,8 +603,6 @@ nautilus_vfs_file_class_init (NautilusVFSFileClass *klass)
file_class->call_when_ready = vfs_file_call_when_ready;
file_class->cancel_call_when_ready = vfs_file_cancel_call_when_ready;
file_class->check_if_ready = vfs_file_check_if_ready;
file_class->get_date = vfs_file_get_date;
file_class->get_where_string = vfs_file_get_where_string;
file_class->set_metadata = vfs_file_set_metadata;
file_class->set_metadata_as_list = vfs_file_set_metadata_as_list;
file_class->mount = vfs_file_mount;

View File

@ -7,7 +7,6 @@
#include "nautilus-view-controls.h"
#include "nautilus-toolbar-menu-sections.h"
#include "nautilus-window.h"
struct _NautilusViewControls
{

View File

@ -10,8 +10,8 @@
#define NAUTILUS_VIEW_LIST_ID 1
#define NAUTILUS_VIEW_GRID_ID 2
/* Special ids, not used by GSettings schemas: */
#define NAUTILUS_VIEW_NETWORK_ID 3
#define NAUTILUS_VIEW_INVALID_ID 0
#define NAUTILUS_VIEW_OTHER_LOCATIONS_ID 3
typedef struct
{

View File

@ -375,6 +375,19 @@ nautilus_view_model_set_sorter (NautilusViewModel *self,
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SORTER]);
}
/**
* Set the section sorter, effectively enabling sections.
*
* Unlike the regular sorter, which compares NautilusViewItem objects, this one
* compares the GtkTreeListRows objects which wrap the NautilusViewItem objects.
*/
void
nautilus_view_model_set_section_sorter (NautilusViewModel *self,
GtkSorter *section_sorter)
{
gtk_sort_list_model_set_section_sorter (self->sort_model, GTK_SORTER (section_sorter));
}
void
nautilus_view_model_sort (NautilusViewModel *self)
{

View File

@ -15,6 +15,8 @@ NautilusViewModel * nautilus_view_model_new (void);
GtkSorter *nautilus_view_model_get_sorter (NautilusViewModel *self);
void nautilus_view_model_set_sorter (NautilusViewModel *self,
GtkSorter *sorter);
void nautilus_view_model_set_section_sorter (NautilusViewModel *self,
GtkSorter *section_sorter);
void nautilus_view_model_sort (NautilusViewModel *self);
NautilusViewItem * nautilus_view_model_get_item_for_file (NautilusViewModel *self,
NautilusFile *file);

View File

@ -124,7 +124,7 @@ nautilus_view_get_icon_name (guint view_id)
{
return "view-grid-symbolic";
}
else if (view_id == NAUTILUS_VIEW_LIST_ID || view_id == NAUTILUS_VIEW_OTHER_LOCATIONS_ID)
else if (view_id == NAUTILUS_VIEW_LIST_ID || view_id == NAUTILUS_VIEW_NETWORK_ID)
{
return "view-list-symbolic";
}
@ -149,11 +149,7 @@ nautilus_view_get_tooltip (guint view_id)
{
return _("Grid View");
}
else if (view_id == NAUTILUS_VIEW_LIST_ID)
{
return _("List View");
}
else if (view_id == NAUTILUS_VIEW_OTHER_LOCATIONS_ID)
else if (view_id == NAUTILUS_VIEW_LIST_ID || view_id == NAUTILUS_VIEW_NETWORK_ID)
{
return _("List View");
}

View File

@ -31,12 +31,10 @@
#include "nautilus-files-view.h"
#include "nautilus-location-banner.h"
#include "nautilus-mime-actions.h"
#include "nautilus-places-view.h"
#include "nautilus-query-editor.h"
#include "nautilus-scheme.h"
#include "nautilus-toolbar.h"
#include "nautilus-view.h"
#include "nautilus-window.h"
#include "nautilus-x-content-bar.h"
#include <glib/gi18n.h>
@ -52,7 +50,6 @@
enum
{
PROP_ACTIVE = 1,
PROP_WINDOW,
PROP_ICON_NAME,
PROP_TOOLBAR_MENU_SECTIONS,
PROP_EXTENSIONS_BACKGROUND_MENU,
@ -72,8 +69,6 @@ struct _NautilusWindowSlot
{
AdwBin parent_instance;
NautilusWindow *window;
gboolean active : 1;
guint loading : 1;
@ -85,6 +80,7 @@ struct _NautilusWindowSlot
/* Slot actions */
GActionGroup *slot_action_group;
GtkShortcutController *shortcuts;
/* Current location. */
GFile *location;
@ -134,7 +130,7 @@ struct _NautilusWindowSlot
GCancellable *mount_cancellable;
GError *mount_error;
gboolean tried_mount;
gint view_mode_before_places;
gint view_mode_before_network;
/* Menus */
GMenuModel *extensions_background_menu;
@ -152,6 +148,13 @@ G_DEFINE_TYPE (NautilusWindowSlot, nautilus_window_slot, ADW_TYPE_BIN);
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
static const GtkPadActionEntry pad_actions[] =
{
{ GTK_PAD_ACTION_BUTTON, 3, -1, N_("Parent folder"), "up" },
{ GTK_PAD_ACTION_BUTTON, 4, -1, N_("Back"), "back" },
{ GTK_PAD_ACTION_BUTTON, 5, -1, N_("Forward"), "forward" },
};
static void nautilus_window_slot_force_reload (NautilusWindowSlot *self);
static void change_view (NautilusWindowSlot *self);
static void nautilus_window_slot_connect_new_content_view (NautilusWindowSlot *self);
@ -168,6 +171,8 @@ static void nautilus_window_slot_set_location (NautilusWindowSlot *self,
static void nautilus_window_slot_set_viewed_file (NautilusWindowSlot *self,
NautilusFile *file);
static void update_search_information (NautilusWindowSlot *self);
static void nautilus_window_slot_go_up (NautilusWindowSlot *self);
static void nautilus_window_slot_go_down (NautilusWindowSlot *self);
void
free_navigation_state (gpointer data)
@ -235,43 +240,26 @@ static NautilusView *
nautilus_window_slot_get_view_for_location (NautilusWindowSlot *self,
GFile *location)
{
g_autoptr (NautilusFile) file = NULL;
NautilusView *view;
guint view_id;
file = nautilus_file_get (location);
view = NULL;
view_id = NAUTILUS_VIEW_INVALID_ID;
if (nautilus_file_is_other_locations (file))
{
view = NAUTILUS_VIEW (nautilus_places_view_new ());
/* Save the current view, so we can go back after places view */
if (NAUTILUS_IS_FILES_VIEW (self->content_view))
{
self->view_mode_before_places = nautilus_view_get_view_id (self->content_view);
}
return view;
}
g_autoptr (NautilusFile) file = nautilus_file_get (location);
NautilusView *view = NULL;
guint view_id = NAUTILUS_VIEW_INVALID_ID;
if (self->content_view != NULL)
{
/* If there is already a view, just use the view mode that it's currently using, or
* if we were on "Other Locations" before, use what we were using before entering
* it. */
if (NAUTILUS_IS_PLACES_VIEW (self->content_view))
/* If there is already a view, just use the view mode that it's currently using */
view_id = nautilus_view_get_view_id (self->content_view);
if (view_id == NAUTILUS_VIEW_NETWORK_ID)
{
view_id = self->view_mode_before_places;
self->view_mode_before_places = NAUTILUS_VIEW_INVALID_ID;
}
else
{
view_id = nautilus_view_get_view_id (self->content_view);
view_id = self->view_mode_before_network;
}
}
if (nautilus_file_is_network_view (file))
{
self->view_mode_before_network = view_id;
view_id = NAUTILUS_VIEW_NETWORK_ID;
}
/* If there is not previous view in this slot, use the default view mode
* from preferences */
if (view_id == NAUTILUS_VIEW_INVALID_ID)
@ -343,6 +331,7 @@ static void
nautilus_window_slot_sync_actions (NautilusWindowSlot *self)
{
NautilusView *view;
gboolean is_network_view;
GAction *action;
GVariant *variant;
@ -363,15 +352,16 @@ nautilus_window_slot_sync_actions (NautilusWindowSlot *self)
/* Files view mode */
view = nautilus_window_slot_get_current_view (self);
is_network_view = nautilus_view_get_view_id (view) == NAUTILUS_VIEW_NETWORK_ID;
action = g_action_map_lookup_action (G_ACTION_MAP (self->slot_action_group), "files-view-mode");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), NAUTILUS_IS_FILES_VIEW (view));
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), !is_network_view);
if (g_action_get_enabled (action))
{
variant = g_variant_new_uint32 (nautilus_view_get_view_id (view));
g_action_change_state (action, variant);
}
action = g_action_map_lookup_action (G_ACTION_MAP (self->slot_action_group), "files-view-mode-toggle");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), NAUTILUS_IS_FILES_VIEW (view));
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), !is_network_view);
}
static void
@ -452,7 +442,7 @@ hide_query_editor (NautilusWindowSlot *self)
if (nautilus_window_slot_get_active (self))
{
gtk_widget_grab_focus (GTK_WIDGET (self->window));
gtk_widget_grab_focus (GTK_WIDGET (gtk_widget_get_root (GTK_WIDGET (self))));
}
}
@ -672,18 +662,6 @@ nautilus_window_slot_set_property (GObject *object,
switch (property_id)
{
case PROP_ACTIVE:
{
nautilus_window_slot_set_active (self, g_value_get_boolean (value));
}
break;
case PROP_WINDOW:
{
nautilus_window_slot_set_window (self, g_value_get_object (value));
}
break;
case PROP_LOCATION:
{
nautilus_window_slot_set_location (self, g_value_get_object (value));
@ -769,12 +747,6 @@ nautilus_window_slot_get_property (GObject *object,
}
break;
case PROP_WINDOW:
{
g_value_set_object (value, self->window);
}
break;
case PROP_ICON_NAME:
{
g_value_set_static_string (value, nautilus_window_slot_get_icon_name (self));
@ -912,6 +884,87 @@ nautilus_window_slot_constructed (GObject *object)
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TITLE]);
}
static void
update_back_forward_actions (NautilusWindowSlot *self)
{
GAction *action;
gboolean enabled;
enabled = (nautilus_window_slot_get_back_history (self) != NULL &&
!nautilus_window_slot_get_search_global (self));
action = g_action_map_lookup_action (G_ACTION_MAP (self->slot_action_group), "back");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), enabled);
action = g_action_map_lookup_action (G_ACTION_MAP (self->slot_action_group), "back-n");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), enabled);
enabled = (nautilus_window_slot_get_forward_history (self) != NULL &&
!nautilus_window_slot_get_search_global (self));
action = g_action_map_lookup_action (G_ACTION_MAP (self->slot_action_group), "forward");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), enabled);
action = g_action_map_lookup_action (G_ACTION_MAP (self->slot_action_group), "forward-n");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), enabled);
}
static void
action_back (GSimpleAction *action,
GVariant *state,
gpointer user_data)
{
NautilusWindowSlot *self = NAUTILUS_WINDOW_SLOT (user_data);
nautilus_window_slot_back_or_forward (self, TRUE, 0);
}
static void
action_forward (GSimpleAction *action,
GVariant *state,
gpointer user_data)
{
NautilusWindowSlot *self = NAUTILUS_WINDOW_SLOT (user_data);
nautilus_window_slot_back_or_forward (self, FALSE, 0);
}
static void
action_back_n (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
NautilusWindowSlot *self = NAUTILUS_WINDOW_SLOT (user_data);
nautilus_window_slot_back_or_forward (self, TRUE, g_variant_get_uint32 (parameter));
}
static void
action_forward_n (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
NautilusWindowSlot *self = NAUTILUS_WINDOW_SLOT (user_data);
nautilus_window_slot_back_or_forward (self, FALSE, g_variant_get_uint32 (parameter));
}
static void
action_up (GSimpleAction *action,
GVariant *state,
gpointer user_data)
{
NautilusWindowSlot *self = NAUTILUS_WINDOW_SLOT (user_data);
nautilus_window_slot_go_up (self);
}
static void
action_down (GSimpleAction *action,
GVariant *state,
gpointer user_data)
{
NautilusWindowSlot *self = NAUTILUS_WINDOW_SLOT (user_data);
nautilus_window_slot_go_down (self);
}
static void
action_focus_search (GSimpleAction *action,
GVariant *state,
@ -1006,6 +1059,8 @@ action_search_global (GSimpleAction *action,
nautilus_window_slot_set_search_visible (self, search_global);
gtk_widget_set_visible (GTK_WIDGET (self->banner), !search_global);
update_back_forward_actions (self);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SEARCH_GLOBAL]);
}
}
@ -1074,8 +1129,34 @@ action_files_view_mode (GSimpleAction *action,
g_simple_action_set_state (action, value);
}
static void
action_reload (GSimpleAction *action,
GVariant *state,
gpointer user_data)
{
NautilusWindowSlot *self = NAUTILUS_WINDOW_SLOT (user_data);
nautilus_window_slot_queue_reload (self);
}
static void
action_stop (GSimpleAction *action,
GVariant *state,
gpointer user_data)
{
NautilusWindowSlot *self = NAUTILUS_WINDOW_SLOT (user_data);
nautilus_window_slot_stop_loading (self);
}
const GActionEntry slot_entries[] =
{
{ .name = "back", .activate = action_back },
{ .name = "forward", .activate = action_forward },
{ .name = "back-n", .activate = action_back_n, .parameter_type = "u" },
{ .name = "forward-n", .activate = action_forward_n, .parameter_type = "u" },
{ .name = "up", .activate = action_up },
{ .name = "down", .activate = action_down },
{
.name = "files-view-mode", .parameter_type = "u",
.state = "uint32 " G_STRINGIFY (NAUTILUS_VIEW_INVALID_ID),
@ -1085,6 +1166,8 @@ const GActionEntry slot_entries[] =
{ .name = "search-visible", .state = "false", .change_state = action_search_visible },
{ .name = "search-global", .state = "false", .change_state = action_search_global },
{ .name = "focus-search", .activate = action_focus_search },
{ .name = "reload", .activate = action_reload },
{ .name = "stop", .activate = action_stop },
};
static void
@ -1109,11 +1192,8 @@ update_search_information (NautilusWindowSlot *self)
file = nautilus_file_get (location);
label = NULL;
if (nautilus_file_is_other_locations (file))
{
label = _("Searching locations only");
}
else if (nautilus_is_root_for_scheme (location, SCHEME_NETWORK))
if (nautilus_is_root_for_scheme (location, SCHEME_NETWORK_VIEW) ||
nautilus_is_root_for_scheme (location, SCHEME_NETWORK))
{
label = _("Searching network locations only");
}
@ -1145,19 +1225,25 @@ recursive_search_preferences_changed (GSettings *settings,
update_search_information (self);
}
static void
set_back_forward_accelerators (NautilusWindowSlot *self)
{
gboolean ltr = (gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_LTR);
#define ADD_SHORTCUT_FOR_ACTION(controller, action, trigger) \
(gtk_shortcut_controller_add_shortcut ((controller), \
gtk_shortcut_new (gtk_shortcut_trigger_parse_string ((trigger)), \
gtk_named_action_new ((action)))))
ADD_SHORTCUT_FOR_ACTION (self->shortcuts, "slot.back", ltr ? "<alt>Left|Back" : "<alt>Right|Back");
ADD_SHORTCUT_FOR_ACTION (self->shortcuts, "slot.forward", ltr ? "<alt>Right|Forward" : "<alt>Left|Forward");
#undef ADD_SHORTCUT_FOR_ACTION
}
static void
nautilus_window_slot_init (NautilusWindowSlot *self)
{
GApplication *app;
const gchar *search_visible_accels[] =
{
"<control>f",
"Search",
NULL
};
app = g_application_get_default ();
g_signal_connect_object (nautilus_preferences,
"changed::recursive-search",
G_CALLBACK (recursive_search_preferences_changed),
@ -1172,17 +1258,47 @@ nautilus_window_slot_init (NautilusWindowSlot *self)
"slot",
G_ACTION_GROUP (self->slot_action_group));
nautilus_application_set_accelerator (app,
"slot.files-view-mode(uint32 " G_STRINGIFY (NAUTILUS_VIEW_LIST_ID) ")",
"<control>1");
nautilus_application_set_accelerator (app,
"slot.files-view-mode(uint32 " G_STRINGIFY (NAUTILUS_VIEW_GRID_ID) ")",
"<control>2");
nautilus_application_set_accelerators (app, "slot.focus-search", search_visible_accels);
nautilus_application_set_accelerator (app, "slot.search-global", "<control><shift>f");
self->shortcuts = GTK_SHORTCUT_CONTROLLER (gtk_shortcut_controller_new ());
gtk_shortcut_controller_set_scope (self->shortcuts, GTK_SHORTCUT_SCOPE_MANAGED);
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (self->shortcuts));
g_autoptr (GtkShortcutAction) view_mode_action = gtk_named_action_new ("slot.files-view-mode");
GtkShortcut *shortcut;
shortcut = gtk_shortcut_new_with_arguments (gtk_shortcut_trigger_parse_string ("<control>1"),
g_object_ref (view_mode_action),
"u", NAUTILUS_VIEW_LIST_ID);
gtk_shortcut_controller_add_shortcut (self->shortcuts, shortcut);
shortcut = gtk_shortcut_new_with_arguments (gtk_shortcut_trigger_parse_string ("<control>2"),
g_object_ref (view_mode_action),
"u", NAUTILUS_VIEW_GRID_ID);
gtk_shortcut_controller_add_shortcut (self->shortcuts, shortcut);
#define ADD_SHORTCUT_FOR_ACTION(controller, action, trigger) \
(gtk_shortcut_controller_add_shortcut ((controller), \
gtk_shortcut_new (gtk_shortcut_trigger_parse_string ((trigger)), \
gtk_named_action_new ((action)))))
ADD_SHORTCUT_FOR_ACTION (self->shortcuts, "slot.focus-search", "<control>f|Search");
ADD_SHORTCUT_FOR_ACTION (self->shortcuts, "slot.search-global", "<control><shift>f");
ADD_SHORTCUT_FOR_ACTION (self->shortcuts, "slot.reload", "F5|<ctrl>r|Refresh|Reload");
ADD_SHORTCUT_FOR_ACTION (self->shortcuts, "slot.stop", "Stop");
ADD_SHORTCUT_FOR_ACTION (self->shortcuts, "slot.up", "<alt>Up");
ADD_SHORTCUT_FOR_ACTION (self->shortcuts, "slot.down", "<alt>Down");
#undef ADD_SHORTCUT_FOR_ACTION
set_back_forward_accelerators (self);
g_signal_connect_swapped (self, "direction-changed",
G_CALLBACK (set_back_forward_accelerators), self);
GtkPadController *pad_controller = gtk_pad_controller_new (G_ACTION_GROUP (self->slot_action_group), NULL);
gtk_pad_controller_set_action_entries (pad_controller, pad_actions, G_N_ELEMENTS (pad_actions));
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (pad_controller));
self->fd_holder = nautilus_fd_holder_new ();
self->view_mode_before_places = NAUTILUS_VIEW_INVALID_ID;
self->view_mode_before_network = NAUTILUS_VIEW_INVALID_ID;
}
static void begin_location_change (NautilusWindowSlot *slot,
@ -1197,12 +1313,6 @@ static void got_file_info_for_view_selection_callback (NautilusFile *file,
gpointer callback_data);
static gboolean setup_view (NautilusWindowSlot *self,
NautilusView *view);
static void load_new_location (NautilusWindowSlot *slot,
GFile *location,
GList *selection,
NautilusFile *file_to_activate,
gboolean tell_current_content_view,
gboolean tell_new_content_view);
void
nautilus_window_slot_open_location_full (NautilusWindowSlot *self,
@ -1410,11 +1520,6 @@ nautilus_window_slot_set_location (NautilusWindowSlot *self,
old_location = self->location;
self->location = g_object_ref (location);
if (nautilus_window_slot_get_active (self))
{
nautilus_window_sync_location_widgets (self->window);
}
nautilus_window_slot_update_title (self);
if (old_location)
@ -1423,6 +1528,7 @@ nautilus_window_slot_set_location (NautilusWindowSlot *self,
}
nautilus_fd_holder_set_location (self->fd_holder, self->location);
update_back_forward_actions (self);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LOCATION]);
}
@ -1601,10 +1707,10 @@ mount_not_mounted_callback (GObject *source_object,
}
static void
nautilus_window_slot_display_view_selection_failure (NautilusWindow *window,
NautilusFile *file,
GFile *location,
GError *error)
nautilus_window_slot_display_view_selection_failure (GtkWindow *window,
NautilusFile *file,
GFile *location,
GError *error)
{
char *error_message;
char *detail_message;
@ -1712,7 +1818,7 @@ nautilus_window_slot_display_view_selection_failure (NautilusWindow *window,
detail_message = g_strdup_printf (_("Unhandled error message: %s"), error->message);
}
show_dialog (error_message, detail_message, GTK_WINDOW (window), GTK_MESSAGE_ERROR);
show_dialog (error_message, detail_message, window, GTK_MESSAGE_ERROR);
done:
g_free (error_message);
@ -1740,14 +1846,12 @@ static gboolean
handle_mount_if_needed (NautilusWindowSlot *self,
NautilusFile *file)
{
NautilusWindow *window;
GMountOperation *mount_op;
MountNotMountedData *data;
GFile *location;
GError *error = NULL;
gboolean needs_mount_handling = FALSE;
window = nautilus_window_slot_get_window (self);
if (self->mount_error)
{
error = g_error_copy (self->mount_error);
@ -1762,7 +1866,7 @@ handle_mount_if_needed (NautilusWindowSlot *self,
{
self->tried_mount = TRUE;
mount_op = gtk_mount_operation_new (GTK_WINDOW (window));
mount_op = gtk_mount_operation_new (GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self))));
g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION);
location = nautilus_file_get_location (file);
data = g_new0 (MountNotMountedData, 1);
@ -1825,14 +1929,11 @@ got_file_info_for_view_selection_callback (NautilusFile *file,
gpointer callback_data)
{
GError *error = NULL;
NautilusWindow *window;
NautilusWindowSlot *self;
NautilusView *view;
GFile *location;
NautilusApplication *app;
self = callback_data;
window = nautilus_window_slot_get_window (self);
g_assert (self->determine_view_file == file);
self->determine_view_file = NULL;
@ -1858,88 +1959,56 @@ got_file_info_for_view_selection_callback (NautilusFile *file,
location = self->pending_location;
/* desktop and other-locations GFile operations report G_IO_ERROR_NOT_SUPPORTED,
* but it's not an actual error for Nautilus */
if (!error || g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
if (error == NULL)
{
view = nautilus_window_slot_get_view_for_location (self, location);
setup_view (self, view);
}
else
{
GtkWindow *window = GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self)));
nautilus_window_slot_display_view_selection_failure (window,
file,
location,
error);
if (!gtk_widget_get_visible (GTK_WIDGET (window)))
GFile *slot_location = nautilus_window_slot_get_location (self);
if (slot_location == NULL)
{
/* Destroy never-had-a-chance-to-be-seen window. This case
* happens when a new window cannot display its initial URI.
*/
/* if this is the only window, we don't want to quit, so we redirect it to home */
/* This happens when a new slot cannot display its initial URI.
* As usual, fallback to $HOME.
*
* But guard against the case that $HOME cannot be displayed either,
* otherwise we would enter an infinite loop. */
app = NAUTILUS_APPLICATION (g_application_get_default ());
if (g_list_length (nautilus_application_get_windows (app)) == 1)
if (!nautilus_is_home_directory (location))
{
/* the user could have typed in a home directory that doesn't exist,
* in which case going home would cause an infinite loop, so we
* better test for that */
if (!nautilus_is_root_directory (location))
{
if (!nautilus_is_home_directory (location))
{
nautilus_window_slot_go_home (self, FALSE);
}
else
{
GFile *root;
root = g_file_new_for_path ("/");
/* the last fallback is to go to a known place that can't be deleted! */
nautilus_window_slot_open_location_full (self, location, 0, NULL);
g_object_unref (root);
}
}
else
{
gtk_window_destroy (GTK_WINDOW (window));
}
nautilus_window_slot_go_home (self, FALSE);
}
else
{
/* Since this is a window, destroying it will also unref it. */
gtk_window_destroy (GTK_WINDOW (window));
/* the last fallback is to go to a known place that can't be deleted! */
g_autoptr (GFile) root = g_file_new_for_path ("/");
nautilus_window_slot_open_location_full (self, root, 0, NULL);
}
}
else
{
GFile *slot_location;
/* Clean up state of already-showing window */
/* Clean up state of slot already showing a previous location */
end_location_change (self);
slot_location = nautilus_window_slot_get_location (self);
if (slot_location == NULL)
{
/* Location is NULL if we open a broken bookmark in a new window */
nautilus_window_slot_go_home (self, 0);
}
else
{
/* We disconnected this, so we need to re-connect it.
* Although not conceptually correct, a force reload is a simple
* way to do that. In the future we may want to have an error
* status page instead and only reload on explicit request. */
nautilus_window_slot_force_reload (self);
/* We disconnected this, so we need to re-connect it.
* Although not conceptually correct, a force reload is a simple
* way to do that. In the future we may want to have an error
* status page instead and only reload on explicit request. */
nautilus_window_slot_force_reload (self);
/* Leave the location bar showing the bad location that the user
* typed (or maybe achieved by dragging or something). Many times
* the mistake will just be an easily-correctable typo.
*/
}
/* Leave the location bar showing the bad location that the user
* typed (or maybe achieved by dragging or something). Many times
* the mistake will just be an easily-correctable typo.
*/
}
}
@ -1960,6 +2029,8 @@ static gboolean
setup_view (NautilusWindowSlot *self,
NautilusView *view)
{
g_assert (view != NULL);
gboolean ret = TRUE;
GFile *old_location;
@ -1972,31 +2043,33 @@ setup_view (NautilusWindowSlot *self,
/* Forward search selection and state before loading the new model */
old_location = self->content_view ? nautilus_view_get_location (self->content_view) : NULL;
/* Actually load the pending location and selection: */
if (self->pending_location != NULL)
{
load_new_location (self,
self->pending_location,
self->pending_selection,
self->pending_file_to_activate,
FALSE,
TRUE);
/* Load the pending location and selection */
nautilus_view_set_location (self->new_content_view, self->pending_location);
nautilus_file_list_free (self->pending_selection);
self->pending_selection = NULL;
if (self->pending_file_to_activate != NULL &&
NAUTILUS_IS_FILES_VIEW (self->new_content_view))
{
g_autoptr (GAppInfo) app_info = NULL;
const gchar *app_id;
app_info = nautilus_mime_get_default_application_for_file (self->pending_file_to_activate);
app_id = g_app_info_get_id (app_info);
if (g_strcmp0 (app_id, NAUTILUS_DESKTOP_ID) == 0)
{
nautilus_files_view_activate_file (NAUTILUS_FILES_VIEW (view),
self->pending_file_to_activate, 0);
}
}
}
else if (old_location != NULL)
{
g_autolist (NautilusFile) selection = NULL;
/* Reuse current location and selection */
g_autolist (NautilusFile) selection = nautilus_view_get_selection (self->content_view);
selection = nautilus_view_get_selection (self->content_view);
load_new_location (self,
old_location,
selection,
NULL,
FALSE,
TRUE);
nautilus_view_set_location (self->new_content_view, old_location);
nautilus_view_set_selection (self->new_content_view, selection);
}
else
{
@ -2010,52 +2083,6 @@ out:
return ret;
}
static void
load_new_location (NautilusWindowSlot *self,
GFile *location,
GList *selection,
NautilusFile *file_to_activate,
gboolean tell_current_content_view,
gboolean tell_new_content_view)
{
NautilusView *view = NULL;
g_assert (self != NULL);
g_assert (location != NULL);
/* Note, these may recurse into report_load_underway */
if (self->content_view != NULL && tell_current_content_view)
{
view = self->content_view;
nautilus_view_set_location (self->content_view, location);
}
if (self->new_content_view != NULL && tell_new_content_view &&
(!tell_current_content_view ||
self->new_content_view != self->content_view))
{
view = self->new_content_view;
nautilus_view_set_location (self->new_content_view, location);
}
if (view)
{
nautilus_view_set_selection (view, selection);
if (file_to_activate != NULL)
{
g_autoptr (GAppInfo) app_info = NULL;
const gchar *app_id;
g_return_if_fail (NAUTILUS_IS_FILES_VIEW (view));
app_info = nautilus_mime_get_default_application_for_file (file_to_activate);
app_id = g_app_info_get_id (app_info);
if (g_strcmp0 (app_id, NAUTILUS_DESKTOP_ID) == 0)
{
nautilus_files_view_activate_file (NAUTILUS_FILES_VIEW (view),
file_to_activate, 0);
}
}
}
}
static void
end_location_change (NautilusWindowSlot *self)
{
@ -2521,6 +2548,24 @@ nautilus_window_slot_update_for_new_location (NautilusWindowSlot *self)
nautilus_location_banner_load (self->banner, new_location);
}
static gboolean
focus_is_on_popup (GtkRoot *window)
{
GtkWidget *focus = gtk_root_get_focus (window);
if (focus != NULL)
{
GtkNative *native = gtk_widget_get_native (focus);
if (native != NULL)
{
return GDK_IS_POPUP (gtk_native_get_surface (native));
}
}
return FALSE;
}
static void
view_started_loading (NautilusWindowSlot *self,
NautilusView *view)
@ -2530,12 +2575,29 @@ view_started_loading (NautilusWindowSlot *self,
nautilus_window_slot_set_allow_stop (self, TRUE);
}
/* Only grab focus if the menu isn't showing. Otherwise the menu disappears
* e.g. when the user toggles Show Hidden Files
*/
if (!nautilus_window_is_menu_visible (self->window))
GtkRoot *window = gtk_widget_get_root (GTK_WIDGET (self));
if (!focus_is_on_popup (window))
{
gtk_widget_grab_focus (GTK_WIDGET (self->window));
/* This mysterious gtk_widget_grab_focus() call has been carried over
* many refactorings, along the way having been wrapped in multiple ways
* (nautilus_view_grab_focus(), nautilus_window_pane_grab_focus(),
* nautilus_view_grab_focus()). It's been added in a series of bugfixes
* related to extra pane.[0] If I had to guess, I'd say it was to deal
* with side effects of the grandparent commit[1], which removed a much
* older bugfix[2].
*
* Regardless of its original purpose, we still rely on this call to
* prevent a "lost focus" situation. This is easily reproduced, in a
* build where this call is removed, by refreshing a view where nothing
* is selected. This "lost focus" state means, e.g., some keybindings,
* such as Ctrl+A, won't work.
*
* [0] Commit c69f3a2ba2d0bd23de5a218b8ce13d256481213a
* [1] Commit 4efd42312584b46f248e2839582a87776a7baebe
* [2] Commit 4f7ae827f7e13cf06965cc72ca60cf7801906a33
*/
gtk_widget_grab_focus (GTK_WIDGET (window));
}
nautilus_window_slot_set_loading (self, TRUE);
@ -2668,6 +2730,7 @@ nautilus_window_slot_switch_new_content_view (NautilusWindowSlot *self)
widget = GTK_WIDGET (self->content_view);
gtk_box_append (GTK_BOX (self->vbox), widget);
gtk_widget_set_vexpand (widget, TRUE);
/* Note that this is not bidirectional and that we may also change
* :search-visible alone, e.g. when clicking the search button. */
self->searching_binding = g_object_bind_property (self->content_view, "searching",
@ -2830,7 +2893,7 @@ nautilus_window_slot_class_init (NautilusWindowSlotClass *klass)
"Whether the slot is active",
"Whether the slot is the active slot of the window",
FALSE,
G_PARAM_READWRITE);
G_PARAM_READABLE);
properties[PROP_LOADING] =
g_param_spec_boolean ("loading",
@ -2861,13 +2924,6 @@ nautilus_window_slot_class_init (NautilusWindowSlotClass *klass)
"The selection of the current view of the slot. Proxy property from the view",
G_PARAM_READWRITE);
properties[PROP_WINDOW] =
g_param_spec_object ("window",
"The NautilusWindow",
"The NautilusWindow this slot is part of",
NAUTILUS_TYPE_WINDOW,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
properties[PROP_ICON_NAME] =
g_param_spec_string ("icon-name",
"Icon that represents the slot",
@ -2956,28 +3012,6 @@ nautilus_window_slot_get_location_uri (NautilusWindowSlot *self)
return NULL;
}
NautilusWindow *
nautilus_window_slot_get_window (NautilusWindowSlot *self)
{
g_assert (NAUTILUS_IS_WINDOW_SLOT (self));
return self->window;
}
void
nautilus_window_slot_set_window (NautilusWindowSlot *self,
NautilusWindow *window)
{
g_assert (NAUTILUS_IS_WINDOW_SLOT (self));
g_assert (NAUTILUS_IS_WINDOW (window));
if (self->window != window)
{
self->window = window;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_WINDOW]);
}
}
/* nautilus_window_slot_update_title:
*
* Re-calculate the slot title.
@ -2988,10 +3022,7 @@ nautilus_window_slot_set_window (NautilusWindowSlot *self,
void
nautilus_window_slot_update_title (NautilusWindowSlot *self)
{
NautilusWindow *window;
g_autofree char *title = NULL;
title = nautilus_compute_title_for_location (self->location);
window = nautilus_window_slot_get_window (self);
g_autofree char *title = nautilus_compute_title_for_location (self->location);
if (g_strcmp0 (title, self->title) != 0)
{
@ -2999,8 +3030,6 @@ nautilus_window_slot_update_title (NautilusWindowSlot *self)
self->title = g_steal_pointer (&title);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TITLE]);
nautilus_window_sync_title (window, self);
}
}
@ -3014,13 +3043,16 @@ void
nautilus_window_slot_set_allow_stop (NautilusWindowSlot *self,
gboolean allow)
{
NautilusWindow *window;
g_assert (NAUTILUS_IS_WINDOW_SLOT (self));
self->allow_stop = allow;
window = nautilus_window_slot_get_window (self);
nautilus_window_sync_allow_stop (window, self);
GActionMap *action_map = G_ACTION_MAP (self->slot_action_group);
GAction *stop_action = g_action_map_lookup_action (action_map, "stop");
GAction *reload_action = g_action_map_lookup_action (action_map, "reload");
g_simple_action_set_enabled (G_SIMPLE_ACTION (stop_action), self->allow_stop);
g_simple_action_set_enabled (G_SIMPLE_ACTION (reload_action), !self->allow_stop);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ALLOW_STOP]);
}
@ -3050,15 +3082,10 @@ nautilus_window_slot_stop_loading (NautilusWindowSlot *self)
* be told, or it is the very pending change we wish
* to cancel.
*/
g_autolist (NautilusFile) selection = NULL;
g_autolist (NautilusFile) selection = nautilus_view_get_selection (self->content_view);
selection = nautilus_view_get_selection (self->content_view);
load_new_location (self,
location,
selection,
NULL,
TRUE,
FALSE);
nautilus_view_set_location (self->content_view, location);
nautilus_view_set_selection (self->content_view, selection);
}
end_location_change (self);
@ -3104,10 +3131,9 @@ nautilus_window_slot_get_forward_history (NautilusWindowSlot *self)
}
NautilusWindowSlot *
nautilus_window_slot_new (NautilusWindow *window)
nautilus_window_slot_new (void)
{
return g_object_new (NAUTILUS_TYPE_WINDOW_SLOT,
"window", window,
NULL);
}
@ -3137,9 +3163,9 @@ nautilus_window_slot_get_icon_name (NautilusWindowSlot *self)
}
break;
case NAUTILUS_VIEW_OTHER_LOCATIONS_ID:
case NAUTILUS_VIEW_NETWORK_ID:
{
return nautilus_view_get_icon_name (NAUTILUS_VIEW_OTHER_LOCATIONS_ID);
return nautilus_view_get_icon_name (NAUTILUS_VIEW_NETWORK_ID);
}
break;
@ -3176,9 +3202,9 @@ nautilus_window_slot_get_tooltip (NautilusWindowSlot *self)
}
break;
case NAUTILUS_VIEW_OTHER_LOCATIONS_ID:
case NAUTILUS_VIEW_NETWORK_ID:
{
return nautilus_view_get_tooltip (NAUTILUS_VIEW_OTHER_LOCATIONS_ID);
return nautilus_view_get_tooltip (NAUTILUS_VIEW_NETWORK_ID);
}
break;
@ -3213,39 +3239,23 @@ void
nautilus_window_slot_set_active (NautilusWindowSlot *self,
gboolean active)
{
NautilusWindow *window;
g_return_if_fail (NAUTILUS_IS_WINDOW_SLOT (self));
if (self->active != active)
{
GtkRoot *window = gtk_widget_get_root (GTK_WIDGET (self));
self->active = active;
if (active)
{
AdwTabView *tab_view;
AdwTabPage *page;
window = self->window;
tab_view = nautilus_window_get_tab_view (window);
page = adw_tab_view_get_page (tab_view, GTK_WIDGET (self));
adw_tab_view_set_selected_page (tab_view, page);
/* sync window to new slot */
nautilus_window_sync_allow_stop (window, self);
nautilus_window_sync_title (window, self);
nautilus_window_sync_location_widgets (window);
nautilus_window_slot_sync_actions (self);
gtk_widget_insert_action_group (GTK_WIDGET (window), "slot", self->slot_action_group);
}
else
{
window = nautilus_window_slot_get_window (self);
g_assert (self == nautilus_window_get_active_slot (window));
gtk_widget_insert_action_group (GTK_WIDGET (window), "slot", NULL);
}
@ -3280,7 +3290,7 @@ nautilus_window_slot_get_query_editor (NautilusWindowSlot *self)
return self->query_editor;
}
void
static void
nautilus_window_slot_go_up (NautilusWindowSlot *self)
{
GFile *location = nautilus_window_slot_get_location (self);
@ -3302,7 +3312,7 @@ nautilus_window_slot_go_up (NautilusWindowSlot *self)
}
}
void
static void
nautilus_window_slot_go_down (NautilusWindowSlot *self)
{
g_autolist (GFile) down_list = g_steal_pointer (&self->down_list);

View File

@ -46,11 +46,7 @@ typedef struct
NautilusQuery *current_search_query;
} NautilusNavigationState;
NautilusWindowSlot * nautilus_window_slot_new (NautilusWindow *window);
NautilusWindow * nautilus_window_slot_get_window (NautilusWindowSlot *slot);
void nautilus_window_slot_set_window (NautilusWindowSlot *slot,
NautilusWindow *window);
NautilusWindowSlot * nautilus_window_slot_new (void);
void nautilus_window_slot_open_location_full (NautilusWindowSlot *slot,
GFile *location,
@ -119,7 +115,4 @@ void nautilus_window_slot_back_or_forward (NautilusWindowSlot *
gboolean back,
guint distance);
void nautilus_window_slot_go_up (NautilusWindowSlot *slot);
void nautilus_window_slot_go_down (NautilusWindowSlot *slot);
void free_navigation_state (gpointer data);

File diff suppressed because it is too large Load Diff

View File

@ -41,11 +41,6 @@ typedef gboolean (* NautilusWindowGoToCallback) (NautilusWindow *window,
GError *error,
gpointer user_data);
typedef void (* NautilusWindowHandleExported) (NautilusWindow *window,
const char *handle,
guint xid,
gpointer user_data);
/* window geometry */
/* Min values are very small, and a Nautilus window at this tiny size is *almost*
* completely unusable. However, if all the extra bits (sidebar, location bar, etc)
@ -81,24 +76,8 @@ GList * nautilus_window_get_slots (NautilusWindow *wind
void nautilus_window_slot_close (NautilusWindow *window,
NautilusWindowSlot *slot);
void nautilus_window_sync_location_widgets (NautilusWindow *window);
void nautilus_window_reset_menus (NautilusWindow *window);
AdwTabView * nautilus_window_get_tab_view (NautilusWindow *window);
void nautilus_window_show_about_dialog (NautilusWindow *window);
gboolean nautilus_window_is_menu_visible (NautilusWindow *toolbar);
/* sync window GUI with current slot. Used when changing slots,
* and when updating the slot state.
*/
void nautilus_window_sync_allow_stop (NautilusWindow *window,
NautilusWindowSlot *slot);
void nautilus_window_sync_title (NautilusWindow *window,
NautilusWindowSlot *slot);
void nautilus_window_show_operation_notification (NautilusWindow *window,
gchar *main_label,
GFile *folder_to_open,
@ -111,11 +90,6 @@ void nautilus_window_initialize_slot (NautilusWindow *window,
NautilusWindowSlot *slot,
NautilusOpenFlags flags);
gboolean nautilus_window_export_handle (NautilusWindow *window,
NautilusWindowHandleExported callback,
gpointer user_data);
void nautilus_window_unexport_handle (NautilusWindow *window);
void nautilus_window_back_or_forward_in_new_tab (NautilusWindow *window,
NautilusNavigationDirection back);

View File

@ -30,7 +30,7 @@
<child>
<object class="GtkShortcutsShortcut">
<property name="title" translatable="yes" context="shortcut window">Search Everywhere</property>
<property name="action-name">slot.search-global</property>
<property name="accelerator">&lt;Primary&gt;&lt;Shift&gt;F</property>
</object>
</child>
<child>
@ -193,7 +193,7 @@
<child>
<object class="GtkShortcutsShortcut">
<property name="title" translatable="yes" context="shortcut window">Go Up</property>
<property name="action-name">win.up</property>
<property name="accelerator">&lt;alt&gt;Up</property>
</object>
</child>
<child>
@ -258,7 +258,7 @@
<child>
<object class="GtkShortcutsShortcut">
<property name="title" translatable="yes" context="shortcut window">Show/Hide Hidden Files</property>
<property name="action-name">view.show-hidden-files</property>
<property name="accelerator">&lt;Primary&gt;H</property>
</object>
</child>
<child>
@ -321,7 +321,7 @@
<child>
<object class="GtkShortcutsShortcut">
<property name="title" translatable="yes" context="shortcut window">Create Folder</property>
<property name="action-name">view.new-folder</property>
<property name="accelerator">&lt;Primary&gt;&lt;shift&gt;N</property>
</object>
</child>
<child>
@ -369,7 +369,7 @@
<child>
<object class="GtkShortcutsShortcut">
<property name="title" translatable="yes" context="shortcut window">Paste</property>
<property name="action-name">view.paste_accel</property>
<property name="accelerator">&lt;Primary&gt;V</property>
</object>
</child>
<child>
@ -387,7 +387,7 @@
<child>
<object class="GtkShortcutsShortcut">
<property name="title" translatable="yes" context="shortcut window">Select Items Matching</property>
<property name="action-name">view.select-pattern</property>
<property name="accelerator">&lt;Primary&gt;S</property>
</object>
</child>
<child>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<path d="m 8 0 c -4.410156 0 -8 3.589844 -8 8 s 3.589844 8 8 8 s 8 -3.589844 8 -8 s -3.589844 -8 -8 -8 z m 0 2 c 3.332031 0 6 2.667969 6 6 s -2.667969 6 -6 6 s -6 -2.667969 -6 -6 s 2.667969 -6 6 -6 z m 0 1.875 c -0.621094 0 -1.125 0.503906 -1.125 1.125 s 0.503906 1.125 1.125 1.125 s 1.125 -0.503906 1.125 -1.125 s -0.503906 -1.125 -1.125 -1.125 z m -1.523438 3.125 c -0.265624 0.011719 -0.476562 0.230469 -0.476562 0.5 c 0 0.277344 0.222656 0.5 0.5 0.5 h 0.5 v 3 h -0.5 c -0.277344 0 -0.5 0.222656 -0.5 0.5 s 0.222656 0.5 0.5 0.5 h 3 c 0.277344 0 0.5 -0.222656 0.5 -0.5 s -0.222656 -0.5 -0.5 -0.5 h -0.5 v -4 h -2.5 c -0.007812 0 -0.015625 0 -0.023438 0 z m 0 0" fill="#222222"/>
</svg>

After

Width:  |  Height:  |  Size: 819 B

View File

@ -27,9 +27,9 @@
<file>ui/nautilus-operations-ui-manager-request-passphrase.ui</file>
<file>ui/nautilus-grid-cell.ui</file>
<file>ui/nautilus-name-cell.ui</file>
<file>ui/nautilus-network-address-bar.ui</file>
<file>ui/nautilus-network-cell.ui</file>
<file alias="gtk/ui/nautilusgtksidebarrow.ui">../gtk/nautilusgtksidebarrow.ui</file>
<file alias="gtk/ui/nautilusgtkplacesview.ui">../gtk/nautilusgtkplacesview.ui</file>
<file alias="gtk/ui/nautilusgtkplacesviewrow.ui">../gtk/nautilusgtkplacesviewrow.ui</file>
<file alias="icons/filmholes.png">../../icons/filmholes.png</file>
<file>style.css</file>
<file>style-hc.css</file>
@ -46,5 +46,6 @@
<file alias="remove-custom-icon-symbolic.svg" preprocess="xml-stripblanks">icons/remove-custom-icon-symbolic.svg</file>
<file alias="nautilus-folder-search-symbolic.svg" preprocess="xml-stripblanks">icons/nautilus-folder-search-symbolic.svg</file>
<file alias="network-computer-symbolic.svg" preprocess="xml-stripblanks">icons/network-computer-symbolic.svg</file>
<file alias="info-outline-symbolic.svg" preprocess="xml-stripblanks">icons/info-outline-symbolic.svg</file>
</gresource>
</gresources>

View File

@ -110,7 +110,7 @@
.floating-bar {
padding: 3px;
background-color: @view_bg_color;
box-shadow: inset 0 100px 0 0 alpha(currentColor, 0.05);
box-shadow: inset 0 100px 0 0 alpha(currentColor, 0.1);
border-radius: 8px;
}
@ -162,10 +162,12 @@
/* Setup padding on the list. Horizontal padding must be set on the columnview
* for it to calculate column widths correctly. */
.nautilus-network-view listview,
.nautilus-list-view columnview {
padding-left: 24px;
padding-right: 24px;
}
.nautilus-network-view listview,
.nautilus-list-view columnview > listview {
padding-top: 16px;
padding-bottom: 24px;
@ -187,6 +189,7 @@
margin-right: 24px;
}
.nautilus-network-view listview > row,
.nautilus-list-view columnview > listview > row {
border-radius: 6px;
}
@ -198,6 +201,8 @@
padding: 0px;
}
.nautilus-network-view #NautilusViewCell,
.nautilus-list-view #NautilusViewCell {
padding: 6px;
}
@ -234,6 +239,7 @@
}
/* Both views */
.nautilus-network-view:drop(active),
.nautilus-list-view:drop(active),
.nautilus-grid-view:drop(active) {
box-shadow: none;
@ -242,6 +248,7 @@
/* Remove the default background of the various view widgets
* since we already apply a background to the entire content
* pane with the .view class. Doing this will avoid overdraw. */
.nautilus-network-view listview,
.nautilus-grid-view gridview,
.nautilus-list-view columnview,
placesview list {
@ -270,6 +277,15 @@ placesview list {
filter: drop-shadow(0px 1px 1px rgba(0,0,0,0.3));
}
.nautilus-network-view {
-gtk-icon-style: symbolic;
}
.nautilus-network-view image.network-icon {
padding: 8px;
border-radius: 999999px;
background-color: alpha(currentColor, 0.1);
}
.view .cut {
opacity: 0.55;
}

View File

@ -31,12 +31,12 @@
</item>
<item>
<attribute name="label" translatable="yes">Season Number</attribute>
<attribute name="action">dialog.add-season-tag</attribute>
<attribute name="action">dialog.add-season-number-tag</attribute>
<attribute name="hidden-when">action-disabled</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Episode Number</attribute>
<attribute name="action">dialog.add-episode-tag</attribute>
<attribute name="action">dialog.add-episode-number-tag</attribute>
<attribute name="hidden-when">action-disabled</attribute>
</item>
<item>

View File

@ -5,6 +5,9 @@
<property name="title" translatable="yes">Change Permissions for Enclosed Files</property>
<property name="modal">True</property>
<property name="destroy-with-parent">True</property>
<property name="width-request">360</property>
<property name="height-request">294</property>
<property name="default-width">480</property>
<property name="content">
<object class="AdwToolbarView">
<child type="top">
@ -29,124 +32,56 @@
</object>
</child>
<property name="content">
<object class="GtkGrid" id="change_permissions_grid">
<property name="halign">center</property>
<property name="margin-top">18</property>
<property name="margin-bottom">18</property>
<property name="margin-start">18</property>
<property name="margin-end">18</property>
<property name="orientation">vertical</property>
<property name="row_spacing">6</property>
<property name="column_spacing">12</property>
<object class="AdwPreferencesPage">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Files</property>
<style>
<class name="dim-label"/>
</style>
<layout>
<property name="column">1</property>
<property name="row">0</property>
</layout>
<object class="AdwPreferencesGroup">
<property name="title" translatable="yes">Owner</property>
<child>
<object class="AdwComboRow" id="file_owner_combo_row">
<property name="title" translatable="yes">_Files</property>
<property name="use-underline">True</property>
</object>
</child>
<child>
<object class="AdwComboRow" id="folder_owner_combo_row">
<property name="title" translatable="yes">F_olders</property>
<property name="use-underline">True</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Folders</property>
<style>
<class name="dim-label"/>
</style>
<layout>
<property name="column">2</property>
<property name="row">0</property>
</layout>
<object class="AdwPreferencesGroup">
<property name="title" translatable="yes">Group</property>
<child>
<object class="AdwComboRow" id="file_group_combo_row">
<property name="title" translatable="yes">Fi_les</property>
<property name="use-underline">True</property>
</object>
</child>
<child>
<object class="AdwComboRow" id="folder_group_combo_row">
<property name="title" translatable="yes">Fol_ders</property>
<property name="use-underline">True</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Owner</property>
<property name="xalign">1</property>
<style>
<class name="dim-label"/>
</style>
<layout>
<property name="column">0</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkDropDown" id="file_owner_drop_down">
<layout>
<property name="column">1</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkDropDown" id="folder_owner_drop_down">
<layout>
<property name="column">2</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Group</property>
<property name="xalign">1</property>
<style>
<class name="dim-label"/>
</style>
<layout>
<property name="column">0</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkDropDown" id="file_group_drop_down">
<layout>
<property name="column">1</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkDropDown" id="folder_group_drop_down">
<layout>
<property name="column">2</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkDropDown" id="file_other_drop_down">
<layout>
<property name="column">1</property>
<property name="row">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkDropDown" id="folder_other_drop_down">
<layout>
<property name="column">2</property>
<property name="row">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Others</property>
<property name="xalign">1</property>
<style>
<class name="dim-label"/>
</style>
<layout>
<property name="column">0</property>
<property name="row">3</property>
</layout>
<object class="AdwPreferencesGroup">
<property name="title" translatable="yes">Others</property>
<child>
<object class="AdwComboRow" id="file_other_combo_row">
<property name="title" translatable="yes">Fil_es</property>
<property name="use-underline">True</property>
</object>
</child>
<child>
<object class="AdwComboRow" id="folder_other_combo_row">
<property name="title" translatable="yes">Folde_rs</property>
<property name="use-underline">True</property>
</object>
</child>
</object>
</child>
</object>

View File

@ -165,7 +165,7 @@
<attribute name="hidden-when">action-disabled</attribute>
</item>
</section>
<section>
<section id="move-copy-section">
<item>
<attribute name="label" translatable="yes">Cu_t</attribute>
<attribute name="action">view.cut</attribute>
@ -183,7 +183,7 @@
<attribute name="action">view.copy-to</attribute>
</item>
</section>
<section>
<section id="file-actions-section">
<item>
<attribute name="label" translatable="yes">Rena_me…</attribute>
<attribute name="action">view.rename</attribute>
@ -249,6 +249,17 @@
<attribute name="hidden-when">action-disabled</attribute>
</item>
</section>
<section id="network-view-section">
<item>
<attribute name="label" translatable="yes">_Copy Address</attribute>
<attribute name="action">view.copy-network-address</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Remove</attribute>
<attribute name="action">view.remove-recent-server</attribute>
<attribute name="hidden-when">action-disabled</attribute>
</item>
</section>
<section id="selection-extensions-section"/>
<section>
<item>

Some files were not shown because too many files have changed in this diff Show More