1 /*
2 * Copyright (C) 2002-2011 Edscott Wilson Garcia
3 * EMail: edscott@imp.mx
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program;
17 */
18
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include "rodent.h"
25 #include "rfm_modules.h"
26
27 /* this should be first 2 lines after headers: */
28 G_MODULE_EXPORT LIBRFM_MODULE
29
30 #define MODULE_NAME "dotdesktop"
31 #define SUBMODULE_NAME "dotdesktop"
32 #define MODULE_LABEL _("Application Launcher...")
33 //#define MODULE_ICON_ID "xffm/places_folder-system"
34 #define MODULE_ENTRY_TIP _("Next-generation application launcher.")
35
36 #include "module-skeleton.h"
37 // Skeleton definitions
38
RFM_MODULE_PAUSE(NULL)39 G_MODULE_EXPORT RFM_MODULE_PAUSE(NULL)
40 G_MODULE_EXPORT RFM_MONITOR_RELOAD(NULL)
41
42 G_MODULE_EXPORT RFM_BLOCKING_LOAD(TRUE)
43 G_MODULE_EXPORT RFM_MODULE_NAME
44 G_MODULE_EXPORT RFM_SUBMODULE_NAME
45 G_MODULE_EXPORT RFM_MODULE_LABEL
46 //G_MODULE_EXPORT RFM_MODULE_ICON_ID
47 G_MODULE_EXPORT RFM_MODULE_ENTRY_TIP
48
49 //Not applicable:
50 //G_MODULE_EXPORT RFM_MODULE_PREFERENCES_KEY("RODENT-DOTD");
51 G_MODULE_EXPORT RFM_IS_ROOT_MODULE(TRUE)
52 //Superceded:
53 //G_MODULE_EXPORT RFM_PLUGIN_INFO(_(""))
54 G_MODULE_EXPORT RFM_MODULE_ACTIVE(TRUE)
55 G_MODULE_EXPORT RFM_MODULE_MONITOR(TRUE)
56 //
57 G_MODULE_EXPORT RFM_IS_SELECTABLE(TRUE)
58
59 #include "dotdesktop-module.i"
60
61
62 G_MODULE_EXPORT
63 void *
64 module_icon_id(void){
65 // this is the module root item
66 static gchar *icon=NULL;
67 if (icon == NULL){
68 icon = g_strdup_printf("%s/pixmaps/rodent-dotdesktop.svg", PACKAGE_DATA_DIR);
69 }
70 return icon;
71 }
72
73 ////////////// General gmodule initialization function
74
75 G_MODULE_EXPORT void *
g_module_check_init(GModule * module)76 g_module_check_init (GModule * module) {
77 BIND_TEXT_DOMAIN;
78 //NOOP("dotdesktop init... \n");
79 if (!glob_signal) rfm_cond_init(glob_signal);
80
81 if(!glob_mutex) {
82 rfm_mutex_init(glob_mutex);
83 }
84
85 icon_hash = g_hash_table_new_full (g_str_hash, g_str_equal,g_free, g_free);
86 icon_exec_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
87 category_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
88
89 reverse_string_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
90 string_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
91
92 dotdesktop_t *qq=dotdesktop_v;
93 GMutex *string_hash_mutex = get_string_hash_mutex();
94 for (; qq && qq->category; qq++){
95 if (qq->string != NULL) {
96 g_mutex_lock(string_hash_mutex);
97 g_hash_table_replace(string_hash, g_strdup(qq->category), g_strdup(qq->string));
98 g_mutex_unlock(string_hash_mutex);
99 }
100 }
101
102 rfm_view_thread_create(NULL, glob_dir_f, NULL, "glob_dir_f");
103 rfm_view_thread_create(NULL, populate_icon_hash_f, NULL, "populate_icon_hash_f");
104 rfm_view_thread_create(NULL, populate_mimetype_hash_f, NULL, "populate_mimetype_hash_f");
105 // This thread requires a termination signal from janitor.
106 rfm_view_thread_create (NULL, monitor_f, NULL, "monitor_f:dotdesktop");
107 return NULL;
108 }
109
110 G_MODULE_EXPORT void
g_module_unload(GModule * module)111 g_module_unload(GModule * module){
112 unload_module = TRUE;
113 rfm_global_t *rfm_global_p = rfm_global();
114 g_cond_signal(rfm_global_p->status_signal);
115 g_hash_table_destroy(icon_hash);
116 g_hash_table_destroy(icon_exec_hash);
117 g_hash_table_destroy(category_hash);
118 g_hash_table_destroy(reverse_string_hash);
119 g_hash_table_destroy(string_hash);
120 }
121 //
122 ////////////// Generalized Root Module functions ///////////////////
123 //
124
125 // Plugin functions. Plugin functions may be specified as one of the
126 // following types.
127 //
128 // void: These functions all return a void pointer
129 // and take no argument
130 // natural: These functions all return a void pointer
131 // and take a single void pointer argument.
132 // The space of natural functions is isomorphic
133 // to the set of natural numbers.
134 // rational: These functions all return a void pointer
135 // and take a two void pointer arguments.
136 // The space of rational functions is isomorphic
137 // to the set of rational numbers.
138 // complex: These functions all return a void pointer
139 // and take a three void pointer arguments.
140 // The space of rational functions is isomorphic
141 // to the set of complex numbers with integer
142 // imaginary component.
143
144
145 //////////////////////////////////////////////////////////////////////
146 // void functions //
147 //////////////////////////////////////////////////////////////////////
148
149
150
151 // gchar *
152 // This function returns a newly allocated string with the general information
153 // of the module. Rodent uses this to construct the popup tip. Returned value
154 // should be freed when no longer used.
155 G_MODULE_EXPORT
156 void *
plugin_info(void)157 plugin_info(void){
158 return g_strdup_printf("%s:\n%s\n",
159 _("Browse and run installed applications"),
160 _("This program is responsible for launching other applications and provides useful utilities."));
161 }
162
163
164 //////////////////////////////////////////////////////////////////////
165 // natural functions //
166 //////////////////////////////////////////////////////////////////////
167
168 // gint
169 // This function returns the count of elements in the module's
170 // view. This value is compared with current value to determine
171 // whether a reload is necessary.
172 // Returns READ_ERROR on skip unconditional reload
173 // Parameter p is the view's widgets_p.
174 G_MODULE_EXPORT
175 void *
module_count(void * p)176 module_count (void *p) {
177 static gint count=0;
178 widgets_t *widgets_p = p;
179 gint serial=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widgets_p->paper), "dotdesktop_serial"));
180 if (serial == desktop_serial){
181 return GINT_TO_POINTER (READ_ERROR);
182 }
183 g_object_set_data(G_OBJECT(widgets_p->paper), "dotdesktop_serial", GINT_TO_POINTER(desktop_serial));
184 return GINT_TO_POINTER (count++);
185 }
186
187 // gboolean
188 // This function processes the double click action on the
189 // icon's label. If it returns FALSE, then the default
190 // Rodent action for label click is performed. The default
191 // Rodent action checks for file existance to do a rename
192 // entry (or symlink or duplicate).
193 // Parameter p is the item's entry pointer.
194 G_MODULE_EXPORT
label_click(void * p)195 void *label_click (void *p) {
196 // Do nothing.
197 record_entry_t *en=p;
198 if (en && en->mimetype && strcmp(en->mimetype, "application/x-desktop")==0){
199 // do default Rodent action (rename/duplicate/link)
200 // nah! Problem with updating, since items are not currently
201 // monitored
202 // return NULL;
203 }
204 // Do nothing
205 return GINT_TO_POINTER(1);
206 }
207
208
209 // const gchar *
210 // This function returns a const pointer to the entry's icon
211 // identifier.
212 // Parameter p is the item's entry pointer.
213 // Identifier may be returned as a mimetype or an absolute path.
214 G_MODULE_EXPORT
item_icon_id(void * p)215 void *item_icon_id(void *p){
216 return dotdesktop_item_icon_id(p);
217 }
218
219 // gchar *
220 // This function returns a newly allocated string with the general information
221 // of the entry (parameter p). Rodent uses this to construct the popup tip.
222 // Returned value should be freed when no longer used.
223 G_MODULE_EXPORT
224 void *
item_entry_tip(void * p)225 item_entry_tip(void *p){
226 return dotdesktop_entry_tip(p);
227 }
228
229 // gboolean
230 // This function informs Rodent if the entry (parameter p) is a
231 // selectable icon or not.
232 /*G_MODULE_EXPORT
233 void *
234 is_selectable(void *p){
235 record_entry_t *en=(record_entry_t *)p;
236 if (rfm_g_file_test(en->path, G_FILE_TEST_EXISTS)){
237 return GINT_TO_POINTER(1);
238 }
239 return NULL;
240 }*/
241
242 // gboolean
243 // This function informs Rodent if the entry (parameter p) is a
244 // valid drop site. Drop may be processed by Rodent or by the
245 // module if process_drop() is defined.
246 G_MODULE_EXPORT
247 void *
valid_drop_site(void * p)248 valid_drop_site(void *p){
249 record_entry_t *en=p;
250 if (en && en->mimetype && strcmp(en->mimetype, "application/x-desktop")==0){
251 // Dotdesktop files will be valid drop sites.
252 return GINT_TO_POINTER(1);
253 }
254 // Anything else is not a valid drop site.
255 return NULL;
256 }
257
258
259 // gboolean
260 // This function fills in previously allocated xfdir_p
261 // with glob records and entries of the module population.
262 // Records which are filled in are:
263 // xfdir_p->pathc: Number of icons for Rodent to display
264 // xfdir_p->gl[0 ... pathc-1].pathv: Labels to display with each icon
265 // xfdir_p->gl[0 ... pathc-1].en: Record_entry_t of each icon
266 // (NULL entries will point to Rodent root)
267 G_MODULE_EXPORT
268 void *
module_xfdir_get(void * p)269 module_xfdir_get (void *p) {
270 xfdir_t *xfdir_p = p;
271 return private_get_xfdir(xfdir_p);
272
273 }
274
275 // gboolean
276 // This is a dotdesktop specific function.
277 // The function informs Rodent if the execution of the dotdesktop
278 // file is to be done in a terminal emulator.
279 // This flag is set within the dotdesktop file.
280 G_MODULE_EXPORT
exec_in_terminal(void * p)281 void *exec_in_terminal(void *p){
282 gchar *path=p;
283 gboolean in_terminal=get_desktop_bool("Terminal", path);
284 return (GINT_TO_POINTER(in_terminal));
285 }
286
287 // gchar *
288 // This is a dotdesktop specific function.
289 // This function returns a newly allocated string with the "Exec" command
290 // of the dotdesktop file. Rodent uses this command to spawn a
291 // background process.
292 // Returned value should be freed when no longer used.
293 // Parameter p is the path to the file.
294 // This variable is set within the dotdesktop file.
295 G_MODULE_EXPORT
item_exec(void * p)296 void *item_exec(void *p){
297 gchar *path=p;
298 if (!path) return NULL;
299 gchar *exec=get_desktop_string("Exec", path);
300 return (void *) exec;
301 }
302
303 // gchar *
304 // This is a dotdesktop specific function.
305 // This function returns a newly allocated string with the "Name"
306 // of the dotdesktop file. Rodent uses this command to create
307 // popup menu item for files with "aaplication/x-desktop" mimetype.
308 //
309 // Returned value should be freed when no longer used.
310 // Parameter p is the path to the file.
311 // This variable is set within the dotdesktop file.
312 G_MODULE_EXPORT
item_name(void * p)313 void *item_name(void *p){
314 gchar *path=p;
315 if (!path) return NULL;
316 gchar *name=get_desktop_string("Name", path);
317 return (void *) name;
318 }
319
320 // gchar *
321 // This is a dotdesktop specific function.
322 // This function returns a newly allocated string with the "TryExec" command
323 // of the dotdesktop file. Rodent uses this command if "Exec" is not found
324 // in the dotdesktop file to spawn a background process.
325 // Returned value should be freed when no longer used.
326 // This variable is set within the dotdesktop file.
327 G_MODULE_EXPORT
item_tryexec(void * p)328 void *item_tryexec(void *p){
329 gchar *path=p;
330 gchar *exec=get_desktop_string("TryExec", path);
331 return (void *) exec;
332 }
333
334 // const gchar
335 // This function is used to get the icon associated to
336 // a particular exec defined in any one of the globbed
337 // dot desktop files.
338 G_MODULE_EXPORT
339 void *
get_exec_icon(void * p)340 get_exec_icon(void *p)
341 {
342 GMutex *exec_hash_mutex = get_exec_hash_mutex();
343 const gchar *exec = p;
344 gchar *hash_key = get_hash_key(exec);
345 g_mutex_lock(exec_hash_mutex);
346 const gchar *iconpath = g_hash_table_lookup (icon_exec_hash, hash_key);
347 g_mutex_unlock(exec_hash_mutex);
348 g_free(hash_key);
349 return (void *)iconpath;
350 }
351
352 //////////////////////////////////////////////////////////////////////
353 // rational functions //
354 //////////////////////////////////////////////////////////////////////
355 // gboolean
356 // This function is used to hide popup menu elements of
357 // Rodent's standard icon area popup menu.
358 // Parameter p is the view's widgets_p pointer.
359 // Parameter q is the icon's record entry.
360 G_MODULE_EXPORT
361 void *
hide_local_menu_items(void * p,void * q)362 hide_local_menu_items (void *p, void *q) {
363 return dotdesktop_hide_local_menu_items(p, q);
364 }
365
366 // gboolean
367 // This function informs Rodent by returning TRUE that the double click
368 // action will be processed by the module. If function returns FALSE
369 // (or is not defined in the module) then Rodent will attempt the default
370 // double click action.
371 // Parameter p is the view's widgets_p pointer.
372 // Parameter q is the icon's record entry.
373 G_MODULE_EXPORT
374 void *
double_click(void * p,void * q)375 double_click(void *p, void *q){
376 return dotdesktop_double_click(p, q);
377 }
378
379 // gboolean
380 // This function is to generate a module specific popup menu, either on
381 // icon click or on void space click .
382 // If this function will generate a popup menu, return value should be TRUE,
383 // otherwise return FALSE so Rodent will generate the default popup menu.
384 // Popup menu for modules should be set as view data on the paper object
385 // identified by "private_popup_menu".
386 // Parameter p is the view's widgets_p pointer.
387 // Parameter q is the icon's record entry.
388 G_MODULE_EXPORT
389 void *
private_popup(void * p,void * q)390 private_popup(void *p, void *q){
391 if (!q) return NULL;
392 // no popup menu for module items...
393 record_entry_t *en = q;
394 gchar *text;
395 if (rfm_g_file_test(en->path, G_FILE_TEST_EXISTS)){
396 gchar *name=get_desktop_string("Name",en->path);
397 gchar *generic_name=get_desktop_string("GenericName",en->path);
398 gchar *exec=get_desktop_string("Exec",en->path);
399 gchar *comment=get_desktop_string("Comment",en->path);
400 gboolean in_term=get_desktop_bool("Terminal",en->path);
401
402 text = g_strconcat(
403 "<big><b>",name,"</b></big>\n",
404 (generic_name)?"<i>(":"",
405 (generic_name)?generic_name:"",
406 (generic_name)?")</i>\n\n":"",
407 (comment)?comment:"",
408 (comment)?"\n\n":"",
409 _("Command to run when clicked:"), " ", exec, "\n\n",
410 _("Terminal application"), ": ", (in_term)?_("Yes"):_("No"),
411 NULL);
412 g_free(name);
413 g_free(generic_name);
414 g_free(exec);
415 g_free(comment);
416 } else {
417 text = g_strdup_printf("<big><b>%s</b></big>\n\n%s <b><i>%s</i></b>",
418 MODULE_ENTRY_TIP, _("Group"), (en->tag)?en->tag:en->path);
419 }
420 rfm_confirm(p, GTK_MESSAGE_INFO, text, NULL, NULL);
421 g_free(text);
422 return GINT_TO_POINTER(1);
423 }
424
425 // gchar *
426 // This function returns a newly allocated string which shall
427 // be used by Rodent to complement the initial text which
428 // appears in the status area (lp command area).
429 // Returned value should be freed when no longer used.
430 // Parameter p is the view's widgets_p pointer.
431 // Parameter q is the icon's record entry.
432 G_MODULE_EXPORT
433 void *
sizetag(void * p,void * q)434 sizetag(void *p, void *q){
435 //widgets_t *widgets_p=p;
436 record_entry_t *en=q;
437 if (en && en->st == NULL){
438 return g_strdup(_("List of categories"));
439 } else {
440 return g_strdup(_("Browse and run installed applications"));
441 }
442 }
443
444 //////////////////////////////////////////////////////////////////////
445 // complex functions //
446 //////////////////////////////////////////////////////////////////////
447
448 // gboolean
449 // This function is used by Rodent to process a drop to a module defined
450 // icon. Drop is only processed if valid_drop_site() returned TRUE
451 // for the drop target entry beforehand.
452 // Parameter p is the view's widgets_p pointer.
453 // Parameter q is path of the drop target entry.
454 // Parameter r is a GList * that contains the drop element paths.
455 G_MODULE_EXPORT
456 void *
process_drop(void * p,void * q,void * r)457 process_drop(void *p, void *q, void *r){
458 widgets_t *widgets_p=p;
459 gchar *path=q;
460 GList *list=r;
461 execute_dot_desktop(widgets_p, path, list);
462 return GINT_TO_POINTER(1);
463 }
464
465 static void *
thread_applications_menu_f(gpointer data)466 thread_applications_menu_f(gpointer data){
467 NOOP(stderr,"thread_applications_menu now\n");
468
469 const gchar *parent_id = "applications_menu";
470 const gchar *menu_id = "applications_menu_menu";
471 GtkWidget *parent=rfm_get_widget(parent_id);
472 GtkWidget *popup_widget=rfm_get_widget(menu_id);
473 GtkWidget *old_popup= popup_widget;
474 g_object_ref(old_popup);
475
476 popup_widget = gtk_menu_new ();
477 gtk_widget_show(popup_widget);
478 rfm_set_widget(popup_widget, menu_id);
479 gtk_menu_item_set_submenu (GTK_MENU_ITEM (parent), popup_widget);
480 g_object_unref(old_popup);
481 GtkWidget *v = gtk_menu_item_new_with_mnemonic ("rodent-dotdesktop");
482 gtk_widget_show (v);
483 gtk_container_add (GTK_CONTAINER (popup_widget), v);
484 gtk_widget_set_sensitive (v, FALSE);
485 NOOP(stderr,"populate_submenu now...\n");
486 return popup_widget;
487 }
488
489 static void *
thread_applications_menu(gpointer data)490 thread_applications_menu(gpointer data){
491 GtkWidget *w = rfm_context_function(thread_applications_menu_f, data);
492 rodent_thread_add_menu_separator (w, NULL);
493 populate_submenu(w);
494 return w;
495 }
496
497
498
499 // GtkWidget *
500 // This returns the menu for a nondetached menu
501 // Parameter p is the view's widgets_p pointer.
502 // Parameter q is the parent for the menu widget
503 // (i.e., the spot where it will be attached)
504 //
505
506 G_MODULE_EXPORT
507 void *
dotdesktop_nondetached_menu(void * p,void * q)508 dotdesktop_nondetached_menu(void *p, void *q){
509 NOOP(stderr, "dotdesktop_nondetached_menu now... desktop_serial=%d\n", desktop_serial);
510 if (rfm_get_gtk_thread() != g_thread_self()){
511 DBG("dotdesktop_nondetached_menu is a main callback function only\n");
512 return GINT_TO_POINTER(1);
513 }
514 const gchar *menu_id = "applications_menu_menu";
515 GtkWidget *popup_widget=rfm_get_widget(menu_id);
516
517 static gint serial=-1;
518 if (popup_widget==NULL){
519 DBG("dotdesktop_nondetached_menu: this is wrong...\n");
520 return NULL;
521 }
522
523 if (serial != desktop_serial) {
524 serial = desktop_serial;
525 rfm_view_thread_create(NULL, thread_applications_menu, NULL, "thread_applications_menu:dotdesktop");
526 }
527
528 return GINT_TO_POINTER(1);
529 //return popup_widget;
530 }
531
532