Move a bunch of common code in the file chooser dialog loops into a

routine to run a file chooser dialog.

On Windows, add to that code to resolve shell links ("shortcuts"),
adopted from the Sylpheed mail reader.  (That code requires a pile of
OLE stuff, so link with the OLE library.)

Make it a bit easier to configure ui/gtk/capture_file_dlg.c to use GTK+
dialogs on Windows, but continue to default to using the Win32 dialogs,
at least for now.

svn path=/trunk/; revision=43439
This commit is contained in:
Guy Harris 2012-06-21 22:21:02 +00:00
parent a0148735c1
commit 204ea39c5d
4 changed files with 180 additions and 123 deletions

View File

@ -73,7 +73,7 @@ dumpcap_OBJECTS = $(dumpcap_SOURCES:.c=.obj)
randpkt_OBJECTS = $(randpkt_SOURCES:.c=.obj)
wireshark_LIBS= wiretap\wiretap-$(WTAP_VERSION).lib \
wsock32.lib user32.lib shell32.lib comctl32.lib \
wsock32.lib user32.lib shell32.lib comctl32.lib ole32.lib \
$(GTHREAD_LIBS) \
$(HHC_LIBS) \
wsutil\libwsutil.lib \

View File

@ -47,7 +47,6 @@
#include <wsutil/file_util.h>
#include "ui/alert_box.h"
#include "ui/last_open_dir.h"
#include "ui/recent.h"
#include "ui/simple_dialog.h"
#include "ui/ui_util.h"
@ -70,7 +69,11 @@
#include "ui/gtk/range_utils.h"
#include "ui/gtk/filter_autocomplete.h"
#if _WIN32
#ifdef _WIN32
#define USE_WIN32_FILE_DIALOGS
#endif
#ifdef USE_WIN32_FILE_DIALOGS
#include <gdk/gdkwin32.h>
#include <windows.h>
#include "ui/win32/file_dlg_win32.h"
@ -422,9 +425,9 @@ preview_new(void)
static void
file_open_cmd(GtkWidget *w)
{
#if _WIN32
#ifdef USE_WIN32_FILE_DIALOGS
win32_open_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)));
#else /* _WIN32 */
#else /* USE_WIN32_FILE_DIALOGS */
GtkWidget *file_open_w;
GtkWidget *main_hb, *main_vb, *filter_hbox, *filter_bt, *filter_te,
*m_resolv_cb, *n_resolv_cb, *t_resolv_cb, *prev;
@ -541,26 +544,12 @@ file_open_cmd(GtkWidget *w)
* Loop until the user either selects a file or gives up.
*/
for (;;) {
if (gtk_dialog_run(GTK_DIALOG(file_open_w)) != GTK_RESPONSE_ACCEPT) {
/* They clicked "Cancel" or closed the dialog or.... */
window_destroy(file_open_w);
cf_name = file_selection_run(file_open_w);
if (cf_name == NULL) {
/* User cancelled or closed the dialog. */
return;
}
cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_open_w));
/* Perhaps the user specified a directory instead of a file.
Check whether they did. */
if (test_for_directory(cf_name) == EISDIR) {
/* It's a directory - set the file selection box to display that
directory, and go back and re-run it; don't try to open the
directory as a capture file. */
set_last_open_dir(cf_name);
g_free(cf_name);
file_selection_set_current_folder(file_open_w, get_last_open_dir());
continue;
}
/* Get the specified read filter and try to compile it. */
rfilter = gtk_entry_get_text(GTK_ENTRY(filter_te));
if (!dfilter_compile(rfilter, &rfcode)) {
@ -633,7 +622,7 @@ file_open_cmd(GtkWidget *w)
g_free(cf_name);
return;
}
#endif /* _WIN32 */
#endif /* USE_WIN32_FILE_DIALOGS */
}
void
@ -648,11 +637,11 @@ file_open_cmd_cb(GtkWidget *widget, gpointer data _U_) {
static void
file_merge_cmd(GtkWidget *w)
{
#if _WIN32
#ifdef USE_WIN32_FILE_DIALOGS
win32_merge_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)));
new_packet_list_freeze();
new_packet_list_thaw();
#else /* _WIN32 */
#else /* USE_WIN32_FILE_DIALOGS */
GtkWidget *file_merge_w;
GtkWidget *main_hb, *main_vb, *ft_hb, *ft_lb, *ft_combo_box, *filter_hbox,
*filter_bt, *filter_te, *prepend_rb, *chrono_rb,
@ -794,26 +783,12 @@ file_merge_cmd(GtkWidget *w)
* Loop until the user either selects a file or gives up.
*/
for (;;) {
if (gtk_dialog_run(GTK_DIALOG(file_merge_w)) != GTK_RESPONSE_ACCEPT) {
/* They clicked "Cancel" or closed the dialog or.... */
window_destroy(file_merge_w);
cf_name = file_selection_run(file_merge_w);
if (cf_name == NULL) {
/* User cancelled or closed the dialog. */
return;
}
cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_merge_w));
/* Perhaps the user specified a directory instead of a file.
Check whether they did. */
if (test_for_directory(cf_name) == EISDIR) {
/* It's a directory - set the file selection box to display that
directory, and go back and re-run it; don't try to open the
directory as a capture file. */
set_last_open_dir(cf_name);
g_free(cf_name);
file_selection_set_current_folder(file_merge_w, get_last_open_dir());
continue;
}
/* Get the specified read filter and try to compile it. */
rfilter = gtk_entry_get_text(GTK_ENTRY(filter_te));
if (!dfilter_compile(rfilter, &rfcode)) {
@ -903,7 +878,7 @@ file_merge_cmd(GtkWidget *w)
set_last_open_dir(s);
return;
}
#endif /* _WIN32 */
#endif /* USE_WIN32_FILE_DIALOGS */
}
void
@ -1594,9 +1569,9 @@ static void
do_file_save_as(capture_file *cf, gboolean must_support_comments,
gboolean dont_reopen)
{
#if _WIN32
#ifdef USE_WIN32_FILE_DIALOGS
win32_save_as_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)));
#else /* _WIN32 */
#else /* USE_WIN32_FILE_DIALOGS */
GtkWidget *file_save_as_w;
GtkWidget *main_vb, *ft_hb, *ft_lb, *ft_combo_box, *compressed_cb;
char *cf_name;
@ -1648,26 +1623,12 @@ do_file_save_as(capture_file *cf, gboolean must_support_comments,
* Loop until the user either selects a file or gives up.
*/
for (;;) {
if (gtk_dialog_run(GTK_DIALOG(file_save_as_w)) != GTK_RESPONSE_ACCEPT) {
/* They clicked "Cancel" or closed the dialog or.... */
window_destroy(file_save_as_w);
cf_name = file_selection_run(file_save_as_w);
if (cf_name == NULL) {
/* User cancelled or closed the dialog. */
return;
}
cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_save_as_w));
/* Perhaps the user specified a directory instead of a file.
Check whether they did. */
if (test_for_directory(cf_name) == EISDIR) {
/* It's a directory - set the file selection box to display that
directory, and go back and re-run it; don't try to write onto
the directory (which won't work anyway). */
set_last_open_dir(cf_name);
g_free(cf_name);
file_selection_set_current_folder(file_save_as_w, get_last_open_dir());
continue;
}
/* If the file has comments, does the format the user selected
support them? If not, ask the user whether they want to
discard the comments or choose a different format. */
@ -1704,6 +1665,7 @@ do_file_save_as(capture_file *cf, gboolean must_support_comments,
return;
}
#ifndef _WIN32
/* If the file exists and it's user-immutable or not writable,
ask the user whether they want to override that. */
if (!file_target_unwritable_ui(file_save_as_w, cf_name)) {
@ -1711,6 +1673,7 @@ do_file_save_as(capture_file *cf, gboolean must_support_comments,
g_free(cf_name);
continue;
}
#endif
/* Attempt to save the file */
g_free(cf_name);
@ -1733,7 +1696,7 @@ do_file_save_as(capture_file *cf, gboolean must_support_comments,
return;
}
}
#endif /* _WIN32 */
#endif /* USE_WIN32_FILE_DIALOGS */
}
void
@ -1806,9 +1769,9 @@ file_save_as_cb(GtkWidget *fs, gboolean discard_comments,
void
file_export_specified_packets_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
{
#if _WIN32
#ifdef USE_WIN32_FILE_DIALOGS
win32_export_specified_packets_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)));
#else /* _WIN32 */
#else /* USE_WIN32_FILE_DIALOGS */
GtkWidget *file_export_specified_packets_w;
GtkWidget *main_vb, *ft_hb, *ft_lb, *ft_combo_box, *range_fr, *range_tb,
*compressed_cb;
@ -1881,26 +1844,12 @@ file_export_specified_packets_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
* Loop until the user either selects a file or gives up.
*/
for (;;) {
if (gtk_dialog_run(GTK_DIALOG(file_export_specified_packets_w)) != GTK_RESPONSE_ACCEPT) {
/* They clicked "Cancel" or closed the dialog or.... */
window_destroy(file_export_specified_packets_w);
cf_name = file_selection_run(file_export_specified_packets_w);
if (cf_name == NULL) {
/* User cancelled or closed the dialog. */
return;
}
cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_export_specified_packets_w));
/* Perhaps the user specified a directory instead of a file.
Check whether they did. */
if (test_for_directory(cf_name) == EISDIR) {
/* It's a directory - set the file selection box to display that
directory, and go back and re-run it; don't try to write onto
the directory (which won't work anyway). */
set_last_open_dir(cf_name);
g_free(cf_name);
file_selection_set_current_folder(file_export_specified_packets_w, get_last_open_dir());
continue;
}
/* Check whether the range is valid. */
if (!range_check_validity_modal(file_export_specified_packets_w, &range)) {
/* The range isn't valid; the user was told that, and dismissed
@ -1935,6 +1884,7 @@ file_export_specified_packets_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
continue;
}
#ifndef _WIN32
/* If the file exists and it's user-immutable or not writable,
ask the user whether they want to override that. */
if (!file_target_unwritable_ui(file_export_specified_packets_w, cf_name)) {
@ -1942,6 +1892,7 @@ file_export_specified_packets_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
g_free(cf_name);
continue;
}
#endif
/* attempt to export the packets */
g_free(cf_name);
@ -1961,7 +1912,7 @@ file_export_specified_packets_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
return;
}
}
#endif /* _WIN32 */
#endif /* USE_WIN32_FILE_DIALOGS */
}
/* all tests ok, we only have to write out the packets */
@ -2062,9 +2013,9 @@ color_global_cb(GtkWidget *widget _U_, gpointer data)
void
file_color_import_cmd_cb(GtkWidget *color_filters, gpointer filter_list _U_)
{
#if _WIN32
#ifdef USE_WIN32_FILE_DIALOGS
win32_import_color_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)), color_filters);
#else /* _WIN32 */
#else /* USE_WIN32_FILE_DIALOGS */
GtkWidget *main_vb, *cfglobal_but;
gchar *cf_name, *s;
@ -2090,26 +2041,12 @@ file_color_import_cmd_cb(GtkWidget *color_filters, gpointer filter_list _U_)
* Loop until the user either selects a file or gives up.
*/
for (;;) {
if (gtk_dialog_run(GTK_DIALOG(file_color_import_w)) != GTK_RESPONSE_ACCEPT) {
/* They clicked "Cancel" or closed the dialog or.... */
window_destroy(file_color_import_w);
cf_name = file_selection_run(file_color_import_w);
if (cf_name == NULL) {
/* User cancelled or closed the dialog. */
return;
}
cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_color_import_w));
/* Perhaps the user specified a directory instead of a file.
Check whether they did. */
if (test_for_directory(cf_name) == EISDIR) {
/* It's a directory - set the file selection box to display that
directory, and go back and re-run it; don't try to open the
directory as a color filter file. */
set_last_open_dir(cf_name);
g_free(cf_name);
file_selection_set_current_folder(file_color_import_w, get_last_open_dir());
continue;
}
/* Try to open the color filter file. */
if (!color_filters_import(cf_name, color_filters)) {
/* We couldn't open it; don't dismiss the open dialog box,
@ -2132,7 +2069,7 @@ file_color_import_cmd_cb(GtkWidget *color_filters, gpointer filter_list _U_)
g_free(cf_name);
return;
}
#endif /* _WIN32 */
#endif /* USE_WIN32_FILE_DIALOGS */
}
/*
@ -2167,9 +2104,9 @@ color_toggle_selected_cb(GtkWidget *widget, gpointer data _U_)
void
file_color_export_cmd_cb(GtkWidget *w _U_, gpointer filter_list)
{
#if _WIN32
#if USE_WIN32_FILE_DIALOGS
win32_export_color_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)), filter_list);
#else /* _WIN32 */
#else /* USE_WIN32_FILE_DIALOGS */
GtkWidget *file_color_export_w;
GtkWidget *main_vb, *cfglobal_but;
GtkWidget *cfselect_cb;
@ -2207,26 +2144,13 @@ file_color_export_cmd_cb(GtkWidget *w _U_, gpointer filter_list)
* Loop until the user either selects a file or gives up.
*/
for (;;) {
if (gtk_dialog_run(GTK_DIALOG(file_color_export_w)) != GTK_RESPONSE_ACCEPT) {
/* They clicked "Cancel" or closed the dialog or.... */
window_destroy(file_color_export_w);
cf_name = file_selection_run(file_color_export_w);
if (cf_name == NULL) {
/* User cancelled or closed the dialog. */
return;
}
cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_color_export_w));
/* Perhaps the user specified a directory instead of a file.
Check whether they did. */
if (test_for_directory(cf_name) == EISDIR) {
/* It's a directory - set the file selection box to display that
directory, and go back and re-run it; don't try to write onto
the directory (which wn't work anyway). */
set_last_open_dir(cf_name);
g_free(cf_name);
file_selection_set_current_folder(file_color_export_w, get_last_open_dir());
continue;
}
#ifndef _WIN32
/* If the file exists and it's user-immutable or not writable,
ask the user whether they want to override that. */
if (!file_target_unwritable_ui(file_color_export_w, cf_name)) {
@ -2234,6 +2158,7 @@ file_color_export_cmd_cb(GtkWidget *w _U_, gpointer filter_list)
g_free(cf_name);
continue;
}
#endif
/* Write out the filters (all, or only the ones that are currently
displayed or selected) to the file with the specified name. */
@ -2253,5 +2178,5 @@ file_color_export_cmd_cb(GtkWidget *w _U_, gpointer filter_list)
set_last_open_dir(dirname);
g_free(cf_name);
}
#endif /* _WIN32 */
#endif /* USE_WIN32_FILE_DIALOGS */
}

View File

@ -22,6 +22,15 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* Code to handle Windows shortcuts courtesy of:
*
* Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
* Copyright (C) 1999-2012 Hiroyuki Yamamoto
*
* licensed under the GPL2 or later.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
@ -30,12 +39,22 @@
#include <gtk/gtk.h>
#ifdef _WIN32
# define COBJMACROS
# include <windows.h>
# include <objbase.h>
# include <objidl.h>
# include <shlobj.h>
#endif
#include <wsutil/file_util.h>
#ifndef _WIN32
#include <epan/filesystem.h>
#endif
#include "ui/last_open_dir.h"
#include "ui/gtk/gtkglobals.h"
#include "ui/gtk/gui_utils.h"
#include "ui/gtk/file_dlg.h"
@ -157,6 +176,110 @@ file_selection_set_extra_widget(GtkWidget *fs, GtkWidget *extra)
gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(fs), extra);
}
#ifdef _WIN32
static gchar *filesel_get_link(const gchar *link_file)
{
WIN32_FIND_DATAW wfd;
IShellLinkW *psl;
IPersistFile *ppf;
wchar_t *wlink_file;
wchar_t wtarget[MAX_PATH];
gchar *target = NULL;
wtarget[0] = 0L;
CoInitialize(NULL);
if (S_OK == CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
&IID_IShellLinkW, (void **)&psl)) {
if (S_OK == IShellLinkW_QueryInterface(psl, &IID_IPersistFile,
(void **)&ppf)) {
wlink_file = g_utf8_to_utf16(link_file, -1, NULL, NULL, NULL);
if (S_OK == IPersistFile_Load(ppf, wlink_file, STGM_READ)) {
if (S_OK == IShellLinkW_GetPath(psl, wtarget, MAX_PATH, &wfd,
SLGP_UNCPRIORITY)) {
target = g_utf16_to_utf8(wtarget, -1, NULL, NULL, NULL);
}
}
IPersistFile_Release(ppf);
g_free(wlink_file);
}
IShellLinkW_Release(psl);
}
CoUninitialize();
return target;
}
#endif /* _WIN32 */
/* Run the dialog, and handle some common operations, such as, if the
user selects a directory, browsing that directory, and handling
shortcuts on Windows.
Returns NULL if the user decided not to open/write to a file,
returns the pathname of the selected file if they selected a
file. */
gchar *
file_selection_run(GtkWidget *fs)
{
gchar *cf_name;
#ifdef _WIN32
gchar *target;
const gchar *ext;
#endif
for (;;) {
if (gtk_dialog_run(GTK_DIALOG(fs)) != GTK_RESPONSE_ACCEPT) {
/* They clicked "Cancel" or closed the dialog or...;
destroy the dialog and tell our caller the user decided
not to do anything with the file. */
window_destroy(fs);
return NULL;
}
cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs));
/* Perhaps the user specified a directory instead of a file.
Check whether they did. */
if (test_for_directory(cf_name) == EISDIR) {
/* It's a directory - set the file selection box to display that
directory, and go back and re-run it; don't try to open the
directory as a file (you'll get crap if you get anything) or
write to it (which won't work anyway). */
set_last_open_dir(cf_name);
g_free(cf_name);
file_selection_set_current_folder(fs, get_last_open_dir());
continue;
}
#ifdef _WIN32
/* Perhaps the user specified a "shortcut" instead of a file.
Check whether they did. */
if ((ext = strrchr(cf_name, '.')) && g_ascii_strcasecmp(ext, ".lnk") == 0) {
/* It ends with ".lnk", so it might be a shortcut. */
target = filesel_get_link(cf_name);
if (target != NULL) {
/* We resolved it, so it must've been a shortcut. */
g_free(cf_name);
if (test_for_directory(target)) {
/* It's a shortcut that points to a directory; treat it the same
way we treat a directory. */
set_last_open_dir(target);
g_free(target);
file_selection_set_current_folder(fs, get_last_open_dir());
continue;
}
/* It's a shortcut that points to a file; act as if the target
is what's selected. */
cf_name = target;
}
}
#endif
break;
}
return cf_name;
}
#ifndef _WIN32
/* If the specified file doesn't exist, return TRUE.
If it exists and is neither user-immutable nor not writable, return

View File

@ -85,6 +85,15 @@ extern gboolean file_selection_set_current_folder(GtkWidget *fs, const gchar *fi
*/
extern void file_selection_set_extra_widget(GtkWidget *fs, GtkWidget *extra);
/** Run the dialog, and handle some common operations, such as, if the
* user selects a directory, browsing that directory, and handling
* shortcuts on Windows.
* @param fs the file selection dialog from file_selection_new()
* @return the pathname of the selected file if the user selected a
* file, NULL if they cancelled or closed the dialog.
*/
extern gchar *file_selection_run(GtkWidget *fs);
#ifndef _WIN32
/** If the specified file doesn't exist, return TRUE.
* If it exists and is neither user-immutable nor not writable, return