thunar-usagebars/thunar/thunar-dialogs.c
4aiman df58603323 thunar 4.20.7 upstream
Tree of tag thunar-4.20.7 (commit df0e054) from https://gitlab.xfce.org/xfce/thunar.
Upstream history is not included here to keep the repository small.
2026-11-04 01:40:30 +03:00

1341 lines
49 KiB
C

/* vi:set et ai sw=2 sts=2 ts=2: */
/*-
* Copyright (c) 2005-2011 Benedikt Meurer <benny@xfce.org>
* Copyright (c) 2009-2011 Jannis Pohlmann <jannis@xfce.org>
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#ifdef HAVE_STDARG_H
#include <stdarg.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include "thunar/thunar-dialogs.h"
#include "thunar/thunar-gtk-extensions.h"
#include "thunar/thunar-icon-factory.h"
#include "thunar/thunar-io-jobs.h"
#include "thunar/thunar-job.h"
#include "thunar/thunar-pango-extensions.h"
#include "thunar/thunar-preferences.h"
#include "thunar/thunar-private.h"
#include "thunar/thunar-util.h"
#include <libxfce4ui/libxfce4ui.h>
static void
thunar_dialogs_select_filename (GtkWidget *entry);
static void
thunar_dialogs_shrink_height (GtkWidget *dialog);
static void
thunar_dialogs_shrink_height (GtkWidget *dialog)
{
gint width;
gint height;
/* Shrinks the dialog to it's minimum height */
gtk_window_get_size (GTK_WINDOW (dialog), &width, &height);
gtk_window_resize (GTK_WINDOW (dialog), width, 1);
}
/**
* thunar_dialogs_show_create:
* @parent : a #GdkScreen, a #GtkWidget or %NULL.
* @content_type : the content type of the file or folder to create.
* @filename : the suggested filename or %NULL.
* @title : the dialog title.
*
* Displays a Thunar create dialog with the specified
* parameters that asks the user to enter a name for a new file or
* folder.
*
* The caller is responsible to free the returned filename using
* g_free() when no longer needed.
*
* Return value: the filename entered by the user or %NULL if the user
* cancelled the dialog.
**/
gchar *
thunar_dialogs_show_create (gpointer parent,
const gchar *content_type,
const gchar *filename,
const gchar *title)
{
GtkWidget *dialog;
GtkWindow *window = NULL;
GdkScreen *screen;
GError *error = NULL;
gchar *name = NULL;
GtkWidget *label;
GtkWidget *grid;
GtkWidget *image;
XfceFilenameInput *filename_input;
GIcon *icon = NULL;
gint row = 0;
_thunar_return_val_if_fail (parent == NULL || GDK_IS_SCREEN (parent) || GTK_IS_WIDGET (parent), NULL);
/* parse the parent window and screen */
screen = thunar_util_parse_parent (parent, &window);
/* create a new dialog window */
dialog = gtk_dialog_new_with_buttons (title,
window,
GTK_DIALOG_MODAL
| GTK_DIALOG_DESTROY_WITH_PARENT,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("C_reate"), GTK_RESPONSE_OK,
NULL);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
gtk_window_set_default_size (GTK_WINDOW (dialog), 300, -1);
grid = gtk_grid_new ();
gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
gtk_grid_set_row_spacing (GTK_GRID (grid), 3);
gtk_container_set_border_width (GTK_CONTAINER (grid), 6);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), grid, TRUE, TRUE, 0);
gtk_widget_show (grid);
/* try to load the icon */
if (G_LIKELY (content_type != NULL))
icon = g_content_type_get_icon (content_type);
/* setup the image */
if (G_LIKELY (icon != NULL))
{
image = g_object_new (GTK_TYPE_IMAGE, "xpad", 6, "ypad", 6, NULL);
gtk_image_set_from_gicon (GTK_IMAGE (image), icon, GTK_ICON_SIZE_DIALOG);
gtk_grid_attach (GTK_GRID (grid), image, 0, row, 1, 2);
gtk_widget_set_valign (GTK_WIDGET (image), GTK_ALIGN_START);
g_object_unref (icon);
gtk_widget_show (image);
}
label = g_object_new (GTK_TYPE_LABEL, "label", _("Enter the name:"), "xalign", 0.0f, "hexpand", TRUE, NULL);
gtk_grid_attach (GTK_GRID (grid), label, 1, row, 1, 1);
gtk_widget_show (label);
/* set up the widget for entering the filename */
filename_input = g_object_new (XFCE_TYPE_FILENAME_INPUT, "original-filename", filename, NULL);
gtk_widget_set_hexpand (GTK_WIDGET (filename_input), TRUE);
gtk_widget_set_valign (GTK_WIDGET (filename_input), GTK_ALIGN_CENTER);
/* connect to signals so that the sensitivity of the Create button is updated according to whether there
* is a valid file name entered */
g_signal_connect_swapped (filename_input, "text-invalid", G_CALLBACK (xfce_filename_input_desensitise_widget),
gtk_dialog_get_widget_for_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK));
g_signal_connect_swapped (filename_input, "text-valid", G_CALLBACK (xfce_filename_input_sensitise_widget),
gtk_dialog_get_widget_for_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK));
/* next row */
row++;
gtk_grid_attach (GTK_GRID (grid), GTK_WIDGET (filename_input), 1, row, 1, 1);
thunar_gtk_label_set_a11y_relation (GTK_LABEL (label),
GTK_WIDGET (xfce_filename_input_get_entry (filename_input)));
gtk_widget_show_all (GTK_WIDGET (filename_input));
/* ensure that the sensitivity of the Create button is set correctly */
xfce_filename_input_check (filename_input);
/* select the filename without the extension */
thunar_dialogs_select_filename (GTK_WIDGET (xfce_filename_input_get_entry (filename_input)));
if (screen != NULL)
gtk_window_set_screen (GTK_WINDOW (dialog), screen);
if (window != NULL)
gtk_window_set_transient_for (GTK_WINDOW (dialog), window);
/* shrink the dialog again, after some filename error was fixed */
g_signal_connect_swapped (filename_input, "text-valid", G_CALLBACK (thunar_dialogs_shrink_height), dialog);
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK)
{
/* determine the chosen filename */
filename = xfce_filename_input_get_text (filename_input);
/* convert the UTF-8 filename to the local file system encoding */
name = g_filename_from_utf8 (filename, -1, NULL, NULL, &error);
if (G_UNLIKELY (name == NULL))
{
/* display an error message */
thunar_dialogs_show_error (dialog, error, _("Cannot convert filename \"%s\" to the local encoding"), filename);
/* release the error */
g_error_free (error);
}
}
/* destroy the dialog */
gtk_widget_destroy (dialog);
return name;
}
/**
* thunar_dialogs_show_rename_file:
* @parent : a #GtkWidget on which the error dialog should be shown, or a #GdkScreen
* if no #GtkWidget is known. May also be %NULL, in which case the default
* #GdkScreen will be used.
* @file : the #ThunarFile we're going to rename.
*
* Displays the Thunar rename dialog for a single file rename.
*
* Return value: The #ThunarJob responsible for renaming the file or
* %NULL if there was no renaming required.
**/
ThunarJob *
thunar_dialogs_show_rename_file (gpointer parent,
ThunarFile *file,
ThunarOperationLogMode log_mode)
{
ThunarIconFactory *icon_factory;
GtkIconTheme *icon_theme;
gint scale_factor;
gchar *filename;
const gchar *text;
ThunarJob *job = NULL;
GtkWidget *dialog;
GtkWidget *label;
GtkWidget *image;
GtkWidget *grid;
XfceFilenameInput *filename_input;
GtkEntry *filename_input_entry;
GtkWindow *window = NULL;
GdkScreen *screen;
GdkPixbuf *icon;
cairo_surface_t *surface;
gchar *title;
gint response;
gint dialog_width;
gint parent_width = 500;
gint row = 0;
_thunar_return_val_if_fail (parent == NULL || GDK_IS_SCREEN (parent) || GTK_IS_WINDOW (parent), FALSE);
_thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE);
/* parse the parent window and screen */
screen = thunar_util_parse_parent (parent, &window);
/* Get the filename of the file. We create our own copy of the string because the file
* can be modified by another process while the rename is in progress (issue #1639). */
filename = g_strdup (thunar_file_get_basename (file));
/* create a new dialog window */
title = g_strdup_printf (_("Rename \"%s\""), filename);
dialog = gtk_dialog_new_with_buttons (title,
window,
GTK_DIALOG_MODAL
| GTK_DIALOG_DESTROY_WITH_PARENT,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Rename"), GTK_RESPONSE_OK,
NULL);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
g_free (title);
/* move the dialog to the appropriate screen */
if (G_UNLIKELY (window == NULL && screen != NULL))
gtk_window_set_screen (GTK_WINDOW (dialog), screen);
if (window != NULL)
scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (window));
else
scale_factor = gtk_widget_get_scale_factor (dialog);
grid = gtk_grid_new ();
gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
gtk_grid_set_row_spacing (GTK_GRID (grid), 3);
gtk_container_set_border_width (GTK_CONTAINER (grid), 6);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), grid, TRUE, TRUE, 0);
gtk_widget_show (grid);
icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (dialog));
icon_factory = thunar_icon_factory_get_for_icon_theme (icon_theme);
icon = thunar_icon_factory_load_file_icon (icon_factory, file, THUNAR_FILE_ICON_STATE_DEFAULT, 48, scale_factor, FALSE, NULL);
surface = gdk_cairo_surface_create_from_pixbuf (icon, scale_factor, NULL);
g_object_unref (G_OBJECT (icon_factory));
image = gtk_image_new_from_surface (surface);
gtk_widget_set_margin_start (GTK_WIDGET (image), 6);
gtk_widget_set_margin_end (GTK_WIDGET (image), 6);
gtk_widget_set_margin_top (GTK_WIDGET (image), 6);
gtk_widget_set_margin_bottom (GTK_WIDGET (image), 6);
gtk_widget_set_valign (GTK_WIDGET (image), GTK_ALIGN_START);
gtk_grid_attach (GTK_GRID (grid), image, 0, row, 1, 2);
g_object_unref (G_OBJECT (icon));
cairo_surface_destroy (surface);
gtk_widget_show (image);
label = gtk_label_new (_("Enter the new name:"));
gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
gtk_widget_set_hexpand (label, TRUE);
gtk_grid_attach (GTK_GRID (grid), label, 1, row, 1, 1);
gtk_widget_show (label);
/* set up the widget for entering the filename */
filename_input = g_object_new (XFCE_TYPE_FILENAME_INPUT, "original-filename", filename, NULL);
filename_input_entry = xfce_filename_input_get_entry (filename_input);
gtk_widget_set_hexpand (GTK_WIDGET (filename_input), TRUE);
gtk_widget_set_valign (GTK_WIDGET (filename_input), GTK_ALIGN_CENTER);
/* connect to signals so that the sensitivity of the Create button is updated according to whether there
* is a valid file name entered */
g_signal_connect_swapped (filename_input, "text-invalid", G_CALLBACK (xfce_filename_input_desensitise_widget),
gtk_dialog_get_widget_for_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK));
g_signal_connect_swapped (filename_input, "text-valid", G_CALLBACK (xfce_filename_input_sensitise_widget),
gtk_dialog_get_widget_for_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK));
/* next row */
row++;
gtk_grid_attach (GTK_GRID (grid), GTK_WIDGET (filename_input), 1, row, 1, 1);
thunar_gtk_label_set_a11y_relation (GTK_LABEL (label), GTK_WIDGET (filename_input_entry));
gtk_widget_show_all (GTK_WIDGET (filename_input));
/* ensure that the sensitivity of the Create button is set correctly */
xfce_filename_input_check (filename_input);
/* If it is no directory, select the filename without the extension */
if (thunar_file_is_directory (file))
gtk_editable_select_region (GTK_EDITABLE (filename_input_entry), 0, -1);
else
thunar_dialogs_select_filename (GTK_WIDGET (filename_input_entry));
/* change the width of the input entry to be about the right size for N chars (filename length) */
gtk_entry_set_max_width_chars (filename_input_entry, g_utf8_strlen (filename, -1));
/* dialog window width */
gtk_window_get_size (GTK_WINDOW (dialog), &dialog_width, NULL);
/* parent window width */
if (G_LIKELY (window != NULL))
{
/* keep below 90% of the parent window width */
gtk_window_get_size (window, &parent_width, NULL);
parent_width *= 0.90f;
}
/* resize the dialog to make long names fit as much as possible */
gtk_window_set_default_size (GTK_WINDOW (dialog), CLAMP (dialog_width, 300, parent_width), -1);
/* automatically close the dialog when the file is destroyed */
g_signal_connect_swapped (G_OBJECT (file), "destroy",
G_CALLBACK (gtk_widget_destroy), dialog);
/* shrink the dialog again, after some filename error was fixed */
g_signal_connect_swapped (filename_input, "text-valid", G_CALLBACK (thunar_dialogs_shrink_height), dialog);
/* run the dialog */
response = gtk_dialog_run (GTK_DIALOG (dialog));
if (G_LIKELY (response == GTK_RESPONSE_OK))
{
/* hide the dialog */
gtk_widget_hide (dialog);
/* determine the new filename */
text = xfce_filename_input_get_text (filename_input);
/* check if we have a new name here */
if (G_LIKELY (g_strcmp0 (filename, text)) != 0)
{
/* try to rename the file */
job = thunar_io_jobs_rename_file (file, text, log_mode);
exo_job_launch (EXO_JOB (job));
}
}
/* cleanup */
if (G_LIKELY (response != GTK_RESPONSE_NONE))
{
/* unregister handler */
g_signal_handlers_disconnect_by_func (G_OBJECT (file), gtk_widget_destroy, dialog);
gtk_widget_destroy (dialog);
}
g_free (filename);
return job;
}
/**
* thunar_dialogs_show_about:
* @parent : the parent #GtkWindow or %NULL.
* @title : the software title.
* @format : the printf()-style format for the main text in the about dialog.
* @... : argument list for the @format.
*
* Displays the Thunar about dialog with @format as main text.
**/
void
thunar_dialogs_show_about (GtkWindow *parent,
const gchar *title,
const gchar *format,
...)
{
static const gchar *artists[] = {
"Young Hahn <youngjin.hahn@gmail.com>",
NULL,
};
static const gchar *authors[] = {
"Benedikt Meurer <benny@xfce.org>",
"Jannis Pohlmann <jannis@xfce.org>",
"Nick Schermer <nick@xfce.org>",
NULL,
};
static const gchar *documenters[] = {
"Benedikt Meurer <benny@xfce.org>",
"Jannis Pohlmann <jannis@xfce.org>",
"Nick Schermer <nick@xfce.org>",
NULL,
};
va_list args;
gchar *comments;
_thunar_return_if_fail (parent == NULL || GTK_IS_WINDOW (parent));
/* determine the comments */
va_start (args, format);
comments = g_strdup_vprintf (format, args);
va_end (args);
/* open the about dialog */
gtk_show_about_dialog (parent,
"artists", artists,
"authors", authors,
"comments", comments,
"copyright", "Copyright \302\251 2004-2011 Benedikt Meurer\n"
"Copyright \302\251 2009-2011 Jannis Pohlmann\n"
"Copyright \302\251 2009-2012 Nick Schermer\n"
"Copyright \302\251 2017-2022 Andre Miranda\n"
"Copyright \302\251 2017-2024 Alexander Schwinn",
"destroy-with-parent", TRUE,
"documenters", documenters,
"license", XFCE_LICENSE_GPL,
"logo-icon-name", "org.xfce.thunar",
"program-name", title,
"translator-credits", _("translator-credits"),
"version", PACKAGE_VERSION,
"website", "https://docs.xfce.org/xfce/thunar/start",
NULL);
/* cleanup */
g_free (comments);
}
/**
* thunar_dialogs_show_error:
* @parent : a #GtkWidget on which the error dialog should be shown, or a #GdkScreen
* if no #GtkWidget is known. May also be %NULL, in which case the default
* #GdkScreen will be used.
* @error : a #GError, which gives a more precise description of the problem or %NULL.
* @format : the printf()-style format for the primary problem description.
* @... : argument list for the @format.
*
* Displays an error dialog on @widget using the @format as primary message and optionally
* displaying @error as secondary error text.
*
* If @widget is not %NULL and @widget is part of a #GtkWindow, the function makes sure
* that the toplevel window is visible prior to displaying the error dialog.
**/
void
thunar_dialogs_show_error (gpointer parent,
const GError *error,
const gchar *format,
...)
{
GtkWidget *dialog;
GtkWindow *window = NULL;
GdkScreen *screen;
va_list args;
gchar *primary_text;
GList *children;
GList *lp;
_thunar_return_if_fail (parent == NULL || GDK_IS_SCREEN (parent) || GTK_IS_WIDGET (parent));
/* do not display error dialog for already handled errors */
if (error && error->code == G_IO_ERROR_FAILED_HANDLED)
return;
/* parse the parent pointer */
screen = thunar_util_parse_parent (parent, &window);
/* determine the primary error text */
va_start (args, format);
primary_text = g_strdup_vprintf (format, args);
va_end (args);
/* allocate the error dialog */
dialog = gtk_message_dialog_new (window,
GTK_DIALOG_DESTROY_WITH_PARENT
| GTK_DIALOG_MODAL,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
"%s.", primary_text);
gtk_window_set_title (GTK_WINDOW (dialog), _("Error"));
/* move the dialog to the appropriate screen */
if (G_UNLIKELY (window == NULL && screen != NULL))
gtk_window_set_screen (GTK_WINDOW (dialog), screen);
/* set secondary text if an error is provided */
if (G_LIKELY (error != NULL))
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s.", error->message);
children = gtk_container_get_children (
GTK_CONTAINER (gtk_message_dialog_get_message_area (GTK_MESSAGE_DIALOG (dialog))));
/* enable wrap for labels */
for (lp = children; lp != NULL; lp = lp->next)
if (GTK_IS_LABEL (lp->data))
gtk_label_set_line_wrap_mode (GTK_LABEL (lp->data), PANGO_WRAP_WORD_CHAR);
/* display the dialog */
gtk_dialog_run (GTK_DIALOG (dialog));
/* cleanup */
gtk_widget_destroy (dialog);
g_free (primary_text);
g_list_free (children);
}
/**
* thunar_dialogs_show_job_ask:
* @parent : the parent #GtkWindow or %NULL.
* @question : the question text.
* @choices : possible responses.
*
* Utility function to display a question dialog for the ThunarJob::ask
* signal.
*
* Return value: the #ThunarJobResponse.
**/
ThunarJobResponse
thunar_dialogs_show_job_ask (GtkWindow *parent,
const gchar *question,
ThunarJobResponse choices)
{
const gchar *separator;
const gchar *mnemonic;
GtkWidget *message;
GtkWidget *button;
GString *secondary = g_string_sized_new (256);
GString *primary = g_string_sized_new (256);
gint response;
gint n;
gboolean has_cancel = FALSE;
_thunar_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), THUNAR_JOB_RESPONSE_CANCEL);
_thunar_return_val_if_fail (g_utf8_validate (question, -1, NULL), THUNAR_JOB_RESPONSE_CANCEL);
/* try to separate the question into primary and secondary parts */
separator = strstr (question, ": ");
if (G_LIKELY (separator != NULL))
{
/* primary is everything before the colon, plus a dot */
g_string_append_len (primary, question, separator - question);
g_string_append_c (primary, '.');
/* secondary is everything after the colon (skipping whitespace) */
do
++separator;
while (g_ascii_isspace (*separator));
g_string_append (secondary, separator);
}
else
{
/* otherwise separate based on the \n\n */
separator = strstr (question, "\n\n");
if (G_LIKELY (separator != NULL))
{
/* primary is everything before the newlines */
g_string_append_len (primary, question, separator - question);
/* secondary is everything after the newlines (skipping whitespace) */
while (g_ascii_isspace (*separator))
++separator;
g_string_append (secondary, separator);
}
else
{
/* everything is primary */
g_string_append (primary, question);
}
}
/* allocate the question message dialog */
message = gtk_message_dialog_new (parent,
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_QUESTION,
GTK_BUTTONS_NONE,
"%s", primary->str);
gtk_window_set_title (GTK_WINDOW (message), _("Attention"));
if (G_LIKELY (*secondary->str != '\0'))
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (message), "%s", secondary->str);
/* add the buttons based on the possible choices */
for (n = THUNAR_JOB_RESPONSE_MAX_INT; n >= 0; --n)
{
/* check if the response is set */
response = choices & (1 << n);
if (response == 0)
continue;
switch (response)
{
case THUNAR_JOB_RESPONSE_YES:
mnemonic = _("_Yes");
break;
case THUNAR_JOB_RESPONSE_YES_ALL:
mnemonic = _("Yes to _all");
break;
case THUNAR_JOB_RESPONSE_REPLACE:
mnemonic = _("_Replace");
break;
case THUNAR_JOB_RESPONSE_REPLACE_ALL:
mnemonic = _("Replace _All");
break;
case THUNAR_JOB_RESPONSE_SKIP:
mnemonic = _("_Skip");
break;
case THUNAR_JOB_RESPONSE_SKIP_ALL:
mnemonic = _("S_kip All");
break;
case THUNAR_JOB_RESPONSE_RENAME:
mnemonic = _("Re_name");
break;
case THUNAR_JOB_RESPONSE_RENAME_ALL:
mnemonic = _("Rena_me All");
break;
case THUNAR_JOB_RESPONSE_NO:
mnemonic = _("_No");
break;
case THUNAR_JOB_RESPONSE_NO_ALL:
mnemonic = _("N_o to all");
break;
case THUNAR_JOB_RESPONSE_RETRY:
mnemonic = _("_Retry");
break;
case THUNAR_JOB_RESPONSE_FORCE:
mnemonic = _("Copy _Anyway");
break;
case THUNAR_JOB_RESPONSE_CANCEL:
/* cancel is always the last option */
has_cancel = TRUE;
continue;
default:
g_assert_not_reached ();
break;
}
button = gtk_button_new_with_mnemonic (mnemonic);
gtk_widget_set_can_default (button, TRUE);
gtk_dialog_add_action_widget (GTK_DIALOG (message), button, response);
gtk_widget_show (button);
gtk_dialog_set_default_response (GTK_DIALOG (message), response);
}
if (has_cancel)
{
button = gtk_button_new_with_mnemonic (_("_Cancel"));
gtk_widget_set_can_default (button, TRUE);
gtk_dialog_add_action_widget (GTK_DIALOG (message), button, GTK_RESPONSE_CANCEL);
gtk_widget_show (button);
gtk_dialog_set_default_response (GTK_DIALOG (message), GTK_RESPONSE_CANCEL);
}
/* run the question dialog */
response = gtk_dialog_run (GTK_DIALOG (message));
gtk_widget_destroy (message);
/* transform the result as required */
if (G_UNLIKELY (response <= 0))
response = THUNAR_JOB_RESPONSE_CANCEL;
/* cleanup */
g_string_free (secondary, TRUE);
g_string_free (primary, TRUE);
return response;
}
static void
thunar_dialog_image_redraw (GtkWidget *image,
ThunarThumbnailSize size,
ThunarFile *file)
{
ThunarIconFactory *icon_factory;
GtkIconTheme *icon_theme;
gint scale_factor;
GdkPixbuf *icon;
cairo_surface_t *surface;
/* determine the icon factory to use */
icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (image));
icon_factory = thunar_icon_factory_get_for_icon_theme (icon_theme);
scale_factor = gtk_widget_get_scale_factor (image);
icon = thunar_icon_factory_load_file_icon (icon_factory, file, THUNAR_FILE_ICON_STATE_DEFAULT, 48, scale_factor, FALSE, NULL);
surface = gdk_cairo_surface_create_from_pixbuf (icon, scale_factor, NULL);
gtk_image_set_from_surface (GTK_IMAGE (image), surface);
/* cleanup */
g_object_unref (G_OBJECT (icon));
cairo_surface_destroy (surface);
g_object_unref (G_OBJECT (icon_factory));
}
/**
* thunar_dialogs_show_job_ask_replace:
* @parent : the parent #GtkWindow or %NULL.
* @src_file : the #ThunarFile of the source file.
* @dst_file : the #ThunarFile of the destination file that
* may be replaced with the source file.
*
* Asks the user whether to replace the destination file with the
* source file identified by @src_file.
*
* Return value: the selected #ThunarJobResponse.
**/
ThunarJobResponse
thunar_dialogs_show_job_ask_replace (GtkWindow *parent,
ThunarFile *src_file,
ThunarFile *dst_file,
gboolean multiple_files)
{
ThunarIconFactory *icon_factory;
ThunarPreferences *preferences;
ThunarDateStyle date_style;
ThunarFile *parent_file;
GtkIconTheme *icon_theme;
GtkWidget *dialog;
GtkWidget *grid;
GtkWidget *image, *src_image, *dst_image;
GtkWidget *label;
GtkWidget *content_area;
GtkWidget *action_area;
GtkWidget *check_button;
GdkPixbuf *icon;
cairo_surface_t *surface;
const gchar *parent_string = "";
gchar *date_custom_style;
gchar *date_string;
gchar *size_string;
gchar *text;
gint response;
gboolean file_size_binary;
gint row = 0;
gint scale_factor;
gint width;
_thunar_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), THUNAR_JOB_RESPONSE_CANCEL);
_thunar_return_val_if_fail (THUNAR_IS_FILE (src_file), THUNAR_JOB_RESPONSE_CANCEL);
_thunar_return_val_if_fail (THUNAR_IS_FILE (dst_file), THUNAR_JOB_RESPONSE_CANCEL);
/* determine the style used to format dates */
preferences = thunar_preferences_get ();
g_object_get (G_OBJECT (preferences), "misc-date-style", &date_style, NULL);
g_object_get (G_OBJECT (preferences), "misc-date-custom-style", &date_custom_style, NULL);
g_object_get (G_OBJECT (preferences), "misc-file-size-binary", &file_size_binary, NULL);
g_object_unref (G_OBJECT (preferences));
/* setup the confirmation dialog */
dialog = gtk_dialog_new_with_buttons (_("Confirm to replace files"),
parent,
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
_("_Cancel"), THUNAR_JOB_RESPONSE_CANCEL,
_("_Skip"), THUNAR_JOB_RESPONSE_SKIP,
_("Re_name"), THUNAR_JOB_RESPONSE_RENAME,
_("_Replace"), THUNAR_JOB_RESPONSE_REPLACE,
NULL);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), THUNAR_JOB_RESPONSE_REPLACE);
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
action_area = gtk_dialog_get_action_area (GTK_DIALOG (dialog));
G_GNUC_END_IGNORE_DEPRECATIONS
gtk_button_box_set_layout (GTK_BUTTON_BOX (action_area), GTK_BUTTONBOX_SPREAD);
gtk_widget_set_margin_bottom (GTK_WIDGET (action_area), 3);
if (parent != NULL)
scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (parent));
else
scale_factor = gtk_widget_get_scale_factor (dialog);
/* determine the icon factory to use */
icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (dialog));
icon_factory = thunar_icon_factory_get_for_icon_theme (icon_theme);
grid = gtk_grid_new ();
gtk_grid_set_column_spacing (GTK_GRID (grid), 5);
gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
gtk_container_set_border_width (GTK_CONTAINER (grid), 10);
gtk_box_pack_start (GTK_BOX (content_area), grid, TRUE, FALSE, 0);
gtk_widget_show (grid);
image = gtk_image_new_from_icon_name ("stock_folder-copy", GTK_ICON_SIZE_BUTTON);
gtk_widget_set_halign (image, GTK_ALIGN_CENTER);
gtk_widget_set_valign (image, GTK_ALIGN_START);
gtk_widget_set_margin_start (GTK_WIDGET (image), 6);
gtk_widget_set_margin_end (GTK_WIDGET (image), 6);
gtk_widget_set_margin_top (GTK_WIDGET (image), 6);
gtk_widget_set_margin_bottom (GTK_WIDGET (image), 6);
gtk_widget_set_vexpand (image, TRUE);
gtk_grid_attach (GTK_GRID (grid), image, 0, row, 1, 1);
gtk_widget_show (image);
if (thunar_file_is_symlink (dst_file))
{
text = g_strdup_printf (_("This folder already contains a symbolic link \"%s\"."),
thunar_file_get_display_name (dst_file));
}
else if (thunar_file_is_directory (dst_file))
{
text = g_strdup_printf (_("This folder already contains a folder \"%s\"."),
thunar_file_get_display_name (dst_file));
}
else
{
if (g_strcmp0 (thunar_file_get_display_name (dst_file), thunar_file_get_basename (dst_file)) != 0)
text = g_strdup_printf (_("This folder already contains a file \"%s\" (%s)."),
thunar_file_get_display_name (dst_file),
thunar_file_get_basename (dst_file));
else
text = g_strdup_printf (_("This folder already contains a file \"%s\"."),
thunar_file_get_display_name (dst_file));
}
label = gtk_label_new (text);
gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
gtk_label_set_attributes (GTK_LABEL (label), thunar_pango_attr_list_big_bold ());
gtk_label_set_selectable (GTK_LABEL (label), TRUE);
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
gtk_label_set_line_wrap_mode (GTK_LABEL (label), PANGO_WRAP_CHAR);
thunar_gtk_label_disable_hyphens (GTK_LABEL (label));
gtk_widget_set_hexpand (label, TRUE);
gtk_grid_attach (GTK_GRID (grid), label, 1, row, 2, 1);
gtk_widget_show (label);
g_free (text);
parent_file = thunar_file_get_parent (dst_file, NULL);
if (parent_file != NULL)
parent_string = thunar_file_get_basename (parent_file);
if (thunar_file_is_symlink (dst_file))
/* TRANSLATORS: First part of replace dialog sentence */
text = g_strdup_printf (_("Replace the link in \"%s\""), parent_string);
else if (thunar_file_is_directory (dst_file))
/* TRANSLATORS: First part of replace dialog sentence */
text = g_strdup_printf (_("Replace the existing folder in \"%s\""), parent_string);
else
/* TRANSLATORS: First part of replace dialog sentence */
text = g_strdup_printf (_("Replace the existing file in \"%s\""), parent_string);
if (parent_file != NULL)
g_object_unref (parent_file);
/* next row */
row++;
label = gtk_label_new (text);
gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_MIDDLE);
gtk_widget_set_hexpand (label, TRUE);
gtk_grid_attach (GTK_GRID (grid), label, 1, row, 2, 1);
gtk_widget_show (label);
g_free (text);
/* next row */
row++;
icon = thunar_icon_factory_load_file_icon (icon_factory, dst_file, THUNAR_FILE_ICON_STATE_DEFAULT, 48, scale_factor, FALSE, NULL);
surface = gdk_cairo_surface_create_from_pixbuf (icon, scale_factor, NULL);
dst_image = gtk_image_new_from_surface (surface);
gtk_widget_set_margin_start (GTK_WIDGET (dst_image), 6);
gtk_widget_set_margin_end (GTK_WIDGET (dst_image), 6);
gtk_widget_set_margin_top (GTK_WIDGET (dst_image), 6);
gtk_widget_set_margin_bottom (GTK_WIDGET (dst_image), 6);
gtk_grid_attach (GTK_GRID (grid), dst_image, 1, row, 1, 1);
g_object_unref (G_OBJECT (icon));
cairo_surface_destroy (surface);
gtk_widget_show (dst_image);
g_signal_connect_swapped (G_OBJECT (dst_file), "thumbnail-updated", G_CALLBACK (thunar_dialog_image_redraw), dst_image);
thunar_file_request_thumbnail (dst_file, thunar_icon_size_to_thumbnail_size (48 * scale_factor));
size_string = thunar_file_get_size_string_long (dst_file, file_size_binary);
date_string = thunar_file_get_date_string (dst_file, THUNAR_FILE_DATE_MODIFIED, date_style, date_custom_style);
text = g_strdup_printf ("%s %s\n%s %s", _("Size:"), size_string, _("Modified:"), date_string);
label = gtk_label_new (text);
gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
gtk_widget_set_hexpand (label, TRUE);
gtk_grid_attach (GTK_GRID (grid), label, 2, row, 1, 1);
gtk_widget_show (label);
g_free (size_string);
g_free (date_string);
g_free (text);
if (thunar_file_is_symlink (src_file))
/* TRANSLATORS: Second part of replace dialog sentence */
text = g_strdup_printf (_("with the following link?"));
else if (thunar_file_is_directory (src_file))
/* TRANSLATORS: Second part of replace dialog sentence */
text = g_strdup_printf (_("with the following folder?"));
else
/* TRANSLATORS: Second part of replace dialog sentence */
text = g_strdup_printf (_("with the following file?"));
/* next row */
row++;
label = gtk_label_new (text);
gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
gtk_widget_set_hexpand (label, TRUE);
gtk_grid_attach (GTK_GRID (grid), label, 1, row, 2, 1);
gtk_widget_show (label);
g_free (text);
/* next row */
row++;
icon = thunar_icon_factory_load_file_icon (icon_factory, src_file, THUNAR_FILE_ICON_STATE_DEFAULT, 48, scale_factor, FALSE, NULL);
surface = gdk_cairo_surface_create_from_pixbuf (icon, scale_factor, NULL);
src_image = gtk_image_new_from_surface (surface);
gtk_widget_set_margin_start (GTK_WIDGET (src_image), 6);
gtk_widget_set_margin_end (GTK_WIDGET (src_image), 6);
gtk_widget_set_margin_top (GTK_WIDGET (src_image), 6);
gtk_widget_set_margin_bottom (GTK_WIDGET (src_image), 6);
gtk_grid_attach (GTK_GRID (grid), src_image, 1, row, 1, 1);
g_object_unref (G_OBJECT (icon));
cairo_surface_destroy (surface);
gtk_widget_show (src_image);
g_signal_connect_swapped (G_OBJECT (src_file), "thumbnail-updated", G_CALLBACK (thunar_dialog_image_redraw), src_image);
thunar_file_request_thumbnail (src_file, thunar_icon_size_to_thumbnail_size (48 * scale_factor));
size_string = thunar_file_get_size_string_long (src_file, file_size_binary);
date_string = thunar_file_get_date_string (src_file, THUNAR_FILE_DATE_MODIFIED, date_style, date_custom_style);
text = g_strdup_printf ("%s %s\n%s %s", _("Size:"), size_string, _("Modified:"), date_string);
label = gtk_label_new (text);
gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
gtk_widget_set_hexpand (label, TRUE);
gtk_grid_attach (GTK_GRID (grid), label, 2, row, 1, 1);
gtk_widget_show (label);
g_free (size_string);
g_free (date_string);
g_free (text);
g_free (date_custom_style);
if (multiple_files)
{
/* next row */
row++;
check_button = gtk_check_button_new_with_mnemonic (_("_Apply the action to all files and folders"));
gtk_widget_set_margin_top (check_button, 6);
gtk_grid_attach (GTK_GRID (grid), check_button, 0, row, 3, 1);
gtk_widget_show (check_button);
}
/* prevent long filenames from pushing the dialog width over a certain value */
gtk_window_get_size (GTK_WINDOW (dialog), &width, NULL);
if (width > 600)
gtk_window_resize (GTK_WINDOW (dialog), 600, 1);
/* run the dialog */
response = gtk_dialog_run (GTK_DIALOG (dialog));
/* translate GTK responses */
if (G_UNLIKELY (response < 0))
response = THUNAR_JOB_RESPONSE_CANCEL;
if (multiple_files)
{
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check_button)))
{
if (response == THUNAR_JOB_RESPONSE_SKIP)
response = THUNAR_JOB_RESPONSE_SKIP_ALL;
else if (response == THUNAR_JOB_RESPONSE_REPLACE)
response = THUNAR_JOB_RESPONSE_REPLACE_ALL;
else if (response == THUNAR_JOB_RESPONSE_RENAME)
response = THUNAR_JOB_RESPONSE_RENAME_ALL;
}
}
g_signal_handlers_disconnect_by_data (src_file, src_image);
g_signal_handlers_disconnect_by_data (dst_file, dst_image);
gtk_widget_destroy (dialog);
/* cleanup */
g_object_unref (G_OBJECT (icon_factory));
return response;
}
gboolean
thunar_dialogs_show_insecure_program (gpointer parent,
const gchar *primary,
ThunarFile *file,
const gchar *command)
{
GdkScreen *screen;
GtkWindow *window = NULL;
gint response;
GtkWidget *dialog;
GString *secondary;
GError *err = NULL;
gchar *file_name;
gchar *executable;
_thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE);
_thunar_return_val_if_fail (g_utf8_validate (command, -1, NULL), FALSE);
/* parse the parent window and screen */
screen = thunar_util_parse_parent (parent, &window);
/* create the secondary text */
if (g_strcmp0 (thunar_file_get_display_name (file), thunar_file_get_basename (file)) != 0)
file_name = g_strdup_printf ("\"%s\" (%s)", thunar_file_get_display_name (file), thunar_file_get_basename (file));
else
file_name = g_strdup_printf ("\"%s\"", thunar_file_get_display_name (file));
if (g_file_info_get_attribute_boolean (thunar_file_get_info (file), G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE) == FALSE)
/* TRANSLATORS: This string will be inserted in the following sentence in the second appearance of %s:
* "The desktop file %s is in an insecure location and not marked as secure%s." */
executable = g_strdup (_("/executable"));
else
executable = g_strdup ("");
secondary = g_string_new (NULL);
g_string_printf (secondary,
_("The desktop file %s is in an insecure location and not marked as secure%s. "
"If you do not trust this program, click Cancel.\n\n"),
file_name,
executable);
g_free (file_name);
g_free (executable);
if (g_uri_is_valid (command, G_URI_FLAGS_NONE, NULL))
g_string_append_printf (secondary, G_KEY_FILE_DESKTOP_KEY_URL "=%s", command);
else
g_string_append_printf (secondary, G_KEY_FILE_DESKTOP_KEY_EXEC "=%s", command);
/* allocate and display the error message dialog */
dialog = gtk_message_dialog_new (window,
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_WARNING,
GTK_BUTTONS_NONE,
"%s", primary);
gtk_window_set_title (GTK_WINDOW (dialog), _("Attention"));
gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Launch Anyway"), GTK_RESPONSE_OK);
if (thunar_file_is_chmodable (file))
gtk_dialog_add_button (GTK_DIALOG (dialog), _("Mark As _Secure And Launch"), GTK_RESPONSE_APPLY);
gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Cancel"), GTK_RESPONSE_CANCEL);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
if (screen != NULL && window == NULL)
gtk_window_set_screen (GTK_WINDOW (dialog), screen);
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", secondary->str);
g_string_free (secondary, TRUE);
response = gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog);
/* check if we can set the file executable */
if (response == GTK_RESPONSE_APPLY)
{
if (thunar_g_file_set_executable_flags (thunar_file_get_file (file), &err))
{
thunar_dialogs_show_error (parent, err, ("Unable to mark launcher executable"));
g_clear_error (&err);
}
if (thunar_g_vfs_metadata_is_supported ())
if (!xfce_g_file_set_trusted (thunar_file_get_file (file), TRUE, NULL, &err))
{
thunar_dialogs_show_error (parent, err, ("Unable to mark launcher as trusted"));
g_clear_error (&err);
}
/* just launch */
response = GTK_RESPONSE_OK;
}
return (response == GTK_RESPONSE_OK);
}
static void
thunar_dialogs_select_filename (GtkWidget *entry)
{
const gchar *filename;
const gchar *ext;
glong offset;
GtkEntryBuffer *buffer;
buffer = gtk_entry_get_buffer (GTK_ENTRY (entry));
filename = gtk_entry_buffer_get_text (buffer);
/* check if the filename contains an extension */
ext = thunar_util_str_get_extension (filename);
if (G_UNLIKELY (ext == NULL))
return;
/* grab focus to the entry first, else the selection will be altered later */
gtk_widget_grab_focus (entry);
/* determine the UTF-8 char offset */
offset = g_utf8_pointer_to_offset (filename, ext);
/* select the text prior to the dot */
if (G_LIKELY (offset > 0))
gtk_editable_select_region (GTK_EDITABLE (entry), 0, offset);
}
/**
* thunar_dialog_confirm_close_split_pane_tabs:
* @parent : (allow-none): transient parent of the dialog, or %NULL.
*
* Runs a dialog to ask the user whether they want to close a split pane with multiple tabs
*
* Return value: #GTK_RESPONSE_CANCEL if cancelled, #GTK_RESPONSE_CLOSE if the user
* wants to close all tabs of the other split pane
*/
gint
thunar_dialog_confirm_close_split_pane_tabs (GtkWindow *parent)
{
GtkWidget *dialog, *checkbutton, *vbox;
const gchar *primary_text, *warning_icon;
gchar *secondary_text;
ThunarPreferences *preferences;
gint response;
g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), GTK_RESPONSE_NONE);
primary_text = _("Close split pane with multiple tabs?");
secondary_text = g_strdup (_("The other split pane has multiple open tabs. Closing it "
"will close all these tabs."));
warning_icon = "dialog-warning";
dialog = xfce_message_dialog_new (parent,
_("Warning"),
warning_icon,
primary_text,
secondary_text,
XFCE_BUTTON_TYPE_MIXED, NULL, _("_Cancel"), GTK_RESPONSE_CANCEL,
XFCE_BUTTON_TYPE_MIXED, NULL, _("Close Pane"), GTK_RESPONSE_CLOSE,
NULL);
checkbutton = gtk_check_button_new_with_mnemonic (_("Do _not ask me again"));
vbox = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
gtk_box_pack_end (GTK_BOX (vbox), checkbutton, FALSE, FALSE, 5);
g_object_set (G_OBJECT (checkbutton), "halign", GTK_ALIGN_END, "margin-start", 6, "margin-end", 6, NULL);
gtk_widget_set_hexpand (checkbutton, TRUE);
gtk_widget_show_all (dialog);
response = gtk_dialog_run (GTK_DIALOG (dialog));
/* if the user requested not to be asked again, store this preference */
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbutton)))
{
preferences = thunar_preferences_get ();
g_object_set (G_OBJECT (preferences), "misc-confirm-close-multiple-tabs", FALSE, NULL);
g_object_unref (G_OBJECT (preferences));
}
gtk_widget_destroy (dialog);
g_free (secondary_text);
return response;
}
/**
* thunar_dialog_ask_execute:
* @file : a #ThunarFile pointer
* @parent : a #GtkWidget on which the error dialog should be shown, or a #GdkScreen
* if no #GtkWidget is known. May also be %NULL, in which case the default
* #GdkScreen will be used.
* @allow_open : if set, the "Open" button is visible.
* @single_file : if set, the file name is visible in dialog message. Otherwise there is
* generic message about selected files.
*
* Shows a dialog where the user is asked if and how he wants to run the executable script.
*
* Return value: One of #ThunarFileAskExecuteResponse enum value.
**/
gint
thunar_dialog_ask_execute (const ThunarFile *file,
gpointer parent,
gboolean allow_open,
gboolean single_file)
{
GtkWidget *dialog;
GtkWindow *window = NULL;
GdkScreen *screen;
gint response;
gchar *dialog_text;
GtkWidget *button;
_thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE);
_thunar_return_val_if_fail (parent == NULL || GDK_IS_SCREEN (parent) || GTK_IS_WIDGET (parent), THUNAR_FILE_ASK_EXECUTE_RESPONSE_OPEN);
/* parse the parent window and screen */
screen = thunar_util_parse_parent (parent, &window);
if (single_file)
{
gchar *basename = g_file_get_basename (thunar_file_get_file (file));
dialog_text = g_strdup_printf (_("The file \"%s\" seems to be executable. What do you want to do with it?"), basename);
g_free (basename);
}
else
{
dialog_text = g_strdup (_("The selected files seem to be executable. What do you want to do with them?"));
}
dialog = gtk_message_dialog_new (window,
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_QUESTION,
GTK_BUTTONS_NONE,
"%s", dialog_text);
gtk_window_set_title (GTK_WINDOW (dialog), _("Open Shell Script"));
g_free (dialog_text);
button = gtk_button_new_with_mnemonic (_("Run In _Terminal"));
gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, THUNAR_FILE_ASK_EXECUTE_RESPONSE_RUN_IN_TERMINAL);
gtk_widget_show (button);
button = gtk_button_new_with_mnemonic (_("_Execute"));
gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, THUNAR_FILE_ASK_EXECUTE_RESPONSE_RUN);
gtk_widget_show (button);
if (allow_open)
{
button = gtk_button_new_with_mnemonic (_("_Open"));
gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, THUNAR_FILE_ASK_EXECUTE_RESPONSE_OPEN);
gtk_widget_show (button);
gtk_widget_set_can_default (button, TRUE);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), THUNAR_FILE_ASK_EXECUTE_RESPONSE_OPEN);
}
else
{
gtk_widget_set_can_default (button, TRUE);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), THUNAR_FILE_ASK_EXECUTE_RESPONSE_RUN);
}
if (G_UNLIKELY (window == NULL && screen != NULL))
gtk_window_set_screen (GTK_WINDOW (dialog), screen);
response = gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog);
return response;
}
/**
* thunar_dialog_show_launcher_props:
* @launcher : a #ThunarFile.
* @parent : a #GdkScreen, a #GtkWidget or %NULL. If %NULL is passed then the default screen will be used.
*
* Calls the exo-desktop-item-edit command to edit the properties of a .desktop file.
* A dialog with the current properties will appear.
**/
void
thunar_dialog_show_launcher_props (ThunarFile *launcher,
gpointer parent)
{
const gchar *display_name;
gchar *cmd = NULL,
*uri = NULL;
GError *error = NULL;
GdkScreen *screen;
_thunar_return_if_fail (launcher == NULL || THUNAR_IS_FILE (launcher));
_thunar_return_if_fail (parent == NULL || GDK_IS_SCREEN (parent) || GTK_IS_WIDGET (parent));
screen = thunar_util_parse_parent (parent, NULL);
uri = thunar_file_dup_uri (launcher);
display_name = gdk_display_get_name (gdk_screen_get_display (screen));
cmd = g_strdup_printf ("exo-desktop-item-edit \"--display=%s\" \"%s\"", display_name, uri);
if (xfce_spawn_command_line (NULL, cmd, FALSE, FALSE, FALSE, &error) == FALSE)
thunar_dialogs_show_error (screen, error, _("Failed to edit launcher via command \"%s\""), cmd);
g_free (cmd);
g_free (uri);
g_clear_error (&error);
}