33.2.2
by Ted Gould
Adding a desktop hook binary |
1 |
/*
|
2 |
* Copyright 2013 Canonical Ltd.
|
|
3 |
*
|
|
4 |
* This program is free software: you can redistribute it and/or modify it
|
|
5 |
* under the terms of the GNU General Public License version 3, as published
|
|
6 |
* by the Free Software Foundation.
|
|
7 |
*
|
|
8 |
* This program is distributed in the hope that it will be useful, but
|
|
9 |
* WITHOUT ANY WARRANTY; without even the implied warranties of
|
|
10 |
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
|
|
11 |
* PURPOSE. See the GNU General Public License for more details.
|
|
12 |
*
|
|
13 |
* You should have received a copy of the GNU General Public License along
|
|
14 |
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
15 |
*
|
|
16 |
* Authors:
|
|
17 |
* Ted Gould <ted.gould@canonical.com>
|
|
18 |
*/
|
|
19 |
||
33.2.40
by Ted Gould
Adding some documentation on what the hook is doing. |
20 |
/*
|
21 |
||
22 |
INTRODUCTION:
|
|
23 |
||
24 |
This is a hook for Click packages. You can find information on Click package hooks in
|
|
25 |
the click documentation:
|
|
26 |
||
135.2.1
by Colin Watson
Update Click documentation link. |
27 |
https://click.readthedocs.org/en/latest/
|
33.2.40
by Ted Gould
Adding some documentation on what the hook is doing. |
28 |
|
29 |
Probably the biggest thing to understand for how this code works is that you need to
|
|
30 |
understand that this hook is run after one, or many packages are installed. A set of
|
|
31 |
symbolic links are made to the desktop files per-application (not per-package) in the
|
|
152.1.6
by Ted Gould
Removing more instances if 'upstart' to not confuse people, leaving the tracepoints for now |
32 |
directory specified in ubuntu-app-launcher-desktop.click-hook.in. Those desktop files
|
33.2.40
by Ted Gould
Adding some documentation on what the hook is doing. |
33 |
give us the App ID of the packages that are installed and have applications needing
|
34 |
desktop files in them. We then operate on each of them ensuring that they are synchronized
|
|
35 |
with the desktop files in ~/.local/share/applications/.
|
|
36 |
||
37 |
The desktop files that we're creating there ARE NOT used for execution by the
|
|
152.1.6
by Ted Gould
Removing more instances if 'upstart' to not confuse people, leaving the tracepoints for now |
38 |
ubuntu-app-launch Upstart jobs. They are there so that Unity can know which applications
|
33.2.40
by Ted Gould
Adding some documentation on what the hook is doing. |
39 |
are installed for this user and they provide an Exec line to allow compatibility with
|
152.1.6
by Ted Gould
Removing more instances if 'upstart' to not confuse people, leaving the tracepoints for now |
40 |
desktop environments that are not using ubuntu-app-launch for launching applications.
|
33.2.40
by Ted Gould
Adding some documentation on what the hook is doing. |
41 |
You should not modify them and expect any executing under Unity to change.
|
42 |
||
43 |
*/
|
|
44 |
||
33.2.3
by Ted Gould
Set up the skeleton for determining state |
45 |
#include <gio/gio.h> |
33.2.16
by Ted Gould
Upping the warnings |
46 |
#include <glib/gstdio.h> |
135.2.2
by Colin Watson
Use libclick to get the package directory, saving about 0.7 seconds from Click application startup. |
47 |
#include <click.h> |
33.2.6
by Ted Gould
Fleshing out listing all the desktop files |
48 |
#include <string.h> |
51.1.6
by Ted Gould
Pipe directly |
49 |
#include <errno.h> |
208.9.1
by Ted Gould
Switching to libwhoopsie for recoverable problem support |
50 |
#include <libwhoopsie/recoverable-problem.h> |
33.2.3
by Ted Gould
Set up the skeleton for determining state |
51 |
|
33.2.15
by Ted Gould
Move the app id checking to the helpers file |
52 |
#include "helpers.h" |
53 |
||
33.2.3
by Ted Gould
Set up the skeleton for determining state |
54 |
typedef struct _app_state_t app_state_t; |
55 |
struct _app_state_t { |
|
56 |
gchar * app_id; |
|
57 |
gboolean has_click; |
|
33.2.6
by Ted Gould
Fleshing out listing all the desktop files |
58 |
gboolean has_desktop; |
33.2.39
by Ted Gould
Switching to modification time. |
59 |
guint64 click_modified; |
60 |
guint64 desktop_modified; |
|
33.2.3
by Ted Gould
Set up the skeleton for determining state |
61 |
};
|
62 |
||
168.1.6
by Ted Gould
Cleaning up and hadding an old key prefix |
63 |
/* Desktop Group */
|
64 |
#define DESKTOP_GROUP "Desktop Entry"
|
|
65 |
/* Desktop Keys */
|
|
66 |
#define APP_ID_KEY "X-Ubuntu-Application-ID"
|
|
67 |
#define PATH_KEY "Path"
|
|
68 |
#define EXEC_KEY "Exec"
|
|
69 |
#define ICON_KEY "Icon"
|
|
70 |
#define SYMBOLIC_ICON_KEY "X-Ubuntu-SymbolicIcon"
|
|
175.5.2
by Ted Gould
Putting the built key into the cache desktop file |
71 |
#define SOURCE_FILE_KEY "X-Ubuntu-UAL-Source-Desktop"
|
168.1.6
by Ted Gould
Cleaning up and hadding an old key prefix |
72 |
/* Other */
|
73 |
#define OLD_KEY_PREFIX "X-Ubuntu-Old-"
|
|
168.1.3
by Ted Gould
Make desktop keys into defines |
74 |
|
33.2.5
by Ted Gould
Fleshing out adding a click package directory |
75 |
/* Find an entry in the app array */
|
76 |
app_state_t * |
|
77 |
find_app_entry (const gchar * name, GArray * app_array) |
|
78 |
{
|
|
79 |
int i; |
|
80 |
for (i = 0; i < app_array->len; i++) { |
|
81 |
app_state_t * state = &g_array_index(app_array, app_state_t, i); |
|
82 |
||
83 |
if (g_strcmp0(state->app_id, name) == 0) { |
|
84 |
return state; |
|
85 |
}
|
|
86 |
}
|
|
87 |
||
88 |
app_state_t newstate; |
|
89 |
newstate.has_click = FALSE; |
|
33.2.6
by Ted Gould
Fleshing out listing all the desktop files |
90 |
newstate.has_desktop = FALSE; |
33.2.39
by Ted Gould
Switching to modification time. |
91 |
newstate.click_modified = 0; |
92 |
newstate.desktop_modified = 0; |
|
33.2.5
by Ted Gould
Fleshing out adding a click package directory |
93 |
newstate.app_id = g_strdup(name); |
94 |
||
95 |
g_array_append_val(app_array, newstate); |
|
96 |
||
97 |
/* Note: The pointer needs to be the entry in the array, not the
|
|
98 |
one that we have on the stack. Criticaly important. */
|
|
99 |
app_state_t * statepntr = &g_array_index(app_array, app_state_t, app_array->len - 1); |
|
100 |
return statepntr; |
|
101 |
}
|
|
102 |
||
33.2.22
by Ted Gould
Handle the case of creation time changing |
103 |
/* Looks up the file creation time, which seems harder with GLib
|
104 |
than it should be */
|
|
105 |
guint64
|
|
33.2.39
by Ted Gould
Switching to modification time. |
106 |
modified_time (const gchar * dir, const gchar * filename) |
33.2.22
by Ted Gould
Handle the case of creation time changing |
107 |
{
|
108 |
gchar * path = g_build_filename(dir, filename, NULL); |
|
109 |
GFile * file = g_file_new_for_path(path); |
|
33.2.39
by Ted Gould
Switching to modification time. |
110 |
GFileInfo * info = g_file_query_info(file, G_FILE_ATTRIBUTE_TIME_MODIFIED, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, NULL); |
33.2.22
by Ted Gould
Handle the case of creation time changing |
111 |
|
33.2.39
by Ted Gould
Switching to modification time. |
112 |
guint64 time = g_file_info_get_attribute_uint64(info, G_FILE_ATTRIBUTE_TIME_MODIFIED); |
33.2.22
by Ted Gould
Handle the case of creation time changing |
113 |
|
114 |
g_object_unref(info); |
|
115 |
g_object_unref(file); |
|
116 |
g_free(path); |
|
117 |
||
118 |
return time; |
|
119 |
}
|
|
120 |
||
33.2.3
by Ted Gould
Set up the skeleton for determining state |
121 |
/* Look at an click package entry */
|
122 |
void
|
|
33.2.22
by Ted Gould
Handle the case of creation time changing |
123 |
add_click_package (const gchar * dir, const gchar * name, GArray * app_array) |
33.2.3
by Ted Gould
Set up the skeleton for determining state |
124 |
{
|
33.2.27
by Ted Gould
Change the name of the symlink |
125 |
if (!g_str_has_suffix(name, ".desktop")) { |
126 |
return; |
|
127 |
}
|
|
128 |
||
129 |
gchar * appid = g_strdup(name); |
|
130 |
g_strstr_len(appid, -1, ".desktop")[0] = '\0'; |
|
131 |
||
132 |
app_state_t * state = find_app_entry(appid, app_array); |
|
33.2.5
by Ted Gould
Fleshing out adding a click package directory |
133 |
state->has_click = TRUE; |
33.2.39
by Ted Gould
Switching to modification time. |
134 |
state->click_modified = modified_time(dir, name); |
33.2.3
by Ted Gould
Set up the skeleton for determining state |
135 |
|
33.2.27
by Ted Gould
Change the name of the symlink |
136 |
g_free(appid); |
137 |
||
33.2.3
by Ted Gould
Set up the skeleton for determining state |
138 |
return; |
139 |
}
|
|
140 |
||
175.5.1
by Ted Gould
Insert the new function to check |
141 |
/* Look at the desktop file and ensure that it was built by us, and if it
|
175.5.18
by Ted Gould
Fix typo |
142 |
was that its source still exists */
|
175.5.1
by Ted Gould
Insert the new function to check |
143 |
gboolean
|
144 |
desktop_source_exists (const gchar * dir, const gchar * name) |
|
145 |
{
|
|
175.5.3
by Ted Gould
Checking the new value we're putting into the desktop file |
146 |
gchar * desktopfile = g_build_filename(dir, name, NULL); |
147 |
||
148 |
GKeyFile * keyfile = g_key_file_new(); |
|
149 |
g_key_file_load_from_file(keyfile, |
|
150 |
desktopfile, |
|
151 |
G_KEY_FILE_NONE, |
|
152 |
NULL); /* No error */ |
|
153 |
||
154 |
if (!g_key_file_has_key(keyfile, DESKTOP_GROUP, SOURCE_FILE_KEY, NULL)) { |
|
195.1.1
by Ted Gould
If we don't have a source label but still have an app id assume that the file is allowed to be further checked for a match |
155 |
gboolean hasappid = g_key_file_has_key(keyfile, DESKTOP_GROUP, APP_ID_KEY, NULL); |
175.5.3
by Ted Gould
Checking the new value we're putting into the desktop file |
156 |
g_free(desktopfile); |
157 |
g_key_file_free(keyfile); |
|
195.1.1
by Ted Gould
If we don't have a source label but still have an app id assume that the file is allowed to be further checked for a match |
158 |
return hasappid; |
175.5.3
by Ted Gould
Checking the new value we're putting into the desktop file |
159 |
}
|
160 |
||
161 |
/* At this point we know the key exists, so if we can't find the source
|
|
162 |
file we want to delete the file as well. We need to replace it. */
|
|
163 |
gchar * originalfile = g_key_file_get_string(keyfile, DESKTOP_GROUP, SOURCE_FILE_KEY, NULL); |
|
164 |
g_key_file_free(keyfile); |
|
165 |
gboolean found = TRUE; |
|
166 |
||
167 |
if (!g_file_test(originalfile, G_FILE_TEST_EXISTS)) { |
|
168 |
g_remove(desktopfile); |
|
169 |
found = FALSE; |
|
170 |
}
|
|
171 |
||
172 |
g_free(originalfile); |
|
173 |
g_free(desktopfile); |
|
174 |
||
175 |
return found; |
|
175.5.1
by Ted Gould
Insert the new function to check |
176 |
}
|
177 |
||
33.2.3
by Ted Gould
Set up the skeleton for determining state |
178 |
/* Look at an desktop file entry */
|
179 |
void
|
|
33.2.22
by Ted Gould
Handle the case of creation time changing |
180 |
add_desktop_file (const gchar * dir, const gchar * name, GArray * app_array) |
33.2.3
by Ted Gould
Set up the skeleton for determining state |
181 |
{
|
33.2.6
by Ted Gould
Fleshing out listing all the desktop files |
182 |
if (!g_str_has_suffix(name, ".desktop")) { |
183 |
return; |
|
184 |
}
|
|
185 |
||
175.5.1
by Ted Gould
Insert the new function to check |
186 |
if (!desktop_source_exists(dir, name)) { |
187 |
return; |
|
188 |
}
|
|
189 |
||
33.2.34
by Ted Gould
Instead of prefixing the files check to seeif the appids are valid |
190 |
gchar * appid = g_strdup(name); |
33.2.6
by Ted Gould
Fleshing out listing all the desktop files |
191 |
g_strstr_len(appid, -1, ".desktop")[0] = '\0'; |
192 |
||
33.2.34
by Ted Gould
Instead of prefixing the files check to seeif the appids are valid |
193 |
/* We only want valid APP IDs as desktop files */
|
194 |
if (!app_id_to_triplet(appid, NULL, NULL, NULL)) { |
|
195 |
g_free(appid); |
|
196 |
return; |
|
197 |
}
|
|
198 |
||
33.2.6
by Ted Gould
Fleshing out listing all the desktop files |
199 |
app_state_t * state = find_app_entry(appid, app_array); |
200 |
state->has_desktop = TRUE; |
|
33.2.39
by Ted Gould
Switching to modification time. |
201 |
state->desktop_modified = modified_time(dir, name); |
33.2.6
by Ted Gould
Fleshing out listing all the desktop files |
202 |
|
203 |
g_free(appid); |
|
33.2.3
by Ted Gould
Set up the skeleton for determining state |
204 |
return; |
205 |
}
|
|
206 |
||
207 |
/* Open a directory and look at all the entries */
|
|
208 |
void
|
|
33.2.22
by Ted Gould
Handle the case of creation time changing |
209 |
dir_for_each (const gchar * dirname, void(*func)(const gchar * dir, const gchar * name, GArray * app_array), GArray * app_array) |
33.2.3
by Ted Gould
Set up the skeleton for determining state |
210 |
{
|
33.2.4
by Ted Gould
Going through the directory entries |
211 |
GError * error = NULL; |
212 |
GDir * directory = g_dir_open(dirname, 0, &error); |
|
213 |
||
214 |
if (error != NULL) { |
|
215 |
g_warning("Unable to read directory '%s': %s", dirname, error->message); |
|
216 |
g_error_free(error); |
|
217 |
return; |
|
218 |
}
|
|
219 |
||
220 |
const gchar * filename = NULL; |
|
221 |
while ((filename = g_dir_read_name(directory)) != NULL) { |
|
33.2.22
by Ted Gould
Handle the case of creation time changing |
222 |
func(dirname, filename, app_array); |
33.2.4
by Ted Gould
Going through the directory entries |
223 |
}
|
224 |
||
225 |
g_dir_close(directory); |
|
33.2.3
by Ted Gould
Set up the skeleton for determining state |
226 |
return; |
227 |
}
|
|
228 |
||
51.1.7
by Ted Gould
Pull the recoverable error stuff into it's own function |
229 |
/* Code to report an error, so we can start tracking how important this is */
|
230 |
static void |
|
168.1.1
by Ted Gould
Support a field in our recoverable error and simplify the bucket |
231 |
report_recoverable_error (const gchar * app_id, const gchar * iconfield, const gchar * originalicon, const gchar * iconpath) |
51.1.7
by Ted Gould
Pull the recoverable error stuff into it's own function |
232 |
{
|
208.9.1
by Ted Gould
Switching to libwhoopsie for recoverable problem support |
233 |
const char * properties[9] = { |
234 |
"IconValue", NULL, |
|
235 |
"AppID", NULL, |
|
236 |
"IconPath", NULL, |
|
237 |
"IconField", NULL, |
|
51.1.7
by Ted Gould
Pull the recoverable error stuff into it's own function |
238 |
NULL
|
239 |
};
|
|
240 |
||
208.9.1
by Ted Gould
Switching to libwhoopsie for recoverable problem support |
241 |
properties[1] = originalicon; |
242 |
properties[3] = app_id; |
|
243 |
properties[5] = iconpath; |
|
244 |
properties[7] = iconfield; |
|
245 |
||
246 |
whoopsie_report_recoverable_problem("icon-path-unhandled", 0, TRUE, properties); |
|
51.1.7
by Ted Gould
Pull the recoverable error stuff into it's own function |
247 |
|
248 |
return; |
|
249 |
}
|
|
250 |
||
33.2.10
by Ted Gould
Add in the manifest parsing |
251 |
/* Function to take the source Desktop file and build a new
|
252 |
one with similar, but not the same data in it */
|
|
253 |
static void |
|
33.2.11
by Ted Gould
Parse the incomming desktop file |
254 |
copy_desktop_file (const gchar * from, const gchar * to, const gchar * appdir, const gchar * app_id) |
33.2.10
by Ted Gould
Add in the manifest parsing |
255 |
{
|
33.2.11
by Ted Gould
Parse the incomming desktop file |
256 |
GError * error = NULL; |
257 |
GKeyFile * keyfile = g_key_file_new(); |
|
258 |
g_key_file_load_from_file(keyfile, |
|
259 |
from, |
|
260 |
G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, |
|
261 |
&error); |
|
262 |
||
263 |
if (error != NULL) { |
|
264 |
g_warning("Unable to read the desktop file '%s' in the application directory: %s", from, error->message); |
|
265 |
g_error_free(error); |
|
266 |
g_key_file_unref(keyfile); |
|
267 |
return; |
|
268 |
}
|
|
269 |
||
51.1.1
by Ted Gould
Add some comments and make the code flow more clear |
270 |
/* Path Hanlding */
|
168.1.5
by Ted Gould
Path, Exec and App ID defines |
271 |
if (g_key_file_has_key(keyfile, DESKTOP_GROUP, PATH_KEY, NULL)) { |
272 |
gchar * oldpath = g_key_file_get_string(keyfile, DESKTOP_GROUP, PATH_KEY, NULL); |
|
168.1.6
by Ted Gould
Cleaning up and hadding an old key prefix |
273 |
g_debug("Desktop file '%s' has a Path set to '%s'. Setting as " OLD_KEY_PREFIX PATH_KEY ".", from, oldpath); |
33.2.11
by Ted Gould
Parse the incomming desktop file |
274 |
|
168.1.6
by Ted Gould
Cleaning up and hadding an old key prefix |
275 |
g_key_file_set_string(keyfile, DESKTOP_GROUP, OLD_KEY_PREFIX PATH_KEY, oldpath); |
33.2.11
by Ted Gould
Parse the incomming desktop file |
276 |
|
277 |
g_free(oldpath); |
|
278 |
}
|
|
279 |
||
168.1.5
by Ted Gould
Path, Exec and App ID defines |
280 |
g_key_file_set_string(keyfile, DESKTOP_GROUP, PATH_KEY, appdir); |
33.2.11
by Ted Gould
Parse the incomming desktop file |
281 |
|
51.1.9
by Ted Gould
Typo in comment |
282 |
/* Icon Handling */
|
168.1.4
by Ted Gould
Desktop group in define |
283 |
if (g_key_file_has_key(keyfile, DESKTOP_GROUP, ICON_KEY, NULL)) { |
284 |
gchar * originalicon = g_key_file_get_string(keyfile, DESKTOP_GROUP, ICON_KEY, NULL); |
|
51.1.3
by Ted Gould
If we can make things better, let's do! |
285 |
gchar * iconpath = g_build_filename(appdir, originalicon, NULL); |
286 |
||
287 |
/* If the icon in the path exists, let's use that */
|
|
288 |
if (g_file_test(iconpath, G_FILE_TEST_EXISTS)) { |
|
168.1.4
by Ted Gould
Desktop group in define |
289 |
g_key_file_set_string(keyfile, DESKTOP_GROUP, ICON_KEY, iconpath); |
51.1.3
by Ted Gould
If we can make things better, let's do! |
290 |
/* Save the old value, because, debugging */
|
168.1.6
by Ted Gould
Cleaning up and hadding an old key prefix |
291 |
g_key_file_set_string(keyfile, DESKTOP_GROUP, OLD_KEY_PREFIX ICON_KEY, originalicon); |
51.1.3
by Ted Gould
If we can make things better, let's do! |
292 |
} else { |
293 |
/* So here we are, realizing all is lost. Let's file a bug. */
|
|
51.1.4
by Ted Gould
Setting up the basis for our recoverable error |
294 |
/* The goal here is to realize how often this case is, so we know how to prioritize fixing it */
|
51.1.6
by Ted Gould
Pipe directly |
295 |
|
168.1.3
by Ted Gould
Make desktop keys into defines |
296 |
report_recoverable_error(app_id, ICON_KEY, originalicon, iconpath); |
51.1.3
by Ted Gould
If we can make things better, let's do! |
297 |
}
|
298 |
||
299 |
g_free(iconpath); |
|
300 |
g_free(originalicon); |
|
301 |
}
|
|
302 |
||
168.1.2
by Ted Gould
Add handling for our symbolic icon just like our icon handling |
303 |
/* SymbolicIcon Handling */
|
168.1.4
by Ted Gould
Desktop group in define |
304 |
if (g_key_file_has_key(keyfile, DESKTOP_GROUP, SYMBOLIC_ICON_KEY, NULL)) { |
305 |
gchar * originalicon = g_key_file_get_string(keyfile, DESKTOP_GROUP, SYMBOLIC_ICON_KEY, NULL); |
|
168.1.2
by Ted Gould
Add handling for our symbolic icon just like our icon handling |
306 |
gchar * iconpath = g_build_filename(appdir, originalicon, NULL); |
307 |
||
308 |
/* If the icon in the path exists, let's use that */
|
|
309 |
if (g_file_test(iconpath, G_FILE_TEST_EXISTS)) { |
|
168.1.4
by Ted Gould
Desktop group in define |
310 |
g_key_file_set_string(keyfile, DESKTOP_GROUP, SYMBOLIC_ICON_KEY, iconpath); |
168.1.2
by Ted Gould
Add handling for our symbolic icon just like our icon handling |
311 |
/* Save the old value, because, debugging */
|
168.1.6
by Ted Gould
Cleaning up and hadding an old key prefix |
312 |
g_key_file_set_string(keyfile, DESKTOP_GROUP, OLD_KEY_PREFIX SYMBOLIC_ICON_KEY, originalicon); |
168.1.2
by Ted Gould
Add handling for our symbolic icon just like our icon handling |
313 |
} else { |
314 |
/* So here we are, realizing all is lost. Let's file a bug. */
|
|
315 |
/* The goal here is to realize how often this case is, so we know how to prioritize fixing it */
|
|
316 |
||
168.1.3
by Ted Gould
Make desktop keys into defines |
317 |
report_recoverable_error(app_id, SYMBOLIC_ICON_KEY, originalicon, iconpath); |
168.1.2
by Ted Gould
Add handling for our symbolic icon just like our icon handling |
318 |
}
|
319 |
||
320 |
g_free(iconpath); |
|
321 |
g_free(originalicon); |
|
322 |
}
|
|
323 |
||
51.1.1
by Ted Gould
Add some comments and make the code flow more clear |
324 |
/* Exec Handling */
|
325 |
gchar * oldexec = desktop_to_exec(keyfile, from); |
|
326 |
if (oldexec == NULL) { |
|
327 |
g_key_file_unref(keyfile); |
|
328 |
return; |
|
329 |
}
|
|
330 |
||
46.1.1
by Jamie Strandboge
application-legacy.conf.in: use aa-exec-click instead of aa-exec |
331 |
gchar * newexec = g_strdup_printf("aa-exec-click -p %s -- %s", app_id, oldexec); |
168.1.5
by Ted Gould
Path, Exec and App ID defines |
332 |
g_key_file_set_string(keyfile, DESKTOP_GROUP, EXEC_KEY, newexec); |
33.2.11
by Ted Gould
Parse the incomming desktop file |
333 |
g_free(newexec); |
334 |
g_free(oldexec); |
|
335 |
||
51.1.1
by Ted Gould
Add some comments and make the code flow more clear |
336 |
/* Adding an Application ID */
|
168.1.5
by Ted Gould
Path, Exec and App ID defines |
337 |
g_key_file_set_string(keyfile, DESKTOP_GROUP, APP_ID_KEY, app_id); |
33.2.33
by Ted Gould
Adding the application ID, perhaps for later |
338 |
|
175.5.2
by Ted Gould
Putting the built key into the cache desktop file |
339 |
/* Adding the source file path */
|
340 |
g_key_file_set_string(keyfile, DESKTOP_GROUP, SOURCE_FILE_KEY, from); |
|
341 |
||
51.1.1
by Ted Gould
Add some comments and make the code flow more clear |
342 |
/* Output */
|
33.2.12
by Ted Gould
Write out the final built desktop file |
343 |
gsize datalen = 0; |
344 |
gchar * data = g_key_file_to_data(keyfile, &datalen, &error); |
|
345 |
g_key_file_unref(keyfile); |
|
346 |
||
347 |
if (error != NULL) { |
|
348 |
g_warning("Unable serialize keyfile built from '%s': %s", from, error->message); |
|
349 |
g_error_free(error); |
|
350 |
return; |
|
351 |
}
|
|
352 |
||
353 |
g_file_set_contents(to, data, datalen, &error); |
|
354 |
g_free(data); |
|
355 |
||
356 |
if (error != NULL) { |
|
357 |
g_warning("Unable to write out desktop file to '%s': %s", to, error->message); |
|
358 |
g_error_free(error); |
|
359 |
return; |
|
360 |
}
|
|
33.2.10
by Ted Gould
Add in the manifest parsing |
361 |
|
362 |
return; |
|
363 |
}
|
|
364 |
||
33.2.7
by Ted Gould
Set up for the handling of each app ID |
365 |
/* Build a desktop file in the user's home directory */
|
366 |
static void |
|
367 |
build_desktop_file (app_state_t * state, const gchar * symlinkdir, const gchar * desktopdir) |
|
368 |
{
|
|
33.2.29
by Ted Gould
Get the directory from click |
369 |
GError * error = NULL; |
370 |
gchar * package = NULL; |
|
33.2.9
by Ted Gould
Get all of the file name stuff out of the way and build up to parsing the manifest |
371 |
/* 'Parse' the App ID */
|
33.2.29
by Ted Gould
Get the directory from click |
372 |
if (!app_id_to_triplet(state->app_id, &package, NULL, NULL)) { |
373 |
return; |
|
374 |
}
|
|
375 |
||
175.5.7
by Ted Gould
Click DB and user database setup and testing |
376 |
/* Read in the database */
|
377 |
ClickDB * db = click_db_new(); |
|
378 |
click_db_read(db, g_getenv("TEST_CLICK_DB"), &error); |
|
379 |
if (error != NULL) { |
|
380 |
g_warning("Unable to read Click database: %s", error->message); |
|
381 |
g_error_free(error); |
|
382 |
g_free(package); |
|
383 |
g_object_unref(db); |
|
384 |
return; |
|
385 |
}
|
|
386 |
||
33.2.30
by Ted Gould
Make sure to clear the final newline |
387 |
/* Check click to find out where the files are */
|
175.5.7
by Ted Gould
Click DB and user database setup and testing |
388 |
ClickUser * user = click_user_new_for_user(db, g_getenv("TEST_CLICK_USER"), &error); |
389 |
g_object_unref(db); |
|
175.5.19
by Ted Gould
Move unref so that there's only one, error or not. |
390 |
if (error != NULL) { |
391 |
g_warning("Unable to read Click database: %s", error->message); |
|
392 |
g_error_free(error); |
|
393 |
g_free(package); |
|
394 |
return; |
|
395 |
}
|
|
175.5.7
by Ted Gould
Click DB and user database setup and testing |
396 |
|
135.2.2
by Colin Watson
Use libclick to get the package directory, saving about 0.7 seconds from Click application startup. |
397 |
gchar * pkgdir = click_user_get_path(user, package, &error); |
398 |
if (error != NULL) { |
|
399 |
g_warning("Unable to get the Click package directory for %s: %s", package, error->message); |
|
400 |
g_error_free(error); |
|
401 |
g_free(package); |
|
402 |
return; |
|
403 |
}
|
|
404 |
g_object_unref(user); |
|
33.2.29
by Ted Gould
Get the directory from click |
405 |
g_free(package); |
406 |
||
135.2.2
by Colin Watson
Use libclick to get the package directory, saving about 0.7 seconds from Click application startup. |
407 |
if (!g_file_test(pkgdir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { |
408 |
g_warning("Directory returned by click '%s' couldn't be found", pkgdir); |
|
409 |
g_free(pkgdir); |
|
410 |
return; |
|
411 |
}
|
|
412 |
||
413 |
gchar * indesktop = manifest_to_desktop(pkgdir, state->app_id); |
|
33.2.17
by Ted Gould
Move the json handling into the helper file |
414 |
if (indesktop == NULL) { |
135.2.2
by Colin Watson
Use libclick to get the package directory, saving about 0.7 seconds from Click application startup. |
415 |
g_free(pkgdir); |
33.2.17
by Ted Gould
Move the json handling into the helper file |
416 |
return; |
417 |
}
|
|
33.2.9
by Ted Gould
Get all of the file name stuff out of the way and build up to parsing the manifest |
418 |
|
419 |
/* Determine the desktop file name */
|
|
33.2.34
by Ted Gould
Instead of prefixing the files check to seeif the appids are valid |
420 |
gchar * desktopfile = g_strdup_printf("%s.desktop", state->app_id); |
33.2.9
by Ted Gould
Get all of the file name stuff out of the way and build up to parsing the manifest |
421 |
gchar * desktoppath = g_build_filename(desktopdir, desktopfile, NULL); |
422 |
g_free(desktopfile); |
|
423 |
||
135.2.2
by Colin Watson
Use libclick to get the package directory, saving about 0.7 seconds from Click application startup. |
424 |
copy_desktop_file(indesktop, desktoppath, pkgdir, state->app_id); |
33.2.9
by Ted Gould
Get all of the file name stuff out of the way and build up to parsing the manifest |
425 |
|
426 |
g_free(desktoppath); |
|
33.2.17
by Ted Gould
Move the json handling into the helper file |
427 |
g_free(indesktop); |
135.2.2
by Colin Watson
Use libclick to get the package directory, saving about 0.7 seconds from Click application startup. |
428 |
g_free(pkgdir); |
33.2.15
by Ted Gould
Move the app id checking to the helpers file |
429 |
|
33.2.7
by Ted Gould
Set up for the handling of each app ID |
430 |
return; |
431 |
}
|
|
432 |
||
433 |
/* Remove the desktop file from the user's home directory */
|
|
33.2.38
by Ted Gould
Checking to see if we did remove the desktop file before trying to build another one. |
434 |
static gboolean |
33.2.7
by Ted Gould
Set up for the handling of each app ID |
435 |
remove_desktop_file (app_state_t * state, const gchar * desktopdir) |
436 |
{
|
|
33.2.34
by Ted Gould
Instead of prefixing the files check to seeif the appids are valid |
437 |
gchar * desktopfile = g_strdup_printf("%s.desktop", state->app_id); |
33.2.8
by Ted Gould
Get the removal code under control |
438 |
gchar * desktoppath = g_build_filename(desktopdir, desktopfile, NULL); |
439 |
g_free(desktopfile); |
|
440 |
||
33.2.35
by Ted Gould
Checking to make sure the desktop has the application id set before deleting it. |
441 |
GKeyFile * keyfile = g_key_file_new(); |
442 |
g_key_file_load_from_file(keyfile, |
|
443 |
desktoppath, |
|
444 |
G_KEY_FILE_NONE, |
|
445 |
NULL); |
|
446 |
||
168.1.5
by Ted Gould
Path, Exec and App ID defines |
447 |
if (!g_key_file_has_key(keyfile, DESKTOP_GROUP, APP_ID_KEY, NULL)) { |
33.2.35
by Ted Gould
Checking to make sure the desktop has the application id set before deleting it. |
448 |
g_debug("Desktop file '%s' is not one created by us.", desktoppath); |
449 |
g_key_file_unref(keyfile); |
|
450 |
g_free(desktoppath); |
|
33.2.38
by Ted Gould
Checking to see if we did remove the desktop file before trying to build another one. |
451 |
return FALSE; |
33.2.35
by Ted Gould
Checking to make sure the desktop has the application id set before deleting it. |
452 |
}
|
453 |
g_key_file_unref(keyfile); |
|
454 |
||
33.2.8
by Ted Gould
Get the removal code under control |
455 |
if (g_unlink(desktoppath) != 0) { |
456 |
g_warning("Unable to delete desktop file: %s", desktoppath); |
|
457 |
}
|
|
458 |
||
459 |
g_free(desktoppath); |
|
33.2.7
by Ted Gould
Set up for the handling of each app ID |
460 |
|
33.2.38
by Ted Gould
Checking to see if we did remove the desktop file before trying to build another one. |
461 |
return TRUE; |
33.2.7
by Ted Gould
Set up for the handling of each app ID |
462 |
}
|
463 |
||
33.2.4
by Ted Gould
Going through the directory entries |
464 |
/* The main function */
|
33.2.2
by Ted Gould
Adding a desktop hook binary |
465 |
int
|
466 |
main (int argc, char * argv[]) |
|
467 |
{
|
|
33.2.3
by Ted Gould
Set up the skeleton for determining state |
468 |
if (argc != 1) { |
469 |
g_error("Shouldn't have arguments"); |
|
470 |
return 1; |
|
471 |
}
|
|
472 |
||
473 |
GArray * apparray = g_array_new(FALSE, FALSE, sizeof(app_state_t)); |
|
474 |
||
33.2.27
by Ted Gould
Change the name of the symlink |
475 |
/* Find all the symlinks of desktop files */
|
152.1.6
by Ted Gould
Removing more instances if 'upstart' to not confuse people, leaving the tracepoints for now |
476 |
gchar * symlinkdir = g_build_filename(g_get_user_cache_dir(), "ubuntu-app-launch", "desktop", NULL); |
33.2.3
by Ted Gould
Set up the skeleton for determining state |
477 |
if (!g_file_test(symlinkdir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { |
144.1.1
by Ted Gould
Debug message for valid, though rare, conditions. |
478 |
g_debug("No installed click packages"); |
33.2.3
by Ted Gould
Set up the skeleton for determining state |
479 |
} else { |
480 |
dir_for_each(symlinkdir, add_click_package, apparray); |
|
481 |
}
|
|
482 |
||
33.2.7
by Ted Gould
Set up for the handling of each app ID |
483 |
/* Find all the click desktop files */
|
33.2.3
by Ted Gould
Set up the skeleton for determining state |
484 |
gchar * desktopdir = g_build_filename(g_get_user_data_dir(), "applications", NULL); |
33.2.23
by Ted Gould
Handle making sure the application dir exists |
485 |
gboolean desktopdirexists = FALSE; |
44.2.1
by Ted Gould
Making sure to look for the application directory |
486 |
if (!g_file_test(desktopdir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { |
144.1.1
by Ted Gould
Debug message for valid, though rare, conditions. |
487 |
g_debug("No applications defined"); |
33.2.3
by Ted Gould
Set up the skeleton for determining state |
488 |
} else { |
489 |
dir_for_each(desktopdir, add_desktop_file, apparray); |
|
33.2.23
by Ted Gould
Handle making sure the application dir exists |
490 |
desktopdirexists = TRUE; |
33.2.3
by Ted Gould
Set up the skeleton for determining state |
491 |
}
|
33.2.2
by Ted Gould
Adding a desktop hook binary |
492 |
|
33.2.7
by Ted Gould
Set up for the handling of each app ID |
493 |
/* Process the merge */
|
494 |
int i; |
|
495 |
for (i = 0; i < apparray->len; i++) { |
|
496 |
app_state_t * state = &g_array_index(apparray, app_state_t, i); |
|
497 |
g_debug("Processing App ID: %s", state->app_id); |
|
498 |
||
499 |
if (state->has_click && state->has_desktop) { |
|
33.2.39
by Ted Gould
Switching to modification time. |
500 |
if (state->click_modified > state->desktop_modified) { |
33.2.22
by Ted Gould
Handle the case of creation time changing |
501 |
g_debug("\tClick updated more recently"); |
502 |
g_debug("\tRemoving desktop file"); |
|
33.2.38
by Ted Gould
Checking to see if we did remove the desktop file before trying to build another one. |
503 |
if (remove_desktop_file(state, desktopdir)) { |
504 |
g_debug("\tBuilding desktop file"); |
|
505 |
build_desktop_file(state, symlinkdir, desktopdir); |
|
506 |
}
|
|
33.2.22
by Ted Gould
Handle the case of creation time changing |
507 |
} else { |
508 |
g_debug("\tAlready synchronized"); |
|
509 |
}
|
|
33.2.7
by Ted Gould
Set up for the handling of each app ID |
510 |
} else if (state->has_click) { |
33.2.23
by Ted Gould
Handle making sure the application dir exists |
511 |
if (!desktopdirexists) { |
33.2.24
by Ted Gould
Bad permissions for directories |
512 |
if (g_mkdir_with_parents(desktopdir, 0755) == 0) { |
33.2.23
by Ted Gould
Handle making sure the application dir exists |
513 |
g_debug("\tCreated applications directory"); |
514 |
desktopdirexists = TRUE; |
|
515 |
} else { |
|
516 |
g_warning("\tUnable to create applications directory"); |
|
517 |
}
|
|
518 |
}
|
|
519 |
if (desktopdirexists) { |
|
520 |
g_debug("\tBuilding desktop file"); |
|
521 |
build_desktop_file(state, symlinkdir, desktopdir); |
|
522 |
}
|
|
33.2.7
by Ted Gould
Set up for the handling of each app ID |
523 |
} else if (state->has_desktop) { |
524 |
g_debug("\tRemoving desktop file"); |
|
525 |
remove_desktop_file(state, desktopdir); |
|
526 |
}
|
|
527 |
||
528 |
g_free(state->app_id); |
|
529 |
}
|
|
530 |
||
531 |
g_array_free(apparray, TRUE); |
|
532 |
g_free(desktopdir); |
|
533 |
g_free(symlinkdir); |
|
33.2.2
by Ted Gould
Adding a desktop hook binary |
534 |
|
535 |
return 0; |
|
536 |
}
|