1. diff -aur compiz-deskmenu/deskmenu-menu.c copy of compiz-deskmenu//deskmenu-menu.c
  2. --- compiz-deskmenu/deskmenu-menu.c 2010-11-08 14:20:23.000000000 -0800
  3. +++ compiz-deskmenu2/deskmenu-menu.c    2010-11-08 14:13:24.000000000 -0800
  4. @@ -1,658 +1,671 @@
  5. -/*
  6. - * compiz-deskmenu 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.
  10. - *
  11. - * compiz-deskmenu 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.
  15. - *
  16. - * You should have received a copy of the GNU General Public License
  17. - * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18. - *
  19. - * Copyright 2008 Christopher Williams <christopherw@verizon.net>
  20. - */
  21. -
  22. -#include <stdlib.h>
  23. -#include <string.h>
  24. -#include <dbus/dbus-glib-lowlevel.h>
  25. -#include <gtk/gtk.h>
  26. -
  27. -#define HAVE_WNCK 1
  28. -
  29. -#if HAVE_WNCK
  30. -#include "deskmenu-wnck.h"
  31. -#endif
  32. -
  33. -#include "deskmenu-menu.h"
  34. -#include "deskmenu-glue.h"
  35. -
  36. -
  37. -G_DEFINE_TYPE(Deskmenu, deskmenu, G_TYPE_OBJECT)
  38. -
  39. -GQuark
  40. -deskmenu_error_quark (void)
  41. -{
  42. -    static GQuark quark = 0;
  43. -    if (!quark)
  44. -        quark = g_quark_from_static_string ("deskmenu_error");
  45. -    return quark;
  46. -}
  47. -
  48. -static void
  49. -quit (GtkWidget *widget,
  50. -      gpointer   data)
  51. -{
  52. -    gtk_main_quit ();
  53. -}
  54. -
  55. -static void
  56. -launcher_activated (GtkWidget *widget,
  57. -                    gchar     *command)
  58. -{
  59. -    GError *error = NULL;
  60. -    Deskmenu *deskmenu;
  61. -
  62. -    deskmenu = g_object_get_data (G_OBJECT (widget), "deskmenu");
  63. -
  64. -   if (!gdk_spawn_on_screen (gdk_screen_get_default (),
  65. -                              g_get_home_dir (),
  66. -                              g_strsplit (command, " ", 0),
  67. -                              deskmenu->envp, G_SPAWN_SEARCH_PATH,
  68. -                              NULL, NULL, NULL, &error))
  69. -    {
  70. -        GtkWidget *message = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR,
  71. -            GTK_BUTTONS_CLOSE, "%s", error->message);
  72. -        gtk_dialog_run (GTK_DIALOG (message));
  73. -        gtk_widget_destroy (message);
  74. -    }
  75. -        
  76. -}
  77. -
  78. -static void
  79. -launcher_name_exec_update (GtkWidget *label)
  80. -{
  81. -    gchar *exec, *stdout;
  82. -    exec = g_object_get_data (G_OBJECT (label), "exec");
  83. -    if (g_spawn_command_line_sync (exec, &stdout, NULL, NULL, NULL))
  84. -        gtk_label_set_text (GTK_LABEL (label), g_strstrip(stdout));
  85. -    else
  86. -        gtk_label_set_text (GTK_LABEL (label), "execution error");
  87. -    g_free (stdout);
  88. -}
  89. -
  90. -static void
  91. -deskmenu_construct_item (Deskmenu *deskmenu)
  92. -{
  93. -    DeskmenuItem *item = deskmenu->current_item;
  94. -    GtkWidget *menu_item;
  95. -    gchar *name, *icon, *command;
  96. -
  97. -    switch (item->type)
  98. -    {
  99. -        case DESKMENU_ITEM_LAUNCHER:
  100. -            if (item->name_exec)
  101. -            {
  102. -                GtkWidget *label;
  103. -                GHook *hook;
  104. -                
  105. -                name = g_strstrip (item->name->str);
  106. -
  107. -                menu_item = gtk_image_menu_item_new ();
  108. -                label = gtk_label_new_with_mnemonic (NULL);
  109. -                gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  110. -
  111. -                g_object_set_data (G_OBJECT (label), "exec", g_strdup (name));
  112. -                gtk_container_add (GTK_CONTAINER (menu_item), label);
  113. -                hook = g_hook_alloc (deskmenu->show_hooks);
  114. -
  115. -                hook->data = (gpointer) label;
  116. -                hook->func = (GHookFunc *) launcher_name_exec_update;
  117. -                g_hook_append (deskmenu->show_hooks, hook);
  118. -            }
  119. -            else
  120. -            {
  121. -                if (item->name)
  122. -                    name = g_strstrip (item->name->str);
  123. -                else
  124. -                    name = "";
  125. -
  126. -                menu_item = gtk_image_menu_item_new_with_mnemonic (name);
  127. -
  128. -            }
  129. -
  130. -            if (item->icon)
  131. -            {
  132. -                icon = g_strstrip (item->icon->str);
  133. -                gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
  134. -                    gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU));
  135. -            }
  136. -        
  137. -            if (item->command)
  138. -            {
  139. -                command = g_strstrip (item->command->str);
  140. -                g_object_set_data (G_OBJECT (menu_item), "deskmenu", deskmenu);
  141. -                g_signal_connect (G_OBJECT (menu_item), "activate",
  142. -                    G_CALLBACK (launcher_activated), g_strdup (command));
  143. -            }
  144. -
  145. -            gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
  146. -                menu_item);
  147. -            break;
  148. -
  149. -#if HAVE_WNCK
  150. -        case DESKMENU_ITEM_WINDOWLIST:
  151. -            menu_item = gtk_menu_item_new_with_mnemonic ("_Windows");
  152. -
  153. -            DeskmenuWindowlist *windowlist = deskmenu_windowlist_new ();
  154. -
  155. -            gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item),
  156. -                windowlist->menu);
  157. -            gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
  158. -                menu_item);
  159. -            break;
  160. -
  161. -        case DESKMENU_ITEM_VIEWPORTLIST:
  162. -            menu_item = gtk_menu_item_new_with_mnemonic ("_Viewports");
  163. -
  164. -            DeskmenuVplist *vplist = deskmenu_vplist_new ();
  165. -
  166. -            if (item->wrap
  167. -                && strcmp (g_strstrip (item->wrap->str), "true") == 0)
  168. -                vplist->wrap = TRUE;
  169. -
  170. -            gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item),
  171. -                vplist->menu);
  172. -            gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
  173. -                menu_item);
  174. -            break;
  175. -#endif
  176. -        case DESKMENU_ITEM_RELOAD:
  177. -            menu_item = gtk_image_menu_item_new_with_mnemonic ("_Reload");
  178. -            gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
  179. -                gtk_image_new_from_stock (GTK_STOCK_REFRESH,
  180. -                    GTK_ICON_SIZE_MENU));
  181. -            g_signal_connect (G_OBJECT (menu_item), "activate",
  182. -                G_CALLBACK (quit), NULL);    
  183. -            gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
  184. -                menu_item);
  185. -            break;
  186. -
  187. -        default:
  188. -            break;
  189. -    }
  190. -
  191. -}
  192. -/* The handler functions. */
  193. -
  194. -static void
  195. -start_element (GMarkupParseContext *context,
  196. -               const gchar         *element_name,
  197. -               const gchar        **attr_names,
  198. -               const gchar        **attr_values,
  199. -               gpointer             user_data,
  200. -               GError             **error)
  201. -{
  202. -    Deskmenu *deskmenu = DESKMENU (user_data);
  203. -    DeskmenuElementType element_type;
  204. -    const gchar **ncursor = attr_names, **vcursor = attr_values;
  205. -    GtkWidget *item, *menu;
  206. -
  207. -    element_type = GPOINTER_TO_INT (g_hash_table_lookup
  208. -        (deskmenu->element_hash, element_name));
  209. -
  210. -    if ((deskmenu->menu && !deskmenu->current_menu)
  211. -       || (!deskmenu->menu && element_type != DESKMENU_ELEMENT_MENU))
  212. -    {
  213. -        gint line_num, char_num;
  214. -        g_markup_parse_context_get_position (context, &line_num, &char_num);    
  215. -        g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
  216. -            "Error on line %d char %d: Element '%s' declared outside of "
  217. -            "toplevel menu element", line_num, char_num, element_name);
  218. -        return;
  219. -    }
  220. -
  221. -    switch (element_type)
  222. -    {
  223. -        case DESKMENU_ELEMENT_MENU:
  224. -
  225. -            if (deskmenu->current_item != NULL)
  226. -            {
  227. -                gint line_num, char_num;
  228. -                g_markup_parse_context_get_position (context, &line_num,
  229. -                    &char_num);    
  230. -                g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
  231. -                    "Error on line %d char %d: Element 'menu' cannot be nested "
  232. -                    "inside of an item element", line_num, char_num);
  233. -                return;
  234. -            }
  235. -
  236. -            if (!deskmenu->menu)
  237. -            {
  238. -                deskmenu->menu = gtk_menu_new ();
  239. -                g_object_set_data (G_OBJECT (deskmenu->menu), "parent menu",
  240. -                    NULL);
  241. -                deskmenu->current_menu = deskmenu->menu;
  242. -            }
  243. -            else
  244. -            {
  245. -                gchar *name = NULL;
  246. -                while (*ncursor)
  247. -                {
  248. -                    if (strcmp (*ncursor, "name") == 0)
  249. -                        name = g_strdup (*vcursor);
  250. -                    else
  251. -                        g_set_error (error, G_MARKUP_ERROR,
  252. -                            G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
  253. -                            "Unknown attribute: %s", *ncursor);
  254. -                    ncursor++;
  255. -                    vcursor++;
  256. -                }
  257. -                if (name)
  258. -                    item = gtk_menu_item_new_with_mnemonic (name);
  259. -                else
  260. -                    item = gtk_menu_item_new_with_mnemonic ("");
  261. -                gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
  262. -                    item);
  263. -                menu = gtk_menu_new ();
  264. -                g_object_set_data (G_OBJECT (menu), "parent menu",
  265. -                    deskmenu->current_menu);
  266. -                deskmenu->current_menu = menu;
  267. -                gtk_menu_item_set_submenu (GTK_MENU_ITEM (item),
  268. -                    deskmenu->current_menu);
  269. -                g_free (name);
  270. -            }
  271. -            break;
  272. -        
  273. -        case DESKMENU_ELEMENT_SEPARATOR:
  274. -            break; /* build it in the end function */
  275. -
  276. -        case DESKMENU_ELEMENT_ITEM:
  277. -
  278. -            if (deskmenu->current_item != NULL)
  279. -            {
  280. -                gint line_num, char_num;
  281. -                g_markup_parse_context_get_position (context, &line_num,
  282. -                    &char_num);    
  283. -                g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
  284. -                    "Error on line %d char %d: Element 'item' cannot be nested "
  285. -                    "inside of another item element", line_num, char_num);
  286. -                return;
  287. -            }
  288. -
  289. -            deskmenu->current_item = g_slice_new0 (DeskmenuItem);
  290. -                while (*ncursor)
  291. -                {
  292. -                    if (strcmp (*ncursor, "type") == 0)
  293. -                        deskmenu->current_item->type = GPOINTER_TO_INT
  294. -                        (g_hash_table_lookup (deskmenu->item_hash, *vcursor));
  295. -                    else
  296. -                        g_set_error (error, G_MARKUP_ERROR,
  297. -                            G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
  298. -                            "Unknown attribute: %s", *ncursor);
  299. -                    ncursor++;
  300. -                    vcursor++;
  301. -                }
  302. -            break;
  303. -
  304. -        case DESKMENU_ELEMENT_NAME:
  305. -             while (*ncursor)
  306. -                {
  307. -                    if ((strcmp (*ncursor, "mode") == 0)
  308. -                        && (strcmp (*vcursor, "exec") == 0))
  309. -                        deskmenu->current_item->name_exec = TRUE;
  310. -                    ncursor++;
  311. -                    vcursor++;
  312. -                } /* no break here to let it fall through */
  313. -        case DESKMENU_ELEMENT_ICON:
  314. -        case DESKMENU_ELEMENT_COMMAND:
  315. -        case DESKMENU_ELEMENT_WRAP:
  316. -            if (deskmenu->current_item)
  317. -                deskmenu->current_item->current_element = element_type;
  318. -            break;
  319. -
  320. -        default:
  321. -            g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
  322. -                "Unknown element: %s", element_name);
  323. -            break;
  324. -    }
  325. -}
  326. -
  327. -static void
  328. -text (GMarkupParseContext *context,
  329. -      const gchar         *text,
  330. -      gsize                text_len,
  331. -      gpointer             user_data,
  332. -      GError             **error)
  333. -{
  334. -    Deskmenu *deskmenu = DESKMENU (user_data);
  335. -    DeskmenuItem *item = deskmenu->current_item;
  336. -
  337. -    if (!(item && item->current_element))
  338. -        return;
  339. -
  340. -    switch (item->current_element)
  341. -    {
  342. -        case DESKMENU_ELEMENT_NAME:
  343. -            if (!item->name)
  344. -                item->name = g_string_new_len (text, text_len);
  345. -            else
  346. -                g_string_append_len (item->name, text, text_len);
  347. -            break;
  348. -
  349. -        case DESKMENU_ELEMENT_ICON:
  350. -            if (!item->icon)
  351. -                item->icon = g_string_new_len (text, text_len);
  352. -            else
  353. -                g_string_append_len (item->icon, text, text_len);
  354. -            break;
  355. -
  356. -        case DESKMENU_ELEMENT_COMMAND:
  357. -            if (!item->command)
  358. -                item->command = g_string_new_len (text, text_len);
  359. -            else
  360. -                g_string_append_len (item->command, text, text_len);
  361. -            break;
  362. -
  363. -        case DESKMENU_ELEMENT_WRAP:
  364. -            if (!item->wrap)
  365. -                item->wrap = g_string_new_len (text, text_len);
  366. -            else
  367. -                g_string_append_len (item->wrap, text, text_len);
  368. -            break;
  369. -
  370. -        default:
  371. -            break;
  372. -    }
  373. -
  374. -}
  375. -
  376. -static void
  377. -end_element (GMarkupParseContext *context,
  378. -             const gchar         *element_name,
  379. -             gpointer             user_data,
  380. -             GError             **error)
  381. -{
  382. -
  383. -    DeskmenuElementType element_type;
  384. -    Deskmenu *deskmenu = DESKMENU (user_data);
  385. -    GtkWidget *parent, *item;
  386. -    element_type = GPOINTER_TO_INT (g_hash_table_lookup
  387. -        (deskmenu->element_hash, element_name));
  388. -
  389. -    switch (element_type)
  390. -    {
  391. -        case DESKMENU_ELEMENT_MENU:
  392. -
  393. -            g_return_if_fail (deskmenu->current_item == NULL);
  394. -
  395. -            parent = g_object_get_data (G_OBJECT (deskmenu->current_menu),
  396. -                "parent menu");
  397. -
  398. -            deskmenu->current_menu = parent;
  399. -
  400. -            break;
  401. -
  402. -        case DESKMENU_ELEMENT_SEPARATOR:
  403. -            item = gtk_separator_menu_item_new ();
  404. -            gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
  405. -                item);
  406. -            break;
  407. -
  408. -        case DESKMENU_ELEMENT_ITEM:
  409. -
  410. -            g_return_if_fail (deskmenu->current_item != NULL);
  411. -
  412. -            /* finally make the item ^_^ */
  413. -            deskmenu_construct_item (deskmenu);
  414. -
  415. -            /* free data used to make it */
  416. -            if (deskmenu->current_item->name)
  417. -                g_string_free (deskmenu->current_item->name, TRUE);
  418. -            if (deskmenu->current_item->icon)
  419. -                g_string_free (deskmenu->current_item->icon, TRUE);
  420. -            if (deskmenu->current_item->command)
  421. -                g_string_free (deskmenu->current_item->command, TRUE);
  422. -            if (deskmenu->current_item->wrap)
  423. -                g_string_free (deskmenu->current_item->wrap, TRUE);
  424. -            g_slice_free (DeskmenuItem, deskmenu->current_item);
  425. -            deskmenu->current_item = NULL;
  426. -            break;
  427. -
  428. -        default:
  429. -            break;
  430. -    }
  431. -}
  432. -
  433. -/* The list of what handler does what. */
  434. -static GMarkupParser parser = {
  435. -    start_element,
  436. -    end_element,
  437. -    text,
  438. -    NULL,
  439. -    NULL
  440. -};
  441. -
  442. -
  443. -/* Class init */
  444. -static void
  445. -deskmenu_class_init (DeskmenuClass *deskmenu_class)
  446. -{
  447. -    dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (deskmenu_class),
  448. -        &dbus_glib_deskmenu_object_info);
  449. -}
  450. -
  451. -/* Instance init */
  452. -static void
  453. -deskmenu_init (Deskmenu *deskmenu)
  454. -{
  455. -
  456. -    deskmenu->show_hooks = g_slice_new0 (GHookList);
  457. -
  458. -    g_hook_list_init (deskmenu->show_hooks, sizeof (GHook));
  459. -
  460. -
  461. -    deskmenu->menu = NULL;
  462. -    deskmenu->current_menu = NULL;
  463. -    deskmenu->current_item = NULL;
  464. -
  465. -    deskmenu->envp = NULL;
  466. -
  467. -    deskmenu->item_hash = g_hash_table_new (g_str_hash, g_str_equal);
  468. -
  469. -    g_hash_table_insert (deskmenu->item_hash, "launcher",
  470. -        GINT_TO_POINTER (DESKMENU_ITEM_LAUNCHER));
  471. -#if HAVE_WNCK
  472. -    g_hash_table_insert (deskmenu->item_hash, "windowlist",
  473. -        GINT_TO_POINTER (DESKMENU_ITEM_WINDOWLIST));
  474. -    g_hash_table_insert (deskmenu->item_hash, "viewportlist",
  475. -        GINT_TO_POINTER (DESKMENU_ITEM_VIEWPORTLIST));
  476. -#endif
  477. -    g_hash_table_insert (deskmenu->item_hash, "reload",
  478. -        GINT_TO_POINTER (DESKMENU_ITEM_RELOAD));
  479. -
  480. -    deskmenu->element_hash = g_hash_table_new (g_str_hash, g_str_equal);
  481. -    
  482. -    g_hash_table_insert (deskmenu->element_hash, "menu",
  483. -        GINT_TO_POINTER (DESKMENU_ELEMENT_MENU));
  484. -    g_hash_table_insert (deskmenu->element_hash, "separator",
  485. -        GINT_TO_POINTER (DESKMENU_ELEMENT_SEPARATOR));
  486. -    g_hash_table_insert (deskmenu->element_hash, "item",
  487. -        GINT_TO_POINTER (DESKMENU_ELEMENT_ITEM));
  488. -    g_hash_table_insert (deskmenu->element_hash, "name",
  489. -        GINT_TO_POINTER (DESKMENU_ELEMENT_NAME));
  490. -    g_hash_table_insert (deskmenu->element_hash, "icon",
  491. -        GINT_TO_POINTER (DESKMENU_ELEMENT_ICON));
  492. -    g_hash_table_insert (deskmenu->element_hash, "command",
  493. -        GINT_TO_POINTER (DESKMENU_ELEMENT_COMMAND));
  494. -    g_hash_table_insert (deskmenu->element_hash, "wrap",
  495. -        GINT_TO_POINTER (DESKMENU_ELEMENT_WRAP));
  496. -
  497. -}
  498. -
  499. -static void
  500. -deskmenu_parse_file (Deskmenu *deskmenu,
  501. -                     gchar *configpath)
  502. -{
  503. -    GError *error = NULL;
  504. -    gboolean success = FALSE;
  505. -    gchar *text;
  506. -    gsize length;
  507. -    
  508. -    if (!configpath)
  509. -        configpath = g_build_path (G_DIR_SEPARATOR_S,
  510. -                                   g_get_user_config_dir (),
  511. -                                   "compiz",
  512. -                                   "deskmenu",
  513. -                                   "menu.xml",
  514. -                                   NULL);
  515. -
  516. -    GMarkupParseContext *context = g_markup_parse_context_new (&parser,
  517. -        0, deskmenu, NULL);
  518. -
  519. -    if (!g_file_get_contents (configpath, &text, &length, NULL))
  520. -    {
  521. -        const gchar* const *cursor = g_get_system_config_dirs ();
  522. -        gchar *path = NULL;
  523. -        while (*cursor)
  524. -        {
  525. -            g_free (configpath);
  526. -            g_free (path);
  527. -            path = g_strdup (*cursor);
  528. -            configpath = g_build_path (G_DIR_SEPARATOR_S,
  529. -                                       path,
  530. -                                       "compiz",
  531. -                                       "deskmenu",
  532. -                                       "menu.xml",
  533. -                                       NULL);
  534. -
  535. -            if (g_file_get_contents (configpath, &text, &length, NULL))
  536. -            {
  537. -                success = TRUE;
  538. -                g_free (path);
  539. -                break;
  540. -            }
  541. -            cursor++;
  542. -        }
  543. -    }
  544. -    else
  545. -    {
  546. -        success = TRUE;
  547. -    }
  548. -
  549. -    if (!success)
  550. -    {
  551. -        g_printerr ("Couldn't find a menu file\n");
  552. -        exit (1);
  553. -    }
  554. -
  555. -    if (!g_markup_parse_context_parse (context, text, length, &error)
  556. -        || !g_markup_parse_context_end_parse (context, &error))
  557. -    {
  558. -        g_printerr ("Parse of %s failed with message: %s \n",
  559. -            configpath, error->message);
  560. -        g_error_free (error);
  561. -        exit (1);
  562. -    }
  563. -
  564. -    g_free(text);
  565. -    g_free (configpath);
  566. -    g_markup_parse_context_free (context);
  567. -
  568. -    gtk_widget_show_all (deskmenu->menu);
  569. -}
  570. -
  571. -/* The show method */
  572. -gboolean
  573. -deskmenu_show (Deskmenu *deskmenu,
  574. -               gchar **env,
  575. -               GError  **error)
  576. -{
  577. -    g_hook_list_invoke (deskmenu->show_hooks, FALSE);
  578. -
  579. -    if (deskmenu->envp)
  580. -        g_strfreev (deskmenu->envp);
  581. -
  582. -    deskmenu->envp = g_strdupv (env);
  583. -
  584. -    gtk_menu_popup (GTK_MENU (deskmenu->menu),
  585. -                    NULL, NULL, NULL, NULL,
  586. -                    0, 0);
  587. -    return TRUE;
  588. -}
  589. -
  590. -/* The reload method */
  591. -gboolean
  592. -deskmenu_reload (Deskmenu *deskmenu,
  593. -               GError  **error)
  594. -{
  595. -    gtk_main_quit ();
  596. -    return TRUE;
  597. -}
  598. -
  599. -int
  600. -main (int    argc,
  601. -      char **argv)
  602. -{
  603. -    DBusGConnection *connection;
  604. -    GError *error = NULL;
  605. -    GObject *deskmenu;
  606. -
  607. -    g_type_init ();
  608. -
  609. -    gchar *filename = NULL;
  610. -    GOptionContext *context;
  611. -    GOptionEntry entries[] =
  612. -    {
  613. -        { "menu", 'm', 0, G_OPTION_ARG_FILENAME, &filename,
  614. -            "Use FILE instead of the default menu file", "FILE" },
  615. -        { NULL, 0, 0, 0, NULL, NULL, NULL }
  616. -    };
  617. -
  618. -    context = g_option_context_new (NULL);
  619. -    g_option_context_add_main_entries (context, entries, NULL);
  620. -    g_option_context_add_group (context, gtk_get_option_group (TRUE));
  621. -    if (!g_option_context_parse (context, &argc, &argv, &error))
  622. -    {
  623. -        g_printerr ("option parsing failed: %s", error->message);
  624. -        g_error_free (error);
  625. -        exit (1);
  626. -    }
  627. -    g_option_context_free (context);
  628. -
  629. -    /* Obtain a connection to the session bus */
  630. -    connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
  631. -    if (connection == NULL)
  632. -    {
  633. -        g_printerr ("Failed to open connection to bus: %s", error->message);
  634. -        g_error_free (error);
  635. -        exit (1);
  636. -    }
  637. -
  638. -#if HAVE_WNCK
  639. -    wnck_set_client_type (WNCK_CLIENT_TYPE_PAGER);
  640. -#endif
  641. -
  642. -    gtk_init (&argc, &argv);
  643. -
  644. -    deskmenu = g_object_new (DESKMENU_TYPE, NULL);
  645. -
  646. -    deskmenu_parse_file (DESKMENU (deskmenu), filename);
  647. -
  648. -    dbus_g_connection_register_g_object (connection,
  649. -                                         DESKMENU_PATH_DBUS,
  650. -                                         deskmenu);
  651. -
  652. -   if (!dbus_bus_request_name (dbus_g_connection_get_connection (connection),
  653. -                               DESKMENU_SERVICE_DBUS,
  654. -                                DBUS_NAME_FLAG_REPLACE_EXISTING,
  655. -                               NULL))
  656. -        return 1;
  657. -
  658. -    gtk_main ();
  659. -
  660. -    return 0;
  661. -}
  662. -
  663. +/*
  664.  
  665. + * compiz-deskmenu is free software; you can redistribute it and/or modify
  666.  
  667. + * it under the terms of the GNU General Public License as published by
  668.  
  669. + * the Free Software Foundation; either version 2 of the License, or
  670.  
  671. + * (at your option) any later version.
  672.  
  673. + *
  674.  
  675. + * compiz-deskmenu is distributed in the hope that it will be useful,
  676.  
  677. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  678.  
  679. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  680.  
  681. + * GNU General Public License for more details.
  682.  
  683. + *
  684.  
  685. + * You should have received a copy of the GNU General Public License
  686.  
  687. + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  688.  
  689. + *
  690.  
  691. + * Copyright 2008 Christopher Williams <christopherw@verizon.net>
  692.  
  693. + */
  694.  
  695. +
  696.  
  697. +#include <stdlib.h>
  698.  
  699. +#include <string.h>
  700.  
  701. +#include <dbus/dbus-glib-lowlevel.h>
  702.  
  703. +#include <gtk/gtk.h>
  704.  
  705. +
  706.  
  707. +#define HAVE_WNCK 1
  708.  
  709. +
  710.  
  711. +#if HAVE_WNCK
  712.  
  713. +#include "deskmenu-wnck.h"
  714.  
  715. +#endif
  716.  
  717. +
  718.  
  719. +#include "deskmenu-menu.h"
  720.  
  721. +#include "deskmenu-glue.h"
  722.  
  723. +
  724.  
  725. +
  726.  
  727. +G_DEFINE_TYPE(Deskmenu, deskmenu, G_TYPE_OBJECT)
  728.  
  729. +
  730.  
  731. +GQuark
  732.  
  733. +deskmenu_error_quark (void)
  734.  
  735. +{
  736.  
  737. +    static GQuark quark = 0;
  738.  
  739. +    if (!quark)
  740.  
  741. +        quark = g_quark_from_static_string ("deskmenu_error");
  742.  
  743. +    return quark;
  744.  
  745. +}
  746.  
  747. +
  748.  
  749. +static void
  750.  
  751. +quit (GtkWidget *widget,
  752.  
  753. +      gpointer   data)
  754.  
  755. +{
  756.  
  757. +    gtk_main_quit ();
  758.  
  759. +}
  760.  
  761. +
  762.  
  763. +//This is how menu command is launched
  764.  
  765. +static void
  766.  
  767. +launcher_activated (GtkWidget *widget,
  768.  
  769. +                    gchar     *command)
  770.  
  771. +{
  772.  
  773. +    GError *error = NULL;
  774.  
  775. +    Deskmenu *deskmenu;
  776.  
  777. +
  778.  
  779. +    deskmenu = g_object_get_data (G_OBJECT (widget), "deskmenu");
  780.  
  781. +    //stolen from openbox
  782.  
  783. +    gchar *parse_expand_tilde(const gchar *command)
  784.  
  785. +   {
  786.  
  787. +    gchar *ret;
  788.  
  789. +    GRegex *regex;
  790.  
  791. +
  792.  
  793. +    if (!command)
  794.  
  795. +        return NULL;
  796.  
  797. +
  798.  
  799. +    regex = g_regex_new("(?:^|(?<=[ \\t]))~(?:(?=[/ \\t])|$)",
  800.  
  801. +                        G_REGEX_MULTILINE | G_REGEX_RAW, 0, NULL);
  802.  
  803. +    ret = g_regex_replace_literal(regex, command, -1, 0, g_get_home_dir(), 0, NULL);
  804.  
  805. +    g_regex_unref(regex);
  806.  
  807. +
  808.  
  809. +    return ret;
  810.  
  811. +   }
  812.  
  813. +   //end stolen
  814.  
  815. +   if (!gdk_spawn_command_line_on_screen (gdk_screen_get_default (), parse_expand_tilde(command), &error))
  816.  
  817. +    {
  818.  
  819. +        GtkWidget *message = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR,
  820.  
  821. +            GTK_BUTTONS_CLOSE, "%s", error->message);
  822.  
  823. +        gtk_dialog_run (GTK_DIALOG (message));
  824.  
  825. +        gtk_widget_destroy (message);
  826.  
  827. +    }
  828.  
  829. +
  830.  
  831. +}
  832.  
  833. +
  834.  
  835. +static void
  836.  
  837. +launcher_name_exec_update (GtkWidget *label)
  838.  
  839. +{
  840.  
  841. +    gchar *exec, *stdout;
  842.  
  843. +    exec = g_object_get_data (G_OBJECT (label), "exec");
  844.  
  845. +    if (g_spawn_command_line_sync (exec, &stdout, NULL, NULL, NULL))
  846.  
  847. +        gtk_label_set_text (GTK_LABEL (label), g_strstrip(stdout));
  848.  
  849. +    else
  850.  
  851. +        gtk_label_set_text (GTK_LABEL (label), "execution error");
  852.  
  853. +    g_free (stdout);
  854.  
  855. +}
  856.  
  857. +
  858.  
  859. +static void
  860.  
  861. +deskmenu_construct_item (Deskmenu *deskmenu)
  862.  
  863. +{
  864.  
  865. +    DeskmenuItem *item = deskmenu->current_item;
  866.  
  867. +    GtkWidget *menu_item;
  868.  
  869. +    gchar *name, *icon, *command;
  870.  
  871. +
  872.  
  873. +    switch (item->type)
  874.  
  875. +    {
  876.  
  877. +        case DESKMENU_ITEM_LAUNCHER:
  878.  
  879. +            if (item->name_exec)
  880.  
  881. +            {
  882.  
  883. +                GtkWidget *label;
  884.  
  885. +                GHook *hook;
  886.  
  887. +                
  888.  
  889. +                name = g_strstrip (item->name->str);
  890.  
  891. +
  892.  
  893. +                menu_item = gtk_image_menu_item_new ();
  894.  
  895. +                label = gtk_label_new_with_mnemonic (NULL);
  896.  
  897. +                gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  898.  
  899. +
  900.  
  901. +                g_object_set_data (G_OBJECT (label), "exec", g_strdup (name));
  902.  
  903. +                gtk_container_add (GTK_CONTAINER (menu_item), label);
  904.  
  905. +                hook = g_hook_alloc (deskmenu->show_hooks);
  906.  
  907. +
  908.  
  909. +                hook->data = (gpointer) label;
  910.  
  911. +                hook->func = (GHookFunc *) launcher_name_exec_update;
  912.  
  913. +                g_hook_append (deskmenu->show_hooks, hook);
  914.  
  915. +            }
  916.  
  917. +            else
  918.  
  919. +            {
  920.  
  921. +                if (item->name)
  922.  
  923. +                    name = g_strstrip (item->name->str);
  924.  
  925. +                else
  926.  
  927. +                    name = "";
  928.  
  929. +
  930.  
  931. +                menu_item = gtk_image_menu_item_new_with_mnemonic (name);
  932.  
  933. +
  934.  
  935. +            }
  936.  
  937. +
  938.  
  939. +            if (item->icon)
  940.  
  941. +            {
  942.  
  943. +                icon = g_strstrip (item->icon->str);
  944.  
  945. +                gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
  946.  
  947. +                    gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU));
  948.  
  949. +            }
  950.  
  951. +        
  952.  
  953. +            if (item->command)
  954.  
  955. +            {
  956.  
  957. +                command = g_strstrip (item->command->str);
  958.  
  959. +                g_object_set_data (G_OBJECT (menu_item), "deskmenu", deskmenu);
  960.  
  961. +                g_signal_connect (G_OBJECT (menu_item), "activate",
  962.  
  963. +                    G_CALLBACK (launcher_activated), g_strdup (command));
  964.  
  965. +            }
  966.  
  967. +
  968.  
  969. +            gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
  970.  
  971. +                menu_item);
  972.  
  973. +            break;
  974.  
  975. +
  976.  
  977. +#if HAVE_WNCK
  978.  
  979. +        case DESKMENU_ITEM_WINDOWLIST:
  980.  
  981. +            menu_item = gtk_menu_item_new_with_mnemonic ("_Windows");
  982.  
  983. +
  984.  
  985. +            DeskmenuWindowlist *windowlist = deskmenu_windowlist_new ();
  986.  
  987. +
  988.  
  989. +            gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item),
  990.  
  991. +                windowlist->menu);
  992.  
  993. +            gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
  994.  
  995. +                menu_item);
  996.  
  997. +            break;
  998.  
  999. +
  1000.  
  1001. +        case DESKMENU_ITEM_VIEWPORTLIST:
  1002.  
  1003. +            menu_item = gtk_menu_item_new_with_mnemonic ("_Viewports");
  1004.  
  1005. +
  1006.  
  1007. +            DeskmenuVplist *vplist = deskmenu_vplist_new ();
  1008.  
  1009. +
  1010.  
  1011. +            if (item->wrap
  1012.  
  1013. +                && strcmp (g_strstrip (item->wrap->str), "true") == 0)
  1014.  
  1015. +                vplist->wrap = TRUE;
  1016.  
  1017. +
  1018.  
  1019. +            gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item),
  1020.  
  1021. +                vplist->menu);
  1022.  
  1023. +            gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
  1024.  
  1025. +                menu_item);
  1026.  
  1027. +            break;
  1028.  
  1029. +#endif
  1030.  
  1031. +        case DESKMENU_ITEM_RELOAD:
  1032.  
  1033. +            menu_item = gtk_image_menu_item_new_with_mnemonic ("_Reload");
  1034.  
  1035. +            gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
  1036.  
  1037. +                gtk_image_new_from_stock (GTK_STOCK_REFRESH,
  1038.  
  1039. +                    GTK_ICON_SIZE_MENU));
  1040.  
  1041. +            g_signal_connect (G_OBJECT (menu_item), "activate",
  1042.  
  1043. +                G_CALLBACK (quit), NULL);    
  1044.  
  1045. +            gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
  1046.  
  1047. +                menu_item);
  1048.  
  1049. +            break;
  1050.  
  1051. +
  1052.  
  1053. +        default:
  1054.  
  1055. +            break;
  1056.  
  1057. +    }
  1058.  
  1059. +
  1060.  
  1061. +}
  1062.  
  1063. +/* The handler functions. */
  1064.  
  1065. +
  1066.  
  1067. +static void
  1068.  
  1069. +start_element (GMarkupParseContext *context,
  1070.  
  1071. +               const gchar         *element_name,
  1072.  
  1073. +               const gchar        **attr_names,
  1074.  
  1075. +               const gchar        **attr_values,
  1076.  
  1077. +               gpointer             user_data,
  1078.  
  1079. +               GError             **error)
  1080.  
  1081. +{
  1082.  
  1083. +    Deskmenu *deskmenu = DESKMENU (user_data);
  1084.  
  1085. +    DeskmenuElementType element_type;
  1086.  
  1087. +    const gchar **ncursor = attr_names, **vcursor = attr_values;
  1088.  
  1089. +    GtkWidget *item, *menu;
  1090.  
  1091. +
  1092.  
  1093. +    element_type = GPOINTER_TO_INT (g_hash_table_lookup
  1094.  
  1095. +        (deskmenu->element_hash, element_name));
  1096.  
  1097. +
  1098.  
  1099. +    if ((deskmenu->menu && !deskmenu->current_menu)
  1100.  
  1101. +       || (!deskmenu->menu && element_type != DESKMENU_ELEMENT_MENU))
  1102.  
  1103. +    {
  1104.  
  1105. +        gint line_num, char_num;
  1106.  
  1107. +        g_markup_parse_context_get_position (context, &line_num, &char_num);    
  1108.  
  1109. +        g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
  1110.  
  1111. +            "Error on line %d char %d: Element '%s' declared outside of "
  1112.  
  1113. +            "toplevel menu element", line_num, char_num, element_name);
  1114.  
  1115. +        return;
  1116.  
  1117. +    }
  1118.  
  1119. +
  1120.  
  1121. +    switch (element_type)
  1122.  
  1123. +    {
  1124.  
  1125. +        case DESKMENU_ELEMENT_MENU:
  1126.  
  1127. +
  1128.  
  1129. +            if (deskmenu->current_item != NULL)
  1130.  
  1131. +            {
  1132.  
  1133. +                gint line_num, char_num;
  1134.  
  1135. +                g_markup_parse_context_get_position (context, &line_num,
  1136.  
  1137. +                    &char_num);    
  1138.  
  1139. +                g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
  1140.  
  1141. +                    "Error on line %d char %d: Element 'menu' cannot be nested "
  1142.  
  1143. +                    "inside of an item element", line_num, char_num);
  1144.  
  1145. +                return;
  1146.  
  1147. +            }
  1148.  
  1149. +
  1150.  
  1151. +            if (!deskmenu->menu)
  1152.  
  1153. +            {
  1154.  
  1155. +                deskmenu->menu = gtk_menu_new ();
  1156.  
  1157. +                g_object_set_data (G_OBJECT (deskmenu->menu), "parent menu",
  1158.  
  1159. +                    NULL);
  1160.  
  1161. +                deskmenu->current_menu = deskmenu->menu;
  1162.  
  1163. +            }
  1164.  
  1165. +            else
  1166.  
  1167. +            {
  1168.  
  1169. +                gchar *name = NULL;
  1170.  
  1171. +                while (*ncursor)
  1172.  
  1173. +                {
  1174.  
  1175. +                    if (strcmp (*ncursor, "name") == 0)
  1176.  
  1177. +                        name = g_strdup (*vcursor);
  1178.  
  1179. +                    else
  1180.  
  1181. +                        g_set_error (error, G_MARKUP_ERROR,
  1182.  
  1183. +                            G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
  1184.  
  1185. +                            "Unknown attribute: %s", *ncursor);
  1186.  
  1187. +                    ncursor++;
  1188.  
  1189. +                    vcursor++;
  1190.  
  1191. +                }
  1192.  
  1193. +                if (name)
  1194.  
  1195. +                    item = gtk_menu_item_new_with_mnemonic (name);
  1196.  
  1197. +                else
  1198.  
  1199. +                    item = gtk_menu_item_new_with_mnemonic ("");
  1200.  
  1201. +                gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
  1202.  
  1203. +                    item);
  1204.  
  1205. +                menu = gtk_menu_new ();
  1206.  
  1207. +                g_object_set_data (G_OBJECT (menu), "parent menu",
  1208.  
  1209. +                    deskmenu->current_menu);
  1210.  
  1211. +                deskmenu->current_menu = menu;
  1212.  
  1213. +                gtk_menu_item_set_submenu (GTK_MENU_ITEM (item),
  1214.  
  1215. +                    deskmenu->current_menu);
  1216.  
  1217. +                g_free (name);
  1218.  
  1219. +            }
  1220.  
  1221. +            break;
  1222.  
  1223. +        
  1224.  
  1225. +        case DESKMENU_ELEMENT_SEPARATOR:
  1226.  
  1227. +            break; /* build it in the end function */
  1228.  
  1229. +
  1230.  
  1231. +        case DESKMENU_ELEMENT_ITEM:
  1232.  
  1233. +
  1234.  
  1235. +            if (deskmenu->current_item != NULL)
  1236.  
  1237. +            {
  1238.  
  1239. +                gint line_num, char_num;
  1240.  
  1241. +                g_markup_parse_context_get_position (context, &line_num,
  1242.  
  1243. +                    &char_num);    
  1244.  
  1245. +                g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
  1246.  
  1247. +                    "Error on line %d char %d: Element 'item' cannot be nested "
  1248.  
  1249. +                    "inside of another item element", line_num, char_num);
  1250.  
  1251. +                return;
  1252.  
  1253. +            }
  1254.  
  1255. +
  1256.  
  1257. +            deskmenu->current_item = g_slice_new0 (DeskmenuItem);
  1258.  
  1259. +                while (*ncursor)
  1260.  
  1261. +                {
  1262.  
  1263. +                    if (strcmp (*ncursor, "type") == 0)
  1264.  
  1265. +                        deskmenu->current_item->type = GPOINTER_TO_INT
  1266.  
  1267. +                        (g_hash_table_lookup (deskmenu->item_hash, *vcursor));
  1268.  
  1269. +                    else
  1270.  
  1271. +                        g_set_error (error, G_MARKUP_ERROR,
  1272.  
  1273. +                            G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
  1274.  
  1275. +                            "Unknown attribute: %s", *ncursor);
  1276.  
  1277. +                    ncursor++;
  1278.  
  1279. +                    vcursor++;
  1280.  
  1281. +                }
  1282.  
  1283. +            break;
  1284.  
  1285. +
  1286.  
  1287. +        case DESKMENU_ELEMENT_NAME:
  1288.  
  1289. +             while (*ncursor)
  1290.  
  1291. +                {
  1292.  
  1293. +                    if ((strcmp (*ncursor, "mode") == 0)
  1294.  
  1295. +                        && (strcmp (*vcursor, "exec") == 0))
  1296.  
  1297. +                        deskmenu->current_item->name_exec = TRUE;
  1298.  
  1299. +                    ncursor++;
  1300.  
  1301. +                    vcursor++;
  1302.  
  1303. +                } /* no break here to let it fall through */
  1304.  
  1305. +        case DESKMENU_ELEMENT_ICON:
  1306.  
  1307. +        case DESKMENU_ELEMENT_COMMAND:
  1308.  
  1309. +        case DESKMENU_ELEMENT_WRAP:
  1310.  
  1311. +            if (deskmenu->current_item)
  1312.  
  1313. +                deskmenu->current_item->current_element = element_type;
  1314.  
  1315. +            break;
  1316.  
  1317. +
  1318.  
  1319. +        default:
  1320.  
  1321. +            g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
  1322.  
  1323. +                "Unknown element: %s", element_name);
  1324.  
  1325. +            break;
  1326.  
  1327. +    }
  1328.  
  1329. +}
  1330.  
  1331. +
  1332.  
  1333. +static void
  1334.  
  1335. +text (GMarkupParseContext *context,
  1336.  
  1337. +      const gchar         *text,
  1338.  
  1339. +      gsize                text_len,
  1340.  
  1341. +      gpointer             user_data,
  1342.  
  1343. +      GError             **error)
  1344.  
  1345. +{
  1346.  
  1347. +    Deskmenu *deskmenu = DESKMENU (user_data);
  1348.  
  1349. +    DeskmenuItem *item = deskmenu->current_item;
  1350.  
  1351. +
  1352.  
  1353. +    if (!(item && item->current_element))
  1354.  
  1355. +        return;
  1356.  
  1357. +
  1358.  
  1359. +    switch (item->current_element)
  1360.  
  1361. +    {
  1362.  
  1363. +        case DESKMENU_ELEMENT_NAME:
  1364.  
  1365. +            if (!item->name)
  1366.  
  1367. +                item->name = g_string_new_len (text, text_len);
  1368.  
  1369. +            else
  1370.  
  1371. +                g_string_append_len (item->name, text, text_len);
  1372.  
  1373. +            break;
  1374.  
  1375. +
  1376.  
  1377. +        case DESKMENU_ELEMENT_ICON:
  1378.  
  1379. +            if (!item->icon)
  1380.  
  1381. +                item->icon = g_string_new_len (text, text_len);
  1382.  
  1383. +            else
  1384.  
  1385. +                g_string_append_len (item->icon, text, text_len);
  1386.  
  1387. +            break;
  1388.  
  1389. +
  1390.  
  1391. +        case DESKMENU_ELEMENT_COMMAND:
  1392.  
  1393. +            if (!item->command)
  1394.  
  1395. +                item->command = g_string_new_len (text, text_len);
  1396.  
  1397. +            else
  1398.  
  1399. +                g_string_append_len (item->command, text, text_len);
  1400.  
  1401. +            break;
  1402.  
  1403. +
  1404.  
  1405. +        case DESKMENU_ELEMENT_WRAP:
  1406.  
  1407. +            if (!item->wrap)
  1408.  
  1409. +                item->wrap = g_string_new_len (text, text_len);
  1410.  
  1411. +            else
  1412.  
  1413. +                g_string_append_len (item->wrap, text, text_len);
  1414.  
  1415. +            break;
  1416.  
  1417. +
  1418.  
  1419. +        default:
  1420.  
  1421. +            break;
  1422.  
  1423. +    }
  1424.  
  1425. +
  1426.  
  1427. +}
  1428.  
  1429. +
  1430.  
  1431. +static void
  1432.  
  1433. +end_element (GMarkupParseContext *context,
  1434.  
  1435. +             const gchar         *element_name,
  1436.  
  1437. +             gpointer             user_data,
  1438.  
  1439. +             GError             **error)
  1440.  
  1441. +{
  1442.  
  1443. +
  1444.  
  1445. +    DeskmenuElementType element_type;
  1446.  
  1447. +    Deskmenu *deskmenu = DESKMENU (user_data);
  1448.  
  1449. +    GtkWidget *parent, *item;
  1450.  
  1451. +    element_type = GPOINTER_TO_INT (g_hash_table_lookup
  1452.  
  1453. +        (deskmenu->element_hash, element_name));
  1454.  
  1455. +
  1456.  
  1457. +    switch (element_type)
  1458.  
  1459. +    {
  1460.  
  1461. +        case DESKMENU_ELEMENT_MENU:
  1462.  
  1463. +
  1464.  
  1465. +            g_return_if_fail (deskmenu->current_item == NULL);
  1466.  
  1467. +
  1468.  
  1469. +            parent = g_object_get_data (G_OBJECT (deskmenu->current_menu),
  1470.  
  1471. +                "parent menu");
  1472.  
  1473. +
  1474.  
  1475. +            deskmenu->current_menu = parent;
  1476.  
  1477. +
  1478.  
  1479. +            break;
  1480.  
  1481. +
  1482.  
  1483. +        case DESKMENU_ELEMENT_SEPARATOR:
  1484.  
  1485. +            item = gtk_separator_menu_item_new ();
  1486.  
  1487. +            gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
  1488.  
  1489. +                item);
  1490.  
  1491. +            break;
  1492.  
  1493. +
  1494.  
  1495. +        case DESKMENU_ELEMENT_ITEM:
  1496.  
  1497. +
  1498.  
  1499. +            g_return_if_fail (deskmenu->current_item != NULL);
  1500.  
  1501. +
  1502.  
  1503. +            /* finally make the item ^_^ */
  1504.  
  1505. +            deskmenu_construct_item (deskmenu);
  1506.  
  1507. +
  1508.  
  1509. +            /* free data used to make it */
  1510.  
  1511. +            if (deskmenu->current_item->name)
  1512.  
  1513. +                g_string_free (deskmenu->current_item->name, TRUE);
  1514.  
  1515. +            if (deskmenu->current_item->icon)
  1516.  
  1517. +                g_string_free (deskmenu->current_item->icon, TRUE);
  1518.  
  1519. +            if (deskmenu->current_item->command)
  1520.  
  1521. +                g_string_free (deskmenu->current_item->command, TRUE);
  1522.  
  1523. +            if (deskmenu->current_item->wrap)
  1524.  
  1525. +                g_string_free (deskmenu->current_item->wrap, TRUE);
  1526.  
  1527. +            g_slice_free (DeskmenuItem, deskmenu->current_item);
  1528.  
  1529. +            deskmenu->current_item = NULL;
  1530.  
  1531. +            break;
  1532.  
  1533. +
  1534.  
  1535. +        default:
  1536.  
  1537. +            break;
  1538.  
  1539. +    }
  1540.  
  1541. +}
  1542.  
  1543. +
  1544.  
  1545. +/* The list of what handler does what. */
  1546.  
  1547. +static GMarkupParser parser = {
  1548.  
  1549. +    start_element,
  1550.  
  1551. +    end_element,
  1552.  
  1553. +    text,
  1554.  
  1555. +    NULL,
  1556.  
  1557. +    NULL
  1558.  
  1559. +};
  1560.  
  1561. +
  1562.  
  1563. +
  1564.  
  1565. +/* Class init */
  1566.  
  1567. +static void
  1568.  
  1569. +deskmenu_class_init (DeskmenuClass *deskmenu_class)
  1570.  
  1571. +{
  1572.  
  1573. +    dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (deskmenu_class),
  1574.  
  1575. +        &dbus_glib_deskmenu_object_info);
  1576.  
  1577. +}
  1578.  
  1579. +
  1580.  
  1581. +/* Instance init */
  1582.  
  1583. +static void
  1584.  
  1585. +deskmenu_init (Deskmenu *deskmenu)
  1586.  
  1587. +{
  1588.  
  1589. +
  1590.  
  1591. +    deskmenu->show_hooks = g_slice_new0 (GHookList);
  1592.  
  1593. +
  1594.  
  1595. +    g_hook_list_init (deskmenu->show_hooks, sizeof (GHook));
  1596.  
  1597. +
  1598.  
  1599. +
  1600.  
  1601. +    deskmenu->menu = NULL;
  1602.  
  1603. +    deskmenu->current_menu = NULL;
  1604.  
  1605. +    deskmenu->current_item = NULL;
  1606.  
  1607. +
  1608.  
  1609. +    deskmenu->envp = NULL;
  1610.  
  1611. +
  1612.  
  1613. +    deskmenu->item_hash = g_hash_table_new (g_str_hash, g_str_equal);
  1614.  
  1615. +
  1616.  
  1617. +    g_hash_table_insert (deskmenu->item_hash, "launcher",
  1618.  
  1619. +        GINT_TO_POINTER (DESKMENU_ITEM_LAUNCHER));
  1620.  
  1621. +#if HAVE_WNCK
  1622.  
  1623. +    g_hash_table_insert (deskmenu->item_hash, "windowlist",
  1624.  
  1625. +        GINT_TO_POINTER (DESKMENU_ITEM_WINDOWLIST));
  1626.  
  1627. +    g_hash_table_insert (deskmenu->item_hash, "viewportlist",
  1628.  
  1629. +        GINT_TO_POINTER (DESKMENU_ITEM_VIEWPORTLIST));
  1630.  
  1631. +#endif
  1632.  
  1633. +    g_hash_table_insert (deskmenu->item_hash, "reload",
  1634.  
  1635. +        GINT_TO_POINTER (DESKMENU_ITEM_RELOAD));
  1636.  
  1637. +
  1638.  
  1639. +    deskmenu->element_hash = g_hash_table_new (g_str_hash, g_str_equal);
  1640.  
  1641. +    
  1642.  
  1643. +    g_hash_table_insert (deskmenu->element_hash, "menu",
  1644.  
  1645. +        GINT_TO_POINTER (DESKMENU_ELEMENT_MENU));
  1646.  
  1647. +    g_hash_table_insert (deskmenu->element_hash, "separator",
  1648.  
  1649. +        GINT_TO_POINTER (DESKMENU_ELEMENT_SEPARATOR));
  1650.  
  1651. +    g_hash_table_insert (deskmenu->element_hash, "item",
  1652.  
  1653. +        GINT_TO_POINTER (DESKMENU_ELEMENT_ITEM));
  1654.  
  1655. +    g_hash_table_insert (deskmenu->element_hash, "name",
  1656.  
  1657. +        GINT_TO_POINTER (DESKMENU_ELEMENT_NAME));
  1658.  
  1659. +    g_hash_table_insert (deskmenu->element_hash, "icon",
  1660.  
  1661. +        GINT_TO_POINTER (DESKMENU_ELEMENT_ICON));
  1662.  
  1663. +    g_hash_table_insert (deskmenu->element_hash, "command",
  1664.  
  1665. +        GINT_TO_POINTER (DESKMENU_ELEMENT_COMMAND));
  1666.  
  1667. +    g_hash_table_insert (deskmenu->element_hash, "wrap",
  1668.  
  1669. +        GINT_TO_POINTER (DESKMENU_ELEMENT_WRAP));
  1670.  
  1671. +
  1672.  
  1673. +}
  1674.  
  1675. +
  1676.  
  1677. +static void
  1678.  
  1679. +deskmenu_parse_file (Deskmenu *deskmenu,
  1680.  
  1681. +                     gchar *configpath)
  1682.  
  1683. +{
  1684.  
  1685. +    GError *error = NULL;
  1686.  
  1687. +    gboolean success = FALSE;
  1688.  
  1689. +    gchar *text;
  1690.  
  1691. +    gsize length;
  1692.  
  1693. +    
  1694.  
  1695. +    if (!configpath)
  1696.  
  1697. +        configpath = g_build_path (G_DIR_SEPARATOR_S,
  1698.  
  1699. +                                   g_get_user_config_dir (),
  1700.  
  1701. +                                   "compiz",
  1702.  
  1703. +                                   "deskmenu",
  1704.  
  1705. +                                   "menu.xml",
  1706.  
  1707. +                                   NULL);
  1708.  
  1709. +
  1710.  
  1711. +    GMarkupParseContext *context = g_markup_parse_context_new (&parser,
  1712.  
  1713. +        0, deskmenu, NULL);
  1714.  
  1715. +
  1716.  
  1717. +    if (!g_file_get_contents (configpath, &text, &length, NULL))
  1718.  
  1719. +    {
  1720.  
  1721. +        const gchar* const *cursor = g_get_system_config_dirs ();
  1722.  
  1723. +        gchar *path = NULL;
  1724.  
  1725. +        while (*cursor)
  1726.  
  1727. +        {
  1728.  
  1729. +            g_free (configpath);
  1730.  
  1731. +            g_free (path);
  1732.  
  1733. +            path = g_strdup (*cursor);
  1734.  
  1735. +            configpath = g_build_path (G_DIR_SEPARATOR_S,
  1736.  
  1737. +                                       path,
  1738.  
  1739. +                                       "compiz",
  1740.  
  1741. +                                       "deskmenu",
  1742.  
  1743. +                                       "menu.xml",
  1744.  
  1745. +                                       NULL);
  1746.  
  1747. +
  1748.  
  1749. +            if (g_file_get_contents (configpath, &text, &length, NULL))
  1750.  
  1751. +            {
  1752.  
  1753. +                success = TRUE;
  1754.  
  1755. +                g_free (path);
  1756.  
  1757. +                break;
  1758.  
  1759. +            }
  1760.  
  1761. +            cursor++;
  1762.  
  1763. +        }
  1764.  
  1765. +    }
  1766.  
  1767. +    else
  1768.  
  1769. +    {
  1770.  
  1771. +        success = TRUE;
  1772.  
  1773. +    }
  1774.  
  1775. +
  1776.  
  1777. +    if (!success)
  1778.  
  1779. +    {
  1780.  
  1781. +        g_printerr ("Couldn't find a menu file\n");
  1782.  
  1783. +        exit (1);
  1784.  
  1785. +    }
  1786.  
  1787. +
  1788.  
  1789. +    if (!g_markup_parse_context_parse (context, text, length, &error)
  1790.  
  1791. +        || !g_markup_parse_context_end_parse (context, &error))
  1792.  
  1793. +    {
  1794.  
  1795. +        g_printerr ("Parse of %s failed with message: %s \n",
  1796.  
  1797. +            configpath, error->message);
  1798.  
  1799. +        g_error_free (error);
  1800.  
  1801. +        exit (1);
  1802.  
  1803. +    }
  1804.  
  1805. +
  1806.  
  1807. +    g_free(text);
  1808.  
  1809. +    g_free (configpath);
  1810.  
  1811. +    g_markup_parse_context_free (context);
  1812.  
  1813. +
  1814.  
  1815. +    gtk_widget_show_all (deskmenu->menu);
  1816.  
  1817. +}
  1818.  
  1819. +
  1820.  
  1821. +/* The show method */
  1822.  
  1823. +gboolean
  1824.  
  1825. +deskmenu_show (Deskmenu *deskmenu,
  1826.  
  1827. +               gchar **env,
  1828.  
  1829. +               GError  **error)
  1830.  
  1831. +{
  1832.  
  1833. +    g_hook_list_invoke (deskmenu->show_hooks, FALSE);
  1834.  
  1835. +
  1836.  
  1837. +    if (deskmenu->envp)
  1838.  
  1839. +        g_strfreev (deskmenu->envp);
  1840.  
  1841. +
  1842.  
  1843. +    deskmenu->envp = g_strdupv (env);
  1844.  
  1845. +
  1846.  
  1847. +    gtk_menu_popup (GTK_MENU (deskmenu->menu),
  1848.  
  1849. +                    NULL, NULL, NULL, NULL,
  1850.  
  1851. +                    0, 0);
  1852.  
  1853. +    return TRUE;
  1854.  
  1855. +}
  1856.  
  1857. +
  1858.  
  1859. +/* The reload method */
  1860.  
  1861. +gboolean
  1862.  
  1863. +deskmenu_reload (Deskmenu *deskmenu,
  1864.  
  1865. +               GError  **error)
  1866.  
  1867. +{
  1868.  
  1869. +    gtk_main_quit ();
  1870.  
  1871. +    return TRUE;
  1872.  
  1873. +}
  1874.  
  1875. +
  1876.  
  1877. +int
  1878.  
  1879. +main (int    argc,
  1880.  
  1881. +      char **argv)
  1882.  
  1883. +{
  1884.  
  1885. +    DBusGConnection *connection;
  1886.  
  1887. +    GError *error = NULL;
  1888.  
  1889. +    GObject *deskmenu;
  1890.  
  1891. +
  1892.  
  1893. +    g_type_init ();
  1894.  
  1895. +
  1896.  
  1897. +    gchar *filename = NULL;
  1898.  
  1899. +    GOptionContext *context;
  1900.  
  1901. +    GOptionEntry entries[] =
  1902.  
  1903. +    {
  1904.  
  1905. +        { "menu", 'm', 0, G_OPTION_ARG_FILENAME, &filename,
  1906.  
  1907. +            "Use FILE instead of the default menu file", "FILE" },
  1908.  
  1909. +        { NULL, 0, 0, 0, NULL, NULL, NULL }
  1910.  
  1911. +    };
  1912.  
  1913. +
  1914.  
  1915. +    context = g_option_context_new (NULL);
  1916.  
  1917. +    g_option_context_add_main_entries (context, entries, NULL);
  1918.  
  1919. +    g_option_context_add_group (context, gtk_get_option_group (TRUE));
  1920.  
  1921. +    if (!g_option_context_parse (context, &argc, &argv, &error))
  1922.  
  1923. +    {
  1924.  
  1925. +        g_printerr ("option parsing failed: %s", error->message);
  1926.  
  1927. +        g_error_free (error);
  1928.  
  1929. +        exit (1);
  1930.  
  1931. +    }
  1932.  
  1933. +    g_option_context_free (context);
  1934.  
  1935. +
  1936.  
  1937. +    /* Obtain a connection to the session bus */
  1938.  
  1939. +    connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
  1940.  
  1941. +    if (connection == NULL)
  1942.  
  1943. +    {
  1944.  
  1945. +        g_printerr ("Failed to open connection to bus: %s", error->message);
  1946.  
  1947. +        g_error_free (error);
  1948.  
  1949. +        exit (1);
  1950.  
  1951. +    }
  1952.  
  1953. +
  1954.  
  1955. +#if HAVE_WNCK
  1956.  
  1957. +    wnck_set_client_type (WNCK_CLIENT_TYPE_PAGER);
  1958.  
  1959. +#endif
  1960.  
  1961. +
  1962.  
  1963. +    gtk_init (&argc, &argv);
  1964.  
  1965. +
  1966.  
  1967. +    deskmenu = g_object_new (DESKMENU_TYPE, NULL);
  1968.  
  1969. +
  1970.  
  1971. +    deskmenu_parse_file (DESKMENU (deskmenu), filename);
  1972.  
  1973. +
  1974.  
  1975. +    dbus_g_connection_register_g_object (connection,
  1976.  
  1977. +                                         DESKMENU_PATH_DBUS,
  1978.  
  1979. +                                         deskmenu);
  1980.  
  1981. +
  1982.  
  1983. +   if (!dbus_bus_request_name (dbus_g_connection_get_connection (connection),
  1984.  
  1985. +                               DESKMENU_SERVICE_DBUS,
  1986.  
  1987. +                                DBUS_NAME_FLAG_REPLACE_EXISTING,
  1988.  
  1989. +                               NULL))
  1990.  
  1991. +        return 1;
  1992.  
  1993. +
  1994.  
  1995. +    gtk_main ();
  1996.  
  1997. +
  1998.  
  1999. +    return 0;
  2000.  
  2001. +}
  2002.  
  2003. +