4
* Copyright 2010 Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program 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
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25
#include <glib/gi18n-lib.h>
29
#include "fm-app-chooser-dlg.h"
30
#include "fm-app-menu-view.h"
31
#include <menu-cache.h>
32
#include <gio/gdesktopappinfo.h>
34
typedef struct _AppChooserData AppChooserData;
35
struct _AppChooserData
41
GtkWidget* set_default;
43
GtkWidget* use_terminal;
44
FmMimeType* mime_type;
47
GAppInfo* fm_app_info_create_from_commandline(const char *commandline,
48
const char *application_name,
52
char* dirname = g_build_filename (g_get_user_data_dir (), "applications", NULL);
54
if(g_mkdir_with_parents(dirname, 0700) == 0)
56
char* filename = g_strdup_printf ("%s/userapp-%s-XXXXXX.desktop", dirname, application_name);
57
int fd = g_mkstemp (filename);
60
GString* content = g_string_sized_new(256);
61
g_string_printf(content,
71
g_string_append_printf(content,
72
"Terminal=%s\n", terminal ? "true" : "false");
73
if(g_file_set_contents(filename, content->str, content->len, NULL))
75
char* desktop_id = g_path_get_basename(filename);
76
app = g_desktop_app_info_new(desktop_id);
87
static void on_dlg_destroy(AppChooserData* data, GObject* dlg)
89
g_slice_free(AppChooserData, data);
92
static void on_switch_page(GtkNotebook* nb, GtkWidget* page, gint num, AppChooserData* data)
94
if(num == 0) /* list of installed apps */
96
gtk_label_set_text(GTK_LABEL(data->status), _("Use selected application to open files"));
97
gtk_dialog_set_response_sensitive(data->dlg, GTK_RESPONSE_OK,
98
fm_app_menu_view_is_app_selected(GTK_TREE_VIEW(data->apps_view)));
100
else /* custom app */
102
const char* cmd = gtk_entry_get_text(GTK_ENTRY(data->cmdline));
103
gtk_label_set_text(GTK_LABEL(data->status), _("Execute custom command line to open files"));
104
gtk_dialog_set_response_sensitive(GTK_DIALOG(data->dlg), GTK_RESPONSE_OK, (cmd && cmd[0]));
108
static void on_apps_view_sel_changed(GtkTreeSelection* tree_sel, AppChooserData* data)
110
if(gtk_notebook_get_current_page(GTK_NOTEBOOK(data->notebook)) == 0)
112
gtk_dialog_set_response_sensitive(data->dlg, GTK_RESPONSE_OK,
113
fm_app_menu_view_is_app_selected(GTK_TREE_VIEW(data->apps_view)));
117
static void on_cmdline_changed(GtkEditable* cmdline, AppChooserData* data)
119
if(gtk_notebook_get_current_page(GTK_NOTEBOOK(data->notebook)) == 1)
121
const char* cmd = gtk_entry_get_text(GTK_ENTRY(data->cmdline));
122
gtk_dialog_set_response_sensitive(GTK_DIALOG(data->dlg), GTK_RESPONSE_OK, (cmd && cmd[0]));
126
GtkWidget *fm_app_chooser_dlg_new(FmMimeType* mime_type, gboolean can_set_default)
129
GtkWidget* file_type;
130
GtkTreeSelection* tree_sel;
131
GtkBuilder* builder = gtk_builder_new();
132
AppChooserData* data = g_slice_new0(AppChooserData);
134
gtk_builder_set_translation_domain(builder, GETTEXT_PACKAGE);
135
gtk_builder_add_from_file(builder, PACKAGE_UI_DIR "/app-chooser.ui", NULL);
136
data->dlg = (GtkWidget*)gtk_builder_get_object(builder, "dlg");
137
data->notebook = (GtkWidget*)gtk_builder_get_object(builder, "notebook");
138
scroll = (GtkWidget*)gtk_builder_get_object(builder, "apps_scroll");
139
file_type = (GtkWidget*)gtk_builder_get_object(builder, "file_type");
140
data->cmdline = (GtkWidget*)gtk_builder_get_object(builder, "cmdline");
141
data->set_default = (GtkWidget*)gtk_builder_get_object(builder, "set_default");
142
data->use_terminal = (GtkWidget*)gtk_builder_get_object(builder, "use_terminal");
143
data->status = (GtkWidget*)gtk_builder_get_object(builder, "status");
144
data->mime_type = mime_type;
146
gtk_dialog_set_alternative_button_order(GTK_DIALOG(data->dlg), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1);
149
gtk_widget_hide(data->set_default);
151
if(mime_type && mime_type->type && mime_type->description)
152
gtk_label_set_text(GTK_LABEL(file_type), mime_type->description);
155
GtkWidget* hbox = (GtkWidget*)gtk_builder_get_object(builder, "file_type_hbox");
156
gtk_widget_destroy(hbox);
157
gtk_widget_hide(data->set_default);
160
data->apps_view = fm_app_menu_view_new();
161
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(data->apps_view), FALSE);
162
gtk_widget_show(data->apps_view);
163
gtk_container_add(GTK_CONTAINER(scroll), data->apps_view);
164
gtk_widget_grab_focus(data->apps_view);
166
g_object_unref(builder);
168
g_object_set_qdata_full(G_OBJECT(data->dlg), fm_qdata_id, data, (GDestroyNotify)on_dlg_destroy);
169
g_signal_connect(data->notebook, "switch-page", G_CALLBACK(on_switch_page), data);
170
on_switch_page(GTK_NOTEBOOK(data->notebook), NULL, 0, data);
171
tree_sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->apps_view));
172
g_signal_connect(tree_sel, "changed", G_CALLBACK(on_apps_view_sel_changed), data);
173
g_signal_connect(data->cmdline, "changed", G_CALLBACK(on_cmdline_changed), data);
174
gtk_dialog_set_response_sensitive(GTK_DIALOG(data->dlg), GTK_RESPONSE_OK, FALSE);
179
inline static char* get_binary(const char* cmdline, gboolean* arg_found)
181
/* see if command line contains %f, %F, %u, or %U. */
182
const char* p = strstr(cmdline, " %");
185
if( !strchr("fFuU", *(p + 2)) )
189
*arg_found = (p != NULL);
191
return g_strndup(cmdline, p - cmdline);
193
return g_strdup(cmdline);
196
GAppInfo* fm_app_chooser_dlg_get_selected_app(GtkDialog* dlg, gboolean* set_default)
198
GAppInfo* app = NULL;
199
AppChooserData* data = (AppChooserData*)g_object_get_qdata(G_OBJECT(dlg), fm_qdata_id);
200
switch( gtk_notebook_get_current_page(GTK_NOTEBOOK(data->notebook)) )
202
case 0: /* all applications */
203
app = fm_app_menu_view_get_selected_app(GTK_TREE_VIEW(data->apps_view));
205
case 1: /* custom cmd line */
207
const char* cmdline = gtk_entry_get_text(GTK_ENTRY(data->cmdline));
208
if(cmdline && cmdline[0])
210
char* _cmdline = NULL;
211
gboolean arg_found = FALSE;
212
char* bin1 = get_binary(cmdline, &arg_found);
213
g_debug("bin1 = %s", bin1);
214
/* see if command line contains %f, %F, %u, or %U. */
215
if(!arg_found) /* append %f if no %f, %F, %u, or %U was found. */
216
cmdline = _cmdline = g_strconcat(cmdline, " %f", NULL);
218
/* FIXME: is there any better way to do this? */
219
/* We need to ensure that no duplicated items are added */
222
MenuCache* menu_cache;
223
#if GLIB_CHECK_VERSION(2, 10, 0)
224
/* see if the command is already in the list of known apps for this mime-type */
225
GList* apps = g_app_info_get_all_for_type(data->mime_type->type);
227
for(l=apps;l;l=l->next)
229
GAppInfo* app2 = (GAppInfo*)l->data;
230
const char* cmd = g_app_info_get_commandline(app2);
231
char* bin2 = get_binary(cmd, NULL);
232
if(g_strcmp0(bin1, bin2) == 0)
234
app = (GAppInfo*)g_object_ref(app2);
235
g_debug("found in app list");
241
g_list_foreach(apps, (GFunc)g_object_unref, NULL);
247
/* see if this command can be found in menu cache */
248
menu_cache = menu_cache_lookup("applications.menu");
251
if(menu_cache_get_root_dir(menu_cache))
253
GSList* all_apps = menu_cache_list_all_apps(menu_cache);
255
for(l=all_apps;l;l=l->next)
257
MenuCacheApp* ma = MENU_CACHE_APP(l->data);
258
char* bin2 = get_binary(menu_cache_app_get_exec(ma), NULL);
259
if(g_strcmp0(bin1, bin2) == 0)
261
app = g_desktop_app_info_new(menu_cache_item_get_id(MENU_CACHE_ITEM(ma)));
262
g_debug("found in menu cache");
263
menu_cache_item_unref(MENU_CACHE_ITEM(ma));
267
menu_cache_item_unref(MENU_CACHE_ITEM(ma));
270
g_slist_free(all_apps);
272
menu_cache_unref(menu_cache);
278
/* FIXME: g_app_info_create_from_commandline force the use of %f or %u, so this is not we need */
279
app = fm_app_info_create_from_commandline(cmdline, bin1, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->use_terminal)));
289
*set_default = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->set_default));
293
GAppInfo* fm_choose_app_for_mime_type(GtkWindow* parent, FmMimeType* mime_type, gboolean can_set_default)
295
GAppInfo* app = NULL;
296
GtkWidget* dlg = fm_app_chooser_dlg_new(mime_type, can_set_default);
298
gtk_window_set_transient_for(GTK_WINDOW(dlg), parent);
299
if(gtk_dialog_run(GTK_DIALOG(dlg)) == GTK_RESPONSE_OK)
301
gboolean set_default;
302
app = fm_app_chooser_dlg_get_selected_app(GTK_DIALOG(dlg), &set_default);
304
if(app && mime_type && mime_type->type)
307
/* add this app to the mime-type */
308
if(!g_app_info_add_supports_type(app, mime_type->type, &err))
310
g_debug("error: %s", err->message);
313
/* if need to set default */
315
g_app_info_set_as_default_for_type(app, mime_type->type, NULL);
318
gtk_widget_destroy(dlg);