Bug Summary

File:ctk/ctkfilechoosernativeportal.c
Warning:line 352, column 41
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ctkfilechoosernativeportal.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/ctk -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I .. -D G_LOG_DOMAIN="Ctk" -D G_LOG_USE_STRUCTURED=1 -D CTK_VERSION="3.25.5" -D CTK_BINARY_VERSION="3.0.0" -D CTK_COMPILATION -D CTK_PRINT_BACKEND_ENABLE_UNSUPPORTED -D CTK_LIBDIR="/usr/lib" -D CTK_LOCALEDIR="/usr/share/locale" -D CTK_DATADIR="/usr/share" -D CTK_DATA_PREFIX="/usr" -D CTK_SYSCONFDIR="/usr/etc" -D CTK_HOST="x86_64-pc-linux-gnu" -D CTK_PRINT_BACKENDS="file,cups" -D X11_DATA_PREFIX="/usr" -D ISO_CODES_PREFIX="" -I .. -I ../ctk -I .. -I ../cdk -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -D G_ENABLE_DEBUG -D G_ENABLE_CONSISTENCY_CHECKS -D GLIB_MIN_REQUIRED_VERSION=GLIB_VERSION_2_66 -D GLIB_MAX_ALLOWED_VERSION=GLIB_VERSION_2_66 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/atk-1.0 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/gio-unix-2.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/pango-1.0 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/ctk -ferror-limit 19 -fvisibility=hidden -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-09-19-170505-43637-1 -x c ctkfilechoosernativeportal.c
1/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2/* CTK - The GIMP Toolkit
3 * ctkfilechoosernativeportal.c: Portal File selector dialog
4 * Copyright (C) 2015, Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "config.h"
21
22#include "ctkfilechoosernativeprivate.h"
23#include "ctknativedialogprivate.h"
24
25#include "ctkprivate.h"
26#include "ctkfilechooserdialog.h"
27#include "ctkfilechooserprivate.h"
28#include "ctkfilechooserwidget.h"
29#include "ctkfilechooserwidgetprivate.h"
30#include "ctkfilechooserutils.h"
31#include "ctkfilechooserembed.h"
32#include "ctkfilesystem.h"
33#include "ctksizerequest.h"
34#include "ctktypebuiltins.h"
35#include "ctkintl.h"
36#include "ctksettings.h"
37#include "ctktogglebutton.h"
38#include "ctkstylecontext.h"
39#include "ctkheaderbar.h"
40#include "ctklabel.h"
41#include "ctkmain.h"
42#include "ctkinvisible.h"
43#include "ctkfilechooserentry.h"
44#include "ctkfilefilterprivate.h"
45#include "ctkwindowprivate.h"
46
47typedef struct {
48 CtkFileChooserNative *self;
49
50 CtkWidget *grab_widget;
51
52 GDBusConnection *connection;
53 char *portal_handle;
54 guint portal_response_signal_id;
55 gboolean modal;
56
57 gboolean hidden;
58
59 const char *method_name;
60
61 CtkWindow *exported_window;
62} FilechooserPortalData;
63
64
65static void
66filechooser_portal_data_free (FilechooserPortalData *data)
67{
68 if (data->portal_response_signal_id != 0)
69 g_dbus_connection_signal_unsubscribe (data->connection,
70 data->portal_response_signal_id);
71
72 g_object_unref (data->connection);
73
74 if (data->grab_widget)
75 {
76 ctk_grab_remove (data->grab_widget);
77 ctk_widget_destroy (data->grab_widget);
78 }
79
80 g_clear_object (&data->self)do { _Static_assert (sizeof *((&data->self)) == sizeof
(gpointer), "Expression evaluates to false"); __typeof__ (((
&data->self))) _pp = ((&data->self)); __typeof__
(*((&data->self))) _ptr = *_pp; *_pp = ((void*)0); if
(_ptr) (g_object_unref) (_ptr); } while (0)
;
81
82 if (data->exported_window)
83 ctk_window_unexport_handle (data->exported_window);
84
85 g_free (data->portal_handle);
86
87 g_free (data);
88}
89
90static void
91response_cb (GDBusConnection *connection G_GNUC_UNUSED__attribute__ ((__unused__)),
92 const gchar *sender_name G_GNUC_UNUSED__attribute__ ((__unused__)),
93 const gchar *object_path G_GNUC_UNUSED__attribute__ ((__unused__)),
94 const gchar *interface_name G_GNUC_UNUSED__attribute__ ((__unused__)),
95 const gchar *signal_name G_GNUC_UNUSED__attribute__ ((__unused__)),
96 GVariant *parameters,
97 gpointer user_data)
98{
99 CtkFileChooserNative *self = user_data;
100 FilechooserPortalData *data = self->mode_data;
101 guint32 portal_response;
102 int ctk_response;
103 const char **uris;
104 int i;
105 GVariant *response_data;
106 GVariant *choices = NULL((void*)0);
107 GVariant *current_filter = NULL((void*)0);
108
109 g_variant_get (parameters, "(u@a{sv})", &portal_response, &response_data);
110 g_variant_lookup (response_data, "uris", "^a&s", &uris);
111
112 choices = g_variant_lookup_value (response_data, "choices", G_VARIANT_TYPE ("a(ss)")(g_variant_type_checked_ (("a(ss)"))));
113 if (choices)
114 {
115 for (i = 0; i < g_variant_n_children (choices); i++)
116 {
117 const char *id;
118 const char *selected;
119 g_variant_get_child (choices, i, "(&s&s)", &id, &selected);
120 ctk_file_chooser_set_choice (CTK_FILE_CHOOSER (self)((((CtkFileChooser*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((self)), ((ctk_file_chooser_get_type ()))))))
, id, selected);
121 }
122 g_variant_unref (choices);
123 }
124
125 current_filter = g_variant_lookup_value (response_data, "current_filter", G_VARIANT_TYPE ("(sa(us))")(g_variant_type_checked_ (("(sa(us))"))));
126 if (current_filter)
127 {
128 CtkFileFilter *filter = ctk_file_filter_new_from_gvariant (current_filter);
129 const gchar *current_filter_name = ctk_file_filter_get_name (filter);
130
131 /* Try to find the given filter in the list of filters.
132 * Since filters are compared by pointer value, using the passed
133 * filter would otherwise not match in a comparison, even if
134 * a filter in the list of filters has been selected.
135 * We'll use the heuristic that if two filters have the same name,
136 * they must be the same.
137 * If there is no match, just set the filter as it was retrieved.
138 */
139 CtkFileFilter *filter_to_select = filter;
140 GSList *filters = ctk_file_chooser_list_filters (CTK_FILE_CHOOSER (self)((((CtkFileChooser*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((self)), ((ctk_file_chooser_get_type ()))))))
);
141 GSList *l;
142
143 for (l = filters; l; l = l->next)
144 {
145 CtkFileFilter *f = l->data;
146 if (g_strcmp0 (ctk_file_filter_get_name (f), current_filter_name) == 0)
147 {
148 filter_to_select = f;
149 break;
150 }
151 }
152 g_slist_free (filters);
153 ctk_file_chooser_set_filter (CTK_FILE_CHOOSER (self)((((CtkFileChooser*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((self)), ((ctk_file_chooser_get_type ()))))))
, filter_to_select);
154 }
155
156 g_slist_free_full (self->custom_files, g_object_unref);
157 self->custom_files = NULL((void*)0);
158 for (i = 0; uris[i]; i++)
159 self->custom_files = g_slist_prepend (self->custom_files, g_file_new_for_uri (uris[i]));
160
161 switch (portal_response)
162 {
163 case 0:
164 ctk_response = CTK_RESPONSE_ACCEPT;
165 break;
166 case 1:
167 ctk_response = CTK_RESPONSE_CANCEL;
168 break;
169 case 2:
170 default:
171 ctk_response = CTK_RESPONSE_DELETE_EVENT;
172 break;
173 }
174
175 filechooser_portal_data_free (data);
176 self->mode_data = NULL((void*)0);
177
178 _ctk_native_dialog_emit_response (CTK_NATIVE_DIALOG (self), ctk_response);
179}
180
181static void
182send_close (FilechooserPortalData *data)
183{
184 GDBusMessage *message;
185 GError *error = NULL((void*)0);
186
187 message = g_dbus_message_new_method_call ("org.freedesktop.portal.Desktop",
188 "/org/freedesktop/portal/desktop",
189 "org.freedesktop.portal.FileChooser",
190 "Close");
191 g_dbus_message_set_body (message,
192 g_variant_new ("(o)", data->portal_handle));
193
194 if (!g_dbus_connection_send_message (data->connection,
195 message,
196 G_DBUS_SEND_MESSAGE_FLAGS_NONE,
197 NULL((void*)0), &error))
198 {
199 g_warning ("unable to send FileChooser Close message: %s", error->message);
200 g_error_free (error);
201 }
202
203 g_object_unref (message);
204}
205
206static void
207open_file_msg_cb (GObject *source_object G_GNUC_UNUSED__attribute__ ((__unused__)),
208 GAsyncResult *res,
209 gpointer user_data)
210{
211 FilechooserPortalData *data = user_data;
212 CtkFileChooserNative *self = data->self;
213 GDBusMessage *reply;
214 GError *error = NULL((void*)0);
215 char *handle = NULL((void*)0);
216
217 reply = g_dbus_connection_send_message_with_reply_finish (data->connection, res, &error);
218
219 if (reply && g_dbus_message_to_gerror (reply, &error))
220 g_clear_object (&reply)do { _Static_assert (sizeof *((&reply)) == sizeof (gpointer
), "Expression evaluates to false"); __typeof__ (((&reply
))) _pp = ((&reply)); __typeof__ (*((&reply))) _ptr =
*_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); }
while (0)
;
221
222 if (reply == NULL((void*)0))
223 {
224 if (!data->hidden)
225 _ctk_native_dialog_emit_response (CTK_NATIVE_DIALOG (self), CTK_RESPONSE_DELETE_EVENT);
226 g_warning ("Can't open portal file chooser: %s", error->message);
227 g_error_free (error);
228 filechooser_portal_data_free (data);
229 self->mode_data = NULL((void*)0);
230 return;
231 }
232
233 g_variant_get_child (g_dbus_message_get_body (reply), 0, "o", &handle);
234
235 if (data->hidden)
236 {
237 /* The dialog was hidden before we got the handle, close it now */
238 send_close (data);
239 filechooser_portal_data_free (data);
240 self->mode_data = NULL((void*)0);
241 }
242 else if (strcmp (handle, data->portal_handle) != 0)
243 {
244 g_free (data->portal_handle);
245 data->portal_handle = g_steal_pointer (&handle)((__typeof__ (*&handle)) (g_steal_pointer) (&handle));
246 g_dbus_connection_signal_unsubscribe (data->connection,
247 data->portal_response_signal_id);
248
249 data->portal_response_signal_id =
250 g_dbus_connection_signal_subscribe (data->connection,
251 "org.freedesktop.portal.Desktop",
252 "org.freedesktop.portal.Request",
253 "Response",
254 data->portal_handle,
255 NULL((void*)0),
256 G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
257 response_cb,
258 self, NULL((void*)0));
259 }
260
261 g_object_unref (reply);
262 g_free (handle);
263}
264
265static GVariant *
266get_filters (CtkFileChooser *self)
267{
268 GSList *list, *l;
269 GVariantBuilder builder;
270
271 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sa(us))")(g_variant_type_checked_ (("a(sa(us))"))));
272 list = ctk_file_chooser_list_filters (self);
273 for (l = list; l; l = l->next)
274 {
275 CtkFileFilter *filter = l->data;
276 g_variant_builder_add (&builder, "@(sa(us))", ctk_file_filter_to_gvariant (filter));
277 }
278 g_slist_free (list);
279
280 return g_variant_builder_end (&builder);
281}
282
283static GVariant *
284ctk_file_chooser_native_choice_to_variant (CtkFileChooserNativeChoice *choice)
285{
286 GVariantBuilder choices;
287 int i;
288
289 g_variant_builder_init (&choices, G_VARIANT_TYPE ("a(ss)")(g_variant_type_checked_ (("a(ss)"))));
290 if (choice->options)
291 {
292 for (i = 0; choice->options[i]; i++)
293 g_variant_builder_add (&choices, "(&s&s)", choice->options[i], choice->option_labels[i]);
294 }
295
296 return g_variant_new ("(&s&s@a(ss)&s)",
297 choice->id,
298 choice->label,
299 g_variant_builder_end (&choices),
300 choice->selected ? choice->selected : "");
301}
302
303static GVariant *
304serialize_choices (CtkFileChooserNative *self)
305{
306 GVariantBuilder builder;
307 GSList *l;
308
309 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ssa(ss)s)")(g_variant_type_checked_ (("a(ssa(ss)s)"))));
310 for (l = self->choices; l; l = l->next)
311 {
312 CtkFileChooserNativeChoice *choice = l->data;
313
314 g_variant_builder_add (&builder, "@(ssa(ss)s)",
315 ctk_file_chooser_native_choice_to_variant (choice));
316 }
317
318 return g_variant_builder_end (&builder);
319}
320
321static void
322show_portal_file_chooser (CtkFileChooserNative *self,
323 const char *parent_window_str)
324{
325 FilechooserPortalData *data = self->mode_data;
326 GDBusMessage *message;
327 GVariantBuilder opt_builder;
328 gboolean multiple;
329 gboolean directory;
330 const char *title;
331 char *token;
332
333 message = g_dbus_message_new_method_call ("org.freedesktop.portal.Desktop",
334 "/org/freedesktop/portal/desktop",
335 "org.freedesktop.portal.FileChooser",
336 data->method_name);
337
338 data->portal_handle = ctk_get_portal_request_path (data->connection, &token);
339 data->portal_response_signal_id =
340 g_dbus_connection_signal_subscribe (data->connection,
341 "org.freedesktop.portal.Desktop",
342 "org.freedesktop.portal.Request",
343 "Response",
344 data->portal_handle,
345 NULL((void*)0),
346 G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
347 response_cb,
348 self, NULL((void*)0));
349
350 multiple = ctk_file_chooser_get_select_multiple (CTK_FILE_CHOOSER (self)((((CtkFileChooser*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((self)), ((ctk_file_chooser_get_type ()))))))
);
351 directory = ctk_file_chooser_get_action (CTK_FILE_CHOOSER (self)((((CtkFileChooser*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((self)), ((ctk_file_chooser_get_type ()))))))
) == CTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
352 g_variant_builder_init (&opt_builder, G_VARIANT_TYPE_VARDICT((const GVariantType *) "a{sv}"));
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption
353
354 g_variant_builder_add (&opt_builder, "{sv}", "handle_token",
355 g_variant_new_string (token));
356 g_free (token);
357
358 g_variant_builder_add (&opt_builder, "{sv}", "multiple",
359 g_variant_new_boolean (multiple));
360 g_variant_builder_add (&opt_builder, "{sv}", "directory",
361 g_variant_new_boolean (directory));
362 if (self->accept_label)
363 g_variant_builder_add (&opt_builder, "{sv}", "accept_label",
364 g_variant_new_string (self->accept_label));
365 if (self->cancel_label)
366 g_variant_builder_add (&opt_builder, "{sv}", "cancel_label",
367 g_variant_new_string (self->cancel_label));
368 g_variant_builder_add (&opt_builder, "{sv}", "modal",
369 g_variant_new_boolean (data->modal));
370 g_variant_builder_add (&opt_builder, "{sv}", "filters", get_filters (CTK_FILE_CHOOSER (self)((((CtkFileChooser*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((self)), ((ctk_file_chooser_get_type ()))))))
));
371 if (self->current_filter)
372 g_variant_builder_add (&opt_builder, "{sv}", "current_filter",
373 ctk_file_filter_to_gvariant (self->current_filter));
374 if (self->current_name)
375 g_variant_builder_add (&opt_builder, "{sv}", "current_name",
376 g_variant_new_string (CTK_FILE_CHOOSER_NATIVE (self)->current_name));
377 if (self->current_folder)
378 {
379 gchar *path;
380
381 path = g_file_get_path (CTK_FILE_CHOOSER_NATIVE (self)->current_folder);
382 g_variant_builder_add (&opt_builder, "{sv}", "current_folder",
383 g_variant_new_bytestring (path));
384 g_free (path);
385 }
386 if (self->current_file)
387 {
388 gchar *path;
389
390 path = g_file_get_path (CTK_FILE_CHOOSER_NATIVE (self)->current_file);
391 g_variant_builder_add (&opt_builder, "{sv}", "current_file",
392 g_variant_new_bytestring (path));
393 g_free (path);
394 }
395
396 if (self->choices)
397 g_variant_builder_add (&opt_builder, "{sv}", "choices",
398 serialize_choices (CTK_FILE_CHOOSER_NATIVE (self)));
399
400 title = ctk_native_dialog_get_title (CTK_NATIVE_DIALOG (self));
401
402 g_dbus_message_set_body (message,
403 g_variant_new ("(ss@a{sv})",
404 parent_window_str ? parent_window_str : "",
405 title ? title : "",
406 g_variant_builder_end (&opt_builder)));
407
408 g_dbus_connection_send_message_with_reply (data->connection,
409 message,
410 G_DBUS_SEND_MESSAGE_FLAGS_NONE,
411 G_MAXINT2147483647,
412 NULL((void*)0),
413 NULL((void*)0),
414 open_file_msg_cb,
415 data);
416
417 g_object_unref (message);
418}
419
420static void
421window_handle_exported (CtkWindow *window,
422 const char *handle_str,
423 gpointer user_data)
424{
425 CtkFileChooserNative *self = user_data;
426 FilechooserPortalData *data = self->mode_data;
427
428 if (data->modal)
429 {
430 CdkScreen *screen = ctk_widget_get_screen (CTK_WIDGET (window)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((ctk_widget_get_type ()))))))
);
431
432 data->grab_widget = ctk_invisible_new_for_screen (screen);
433 ctk_grab_add (CTK_WIDGET (data->grab_widget)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data->grab_widget)), ((ctk_widget_get_type ()))))))
);
434 }
435
436 show_portal_file_chooser (self, handle_str);
437}
438
439gboolean
440ctk_file_chooser_native_portal_show (CtkFileChooserNative *self)
441{
442 FilechooserPortalData *data;
443 CtkWindow *transient_for;
444 GDBusConnection *connection;
445 CtkFileChooserAction action;
446 const char *method_name;
447
448 if (!ctk_should_use_portal ())
449 return FALSE(0);
450
451 connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL((void*)0), NULL((void*)0));
452 if (connection == NULL((void*)0))
453 return FALSE(0);
454
455 action = ctk_file_chooser_get_action (CTK_FILE_CHOOSER (self)((((CtkFileChooser*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((self)), ((ctk_file_chooser_get_type ()))))))
);
456
457 if (action == CTK_FILE_CHOOSER_ACTION_OPEN)
458 method_name = "OpenFile";
459 else if (action == CTK_FILE_CHOOSER_ACTION_SAVE)
460 method_name = "SaveFile";
461 else if (action == CTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
462 {
463 if (ctk_get_portal_interface_version (connection, "org.freedesktop.portal.FileChooser") < 3)
464 {
465 g_warning ("CTK_FILE_CHOOSER_ACTION_SELECT_FOLDER is not supported by CtkFileChooserNativePortal because portal is too old");
466 return FALSE(0);
467 }
468 method_name = "OpenFile";
469 }
470 else
471 {
472 g_warning ("CTK_FILE_CHOOSER_ACTION_CREATE_FOLDER is not supported by CtkFileChooserNativePortal");
473 return FALSE(0);
474 }
475
476 data = g_new0 (FilechooserPortalData, 1)((FilechooserPortalData *) g_malloc0_n ((1), sizeof (FilechooserPortalData
)))
;
477 data->self = g_object_ref (self)((__typeof__ (self)) (g_object_ref) (self));
478 data->connection = connection;
479
480 data->method_name = method_name;
481
482 if (ctk_native_dialog_get_modal (CTK_NATIVE_DIALOG (self)))
483 data->modal = TRUE(!(0));
484
485 self->mode_data = data;
486
487 transient_for = ctk_native_dialog_get_transient_for (CTK_NATIVE_DIALOG (self));
488 if (transient_for != NULL((void*)0) && ctk_widget_is_visible (CTK_WIDGET (transient_for)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((transient_for)), ((ctk_widget_get_type ()))))))
))
489 {
490 if (!ctk_window_export_handle (transient_for,
491 window_handle_exported,
492 self))
493 {
494 g_warning ("Failed to export handle, could not set transient for");
495 show_portal_file_chooser (self, NULL((void*)0));
496 }
497 else
498 {
499 data->exported_window = transient_for;
500 }
501 }
502 else
503 {
504 show_portal_file_chooser (self, NULL((void*)0));
505 }
506
507 return TRUE(!(0));
508}
509
510void
511ctk_file_chooser_native_portal_hide (CtkFileChooserNative *self)
512{
513 FilechooserPortalData *data = self->mode_data;
514
515 /* This is always set while dialog visible */
516 g_assert (data != NULL)do { if (data != ((void*)0)) ; else g_assertion_message_expr (
"Ctk", "ctkfilechoosernativeportal.c", 516, ((const char*) (__func__
)), "data != NULL"); } while (0)
;
517
518 data->hidden = TRUE(!(0));
519
520 if (data->portal_handle)
521 {
522 send_close (data);
523 filechooser_portal_data_free (data);
524 }
525
526 self->mode_data = NULL((void*)0);
527}