Adding upstream version 0.9.0.
[debian/lxpanel.git] / plugins / launch-button.c
1 /**
2 * Copyright (C) 2016 Andriy Grytsenko <andrej@rep.kiev.ua>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include "launch-button.h"
24 #include "misc.h"
25
26 #include <string.h>
27
28 /* Representative of one launch button.
29 * Note that the launch parameters come from the specified desktop file, or from the configuration file.
30 * This structure is also used during the "add to launchtaskbar" dialog to hold menu items. */
31 struct _LaunchButton
32 {
33 GtkEventBox parent;
34 LXPanel * panel; /* Back pointer to panel (grandparent widget) */
35 GtkWidget * plugin; /* Back pointer to the plugin */
36 FmJob * job; /* Async job to retrieve file info */
37 FmFileInfo * fi; /* Launcher application descriptor */
38 config_setting_t * settings; /* Button settings */
39 };
40
41
42 static void launch_button_job_finished(FmJob *job, LaunchButton *self)
43 {
44 GtkWidget *image;
45
46 if (self->job == NULL)
47 return; // duplicate call? seems a bug in libfm
48
49 if (FM_IS_FILE_INFO_JOB(job))
50 {
51 /* absolute path */
52 self->fi = fm_file_info_list_pop_head(FM_FILE_INFO_JOB(job)->file_infos);
53 }
54 else
55 {
56 /* search for id */
57 self->fi = fm_file_info_list_pop_head(FM_DIR_LIST_JOB(job)->files);
58 }
59 self->job = NULL;
60 g_object_unref(job);
61 if (self->fi == NULL)
62 {
63 g_warning("launchbar: desktop entry does not exist");
64 return;
65 }
66 image = lxpanel_image_new_for_fm_icon(self->panel, fm_file_info_get_icon(self->fi),
67 -1, NULL);
68 lxpanel_button_compose(GTK_WIDGET(self), image, NULL, NULL);
69 gtk_widget_set_tooltip_text(GTK_WIDGET(self), fm_file_info_get_disp_name(self->fi));
70 }
71
72
73 /* -----------------------------------------------------------------------------
74 * Class implementation
75 */
76
77 G_DEFINE_TYPE(LaunchButton, launch_button, GTK_TYPE_EVENT_BOX)
78
79 static void launch_button_dispose(GObject *object)
80 {
81 LaunchButton *self = (LaunchButton *)object;
82
83 if (self->job)
84 {
85 g_signal_handlers_disconnect_by_func(self->job,
86 launch_button_job_finished, object);
87 fm_job_cancel(self->job);
88 self->job = NULL;
89 }
90
91 if (self->fi)
92 {
93 fm_file_info_unref(self->fi);
94 self->fi = NULL;
95 }
96
97 G_OBJECT_CLASS(launch_button_parent_class)->dispose(object);
98 }
99
100 static gboolean launch_button_release_event(GtkWidget *widget, GdkEventButton *event)
101 {
102 LaunchButton *btn = PANEL_LAUNCH_BUTTON(widget);
103
104 if (event->button == 1) /* left button */
105 {
106 if (btn->job) /* The job is still running */
107 ;
108 else if (btn->fi == NULL) /* The bootstrap button */
109 lxpanel_plugin_show_config_dialog(btn->plugin);
110 else
111 lxpanel_launch_path(btn->panel, fm_file_info_get_path(btn->fi));
112 return TRUE;
113 }
114 return FALSE;
115 }
116
117 static void launch_button_init(LaunchButton *self)
118 {
119 gtk_container_set_border_width(GTK_CONTAINER(self), 0);
120 gtk_widget_set_can_focus(GTK_WIDGET(self), FALSE);
121 }
122
123 static void launch_button_class_init(LaunchButtonClass *klass)
124 {
125 GObjectClass *object_class = G_OBJECT_CLASS(klass);
126 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
127
128 object_class->dispose = launch_button_dispose;
129 widget_class->button_release_event = launch_button_release_event;
130 }
131
132
133 /* -----------------------------------------------------------------------------
134 * Interface functions
135 */
136
137 /* creates new button */
138 LaunchButton *launch_button_new(LXPanel *panel, GtkWidget *plugin, FmPath *id,
139 config_setting_t *settings)
140 {
141 LaunchButton *self = g_object_new(PANEL_TYPE_LAUNCH_BUTTON, NULL);
142 GtkWidget *image;
143
144 self->panel = panel;
145 self->plugin = plugin;
146 self->settings = settings;
147 if (id == NULL)
148 {
149 /* a bootstrap button */
150 image = lxpanel_image_new_for_icon(panel, GTK_STOCK_ADD, -1, NULL);
151 lxpanel_button_compose(GTK_WIDGET(self), image, NULL, NULL);
152 }
153 else
154 {
155 /* g_debug("LaunchButton: trying file %s in scheme %s", fm_path_get_basename(id),
156 fm_path_get_basename(fm_path_get_scheme_path(id))); */
157 if (fm_path_is_native(id) ||
158 strncmp(fm_path_get_basename(fm_path_get_scheme_path(id)), "search:", 7) != 0)
159 {
160 FmFileInfoJob *job = fm_file_info_job_new(NULL, FM_FILE_INFO_JOB_NONE);
161
162 fm_file_info_job_add(job, id);
163 self->job = FM_JOB(job);
164 }
165 else /* it is a search job */
166 {
167 FmDirListJob *job = fm_dir_list_job_new2(id, FM_DIR_LIST_JOB_FAST);
168
169 self->job = FM_JOB(job);
170 }
171 g_signal_connect(self->job, "finished",
172 G_CALLBACK(launch_button_job_finished), self);
173 if (!fm_job_run_async(self->job))
174 {
175 g_object_unref(self->job);
176 self->job = NULL;
177 gtk_widget_destroy(GTK_WIDGET(self));
178 g_warning("launchbar: problem running file search job");
179 return NULL;
180 }
181 }
182 return self;
183 }
184
185 FmFileInfo *launch_button_get_file_info(LaunchButton *btn)
186 {
187 if (PANEL_IS_LAUNCH_BUTTON(btn))
188 return btn->fi;
189 return NULL;
190 }
191
192 const char *launch_button_get_disp_name(LaunchButton *btn)
193 {
194 if (PANEL_IS_LAUNCH_BUTTON(btn) && btn->fi != NULL)
195 return fm_file_info_get_disp_name(btn->fi);
196 return NULL;
197 }
198
199 FmIcon *launch_button_get_icon(LaunchButton *btn)
200 {
201 if (PANEL_IS_LAUNCH_BUTTON(btn) && btn->fi != NULL)
202 return fm_file_info_get_icon(btn->fi);
203 return NULL;
204 }
205
206 config_setting_t *launch_button_get_settings(LaunchButton *btn)
207 {
208 if (PANEL_IS_LAUNCH_BUTTON(btn))
209 return btn->settings;
210 return NULL;
211 }
212
213 void launch_button_set_settings(LaunchButton *btn, config_setting_t *settings)
214 {
215 if (PANEL_IS_LAUNCH_BUTTON(btn))
216 btn->settings = settings;
217 }
218
219 /**
220 * launch_button_wait_load
221 * @btn: a button instance
222 *
223 * If @btn does not have pending file info then returns. Otherwise waits
224 * for it. If loading the info failed then destroys @btn and associated
225 * settings.
226 *
227 * Returns: %TRUE if button is fully loaded.
228 *
229 * Since: 0.9.0
230 */
231 gboolean launch_button_wait_load(LaunchButton *btn)
232 {
233 if (!PANEL_IS_LAUNCH_BUTTON(btn) || btn->job == NULL)
234 return TRUE;
235 if (fm_job_run_sync(btn->job))
236 return TRUE;
237
238 if (btn->settings)
239 config_setting_destroy(btn->settings);
240 gtk_widget_destroy(GTK_WIDGET(btn));
241 return FALSE;
242 }