10000 Change File Dialogs to use GtkFileChooserNative for XDG Portal support by LDprg · Pull Request #6049 · xournalpp/xournalpp · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Change File Dialogs to use GtkFileChooserNative for XDG Portal support #6049

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 28 commits into
base: master
Choose a base branch
from

Conversation

LDprg
Copy link
@LDprg LDprg commented Nov 10, 2024

This PR changes the file dialogs to use GtkFileChooserNative for XDG Portal support. This means that using GTK_USE_PORTAL=1 xournalpp would use the DE's File Picker instead of the GTK one. Which is very convenient especially on KDE (since the dolphin file picker is not as similar as the GTK and gnome one is).

As far as my testing can tell everything should work except the export to PDF dialog. It strangely behaves when closing the dialog instead of exporting the file (loading cursor and UI wouldn't respond).

This should close #5460 when merged.

@bhennion
Copy link
Collaborator
bhennion commented Nov 10, 2024

Sorry I wasn't quite clear. The point is not to necessarily use the existing PopupWindowWrapper (so you can create another wrapper for NativeDialogs if needed), but just to get inspiration from it.

The main objective is to not use gtk_native_dialog_run() so that the same code will run (more or less) on GTK4.
To do so you should use gtk_native_dialog_show() (which returns immediately) and the signal gtk_native_dialog::response which is emitted once a file have been selected or the native dialog has been closed. See GTK4's doc: https://docs.gtk.org/gtk4/class.FileChooserNative.html.
Once we are done with the GtkNativeDialog, we should probably call gtk_native_dialog_destroy() (I'm not sure about that -- we need to check: maybe dropping the GObject's ref-count to 0 is enough).

Look at the example of all the xoj::OpenDlg::showOpenBlaBla()

auto popup = xoj::popup::PopupWindowWrapper<FileDlg>("Some title", someCallbackFunction);
...
popup.show(parent);

Unpacking what it does, it moves the callback function (and its context: it is typically a lambda so it may carry data attached) to a FileDlg instance, then shows a dialog and returns.
The main loop then continues running. When dialog receives a response, its response signal is emitted and the g_signal_connect() from FileDlg's constructor feeds that response to someCallbackFunction and then destroys the GtkDialog and the FileDlg instance (via gtk_window_close() which in turn calls the callback from PopupWindowWrapper's contructor).

This is a bit overly complicated for GtkDialogs (but necessary for general GtkWindows). In any case, it looks like that for GtkNativeDialog, one layer can be dropped (because there is no equivalent to gtk_window_close()). You can probably have a single NativeWrapper playing the roles of both FileDlg and PopupWindowWrapper: it owns the callback (as a member variable of type std::function<void(...)>) and will delete every piece of data once we are done.

@LDprg
Copy link
Author
LDprg commented Nov 11, 2024

@bhennion Ok, now I got it. I created an own wrapper which manages the destruction of the dialog (currently only for saving). The goal is to create one wrapper for saving and opening files, where you specify which one to use at creation of the wrapper.

It's a bit awkward the way I deconstruct the wrapper, since it needs to be a pointer. Later, the response event deletes it, which is needed since I have no other event indicating the dialog has been closed.

Also

gtk_native_dialog_set_transient_for(getNativeDialog(), parent);
gtk_native_dialog_set_modal(getNativeDialog(), true);

doesn't seem to work correctly on my system (which isn't that huge of a deal).

Everything else seems to work on my system.

bhennion
Copy link
Collaborator
@bhennion bhennion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are a couple of comments/questions.

We should also be careful that the GTK documentation lists a handful of features that are not working on various platforms.
Are we relying on those features? If so, this needs to be remedied (I think we are using MIME type for filters for instance - we need to avoid them on Windows)

@LDprg
Copy link
Author
LDprg commented Nov 11, 2024

As far as I can tell we might rely on GtkFileFilters with custom filters (will double check this).

@LDprg
Copy link
Author
LDprg commented Nov 12, 2024

Ok did try using it on Windows, which works. However, it does not use the native Windows dialog, which seems related to GtkFileFilters, should be quite easy to fix (will look into that).

@LDprg
Copy link
Author
LDprg commented Nov 15, 2024

@bhennion I would replace the open file dialog now too. Would you prefer two separate wrapper (one for open and one for save) or a combined one (with just a wrapper)?

I personally think a combined wrapper would be better.

Edit: I implemented it now using a wrapper and I have done some cleanups. I now look into native dialogs for Windows.

@LDprg
Copy link
Author
LDprg commented Nov 15, 2024

Native Windows implementation mostly works now.
I got a problem where I could find the cause. I seem like the code getting the date for the default names doesn't work on Windows strangely (time does work, so the name is missing some parts). Another thing is that the default name for the PageTemplateDialog doesn't work at all.

I couldn't find the reason for PageTemplateDialog and I couldn't find the code to determine the date (since the error must be here).

Copy link
Collaborator
@bhennion bhennion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is a first pass of comments on the code (I haven't tried it out)

Co-authored-by: Benjamin Hennion <17818041+bhennion@users.noreply.github.com>
Copy link
Collaborator
@bhennion bhennion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested it. It doesn't quite work: it is really easy to override a file without being warned about it (on KDE, both with and without GTK_USE_PORTAL).
The point is, if you type as a name foobar when you save, the saved file will be foobar.xopp.
Without GTK_USE_PORTAL, you will not be warned at all even if foobar.xopp exists (but foobar does not).
With GTK_USE_PORTAL=1, you will only be warned about it if the box "Automatically choose file name and extension" is ticked (not quite sure what the original english string is).

@LDprg
Copy link
Author
LDprg commented Nov 17, 2024

@bhennion I moved the ExportTypes to a separate file. I also changed the logic for replacing files, but now you get double replace dialogs on KDE (which I guess is better than none) if files are the same. There seems no way to completely disable it in gtk3.

So we have to choose between:

  1. missing override dialogs
  2. conditional depending on the platform
  3. duplicate override dialogs

@LDprg LDprg requested a review from bhennion November 17, 2024 10:35
Copy link
Collaborator
@bhennion bhennion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code looks nice and the MimeType type cleans things up well
On question: have you checks if there were other occurrences of mimetypes in the code? If so, you can use the new class and the constexpr defs there as well -- the constexpr definitions make typos almost impossible.

As for the choice in behaviour: losing data because the user has not been warned must be avoided at any cost.

I don't believe in "DE/platform"-based code. Behaviour may vary from one version (e.g. of Dolphin) to the other. Moreover, having XDG_CURRENT_DESKTOP set to KDE does not imply the portal configuration is that of KDE. The user may be using some third party file manager and have configured their portal to use that.

The requirements for the File Chooser portal do not mention file overriding at all, so we cannot assume anything, nor can we report to that or that implementation "you don't check if a file already exists" (even for Linux targets).
MacOS and Windows raise another set of questions.

I'm leaning towards a double check on Dolphin's portal, but we have to check the behaviour in other common situations before deciding. That includes:

  • KDE with and without GTK_USE_PORTAL
  • Gnome with and without GTK_USE_PORTAL
  • MacOS (is there something to configure there?)
  • Windows (is there something to configure there?)

As a note for other maintainers: moving to native dialogs is a step we will have to take in the long run: past GTK4.10, we should use GtkFileDialog which is a rewrite of GtkFileChooserNative.

LDprg and others added 7 commits November 18, 2024 07:47
Co-authored-by: Benjamin Hennion <17818041+bhennion@users.noreply.github.com>
Co-authored-by: Benjamin Hennion <17818041+bhennion@users.noreply.github.com>
Co-authored-by: Benjamin Hennion <17818041+bhennion@users.noreply.github.com>
Co-authored-by: Benjamin Hennion <17818041+bhennion@users.noreply.github.com>
@LDprg LDprg requested a review from bhennion November 18, 2024 08:37
@LDprg
Copy link
Author
LDprg commented Nov 18, 2024

I also double-checked there shouldn't be any Mime type usages anymore.

@LDprg LDprg requested a review from bhennion November 19, 2024 09:56
Copy link
Collaborator
@bhennion bhennion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code looks good to me. This needs to be tested on MacOS, Windows, Gnome and KDE before being merged though.
@rolandlo would you have time to test this on MacOS/Windows?

@rolandlo
Copy link
Member

The code looks good to me. This needs to be tested on MacOS, Windows, Gnome and KDE before being merged though. @rolandlo would you have time to test this on MacOS/Windows?

What dialogs need to be checked?

  • Save
  • Export
  • Plugin API fileDialogSave
  • Open
  • Annotate PDF

Did I miss one?

@bhennion
Copy link
Collaborator

Template page format file (.xopt) in Journal->Configure Page Template
What matters most is checking that on every platform, overriding a file is only possible after the user said yes to some "Are you sure?" dialog.

@bhennion
Copy link
Collaborator

And for export, I guess it'd be best to check both the "Export as..." and the "Export as PDF" cases.

@bhennion
Copy link
Collaborator

I found a case that is not working (on KDE, without GTK_USE_PORTAL): Click on Export as PDF and pick a name foobar. The file will be exported to foobar.pdf. Reiterated the same steps (with foobar as name, still): the file foobar.pdf will be overidden without asking for confirmation.
(Note that if the name in the file dialog is foobar.pdf, then you get the confirmation dialog)

@bhennion
Copy link
Collaborator
bhennion commented Nov 19, 2024

Another issue: if you click on Save As and choose a file name that already exists (foobar or foobar.xopp yield the same result), you are (rightfully) asked to confirm your choice. If you click on "Select another filename", the file dialog now shows the working directory (so my build directory). It should be in the same directory as before or in the last saved directory recorded in the settings.

[The same issue appears in any situation where you are asked to confirm]

@bhennion
Copy link
Collaborator

I also got a SegFault: Click on Export As... and select a file name without extension (the selected filter is PDF by default). Click on export and then Ok in the next dialog: SegFault.

In the terminal, I get the warning

(com.github.xournalpp.xournalpp:139183): xopp-WARNING **: 21:23:03.903: Unknown extension

and the crashlog
errorlog.20241119-212306.log

@bhennion
Copy link
Collaborator
bhennion commented Nov 19, 2024

About the SegFault: the problem is probably related to https://discourse.gnome.org/t/gtk4-c-gtkfilefilter-gtkfilechooser-vs-gtkfiledialog/23528
This thread is about GTK4, but I think the point still holds in GTK3: for a native dialog, there is no way to reliably get the selected filter.

This probably means we'll have to rethink how we do things in CustomExportJob::showDialogAndRun()

@rolandlo
Copy link
Member
rolandlo commented Dec 9, 2024

About the SegFault: the problem is probably related to https://discourse.gnome.org/t/gtk4-c-gtkfilefilter-gtkfilechooser-vs-gtkfiledialog/23528 This thread is about GTK4, but I think the point still holds in GTK3: for a native dialog, there is no way to reliably get the selected filter.

This probably means we'll have to rethink how we do things in CustomExportJob::showDialogAndRun()

What about implementing it like in the Libadwaita redesign mockup:
Bildschirmfoto vom 2024-12-09 15-08-40

Of course it can be done without Libadwaita.

When the chosen format is png:
Bildschirmfoto vom 2024-12-09 15-13-34

@bhennion
Copy link
Collaborator
bhennion commented Dec 9, 2024

Yes, it seems to be what the GTK people are suggesting here for instance. It seems reasonable to me.

@bhennion
Copy link
Collaborator
bhennion commented Dec 9, 2024

We may also consider never changing the filename ourselves (to add an extension) and trust the "native" dialog to check and ask if a file already exists.
We'd have to check if this is a reasonable assumption:

  • do common native dialogs append and extension corresponding to the selected filter if necessary?
  • do they indeed check and ask when overwriting a file? (if GtkFileChooser:do-overwrite-confirmation is set to true, of course)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Request to change GtkFileChooser to GtkFileChooserNative
3 participants
0