Pastebin is 300% more awesome when you are logged in. Sign Up, it's FREE!
Guest

Untitled

By: a guest on Nov 10th, 2010  |  syntax: Diff  |  size: 42.11 KB  |  hits: 54  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
This paste has a previous version, view the difference. Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  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. + * compiz-deskmenu is free software; you can redistribute it and/or modify
  665. + * it under the terms of the GNU General Public License as published by
  666. + * the Free Software Foundation; either version 2 of the License, or
  667. + * (at your option) any later version.
  668. + *
  669. + * compiz-deskmenu is distributed in the hope that it will be useful,
  670. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  671. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  672. + * GNU General Public License for more details.
  673. + *
  674. + * You should have received a copy of the GNU General Public License
  675. + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  676. + *
  677. + * Copyright 2008 Christopher Williams <christopherw@verizon.net>
  678. + */
  679. +
  680. +#include <stdlib.h>
  681. +#include <string.h>
  682. +#include <dbus/dbus-glib-lowlevel.h>
  683. +#include <gtk/gtk.h>
  684. +
  685. +#define HAVE_WNCK 1
  686. +
  687. +#if HAVE_WNCK
  688. +#include "deskmenu-wnck.h"
  689. +#endif
  690. +
  691. +#include "deskmenu-menu.h"
  692. +#include "deskmenu-glue.h"
  693. +
  694. +
  695. +G_DEFINE_TYPE(Deskmenu, deskmenu, G_TYPE_OBJECT)
  696. +
  697. +GQuark
  698. +deskmenu_error_quark (void)
  699. +{
  700. +    static GQuark quark = 0;
  701. +    if (!quark)
  702. +        quark = g_quark_from_static_string ("deskmenu_error");
  703. +    return quark;
  704. +}
  705. +
  706. +static void
  707. +quit (GtkWidget *widget,
  708. +      gpointer   data)
  709. +{
  710. +    gtk_main_quit ();
  711. +}
  712. +
  713. +//This is how menu command is launched
  714. +static void
  715. +launcher_activated (GtkWidget *widget,
  716. +                    gchar     *command)
  717. +{
  718. +    GError *error = NULL;
  719. +    Deskmenu *deskmenu;
  720. +
  721. +    deskmenu = g_object_get_data (G_OBJECT (widget), "deskmenu");
  722. +    //stolen from openbox
  723. +    gchar *parse_expand_tilde(const gchar *command)
  724. +       {
  725. +    gchar *ret;
  726. +    GRegex *regex;
  727. +
  728. +    if (!command)
  729. +        return NULL;
  730. +
  731. +    regex = g_regex_new("(?:^|(?<=[ \\t]))~(?:(?=[/ \\t])|$)",
  732. +                        G_REGEX_MULTILINE | G_REGEX_RAW, 0, NULL);
  733. +    ret = g_regex_replace_literal(regex, command, -1, 0, g_get_home_dir(), 0, NULL);
  734. +    g_regex_unref(regex);
  735. +
  736. +    return ret;
  737. +       }
  738. +       //end stolen
  739. +       if (!gdk_spawn_command_line_on_screen (gdk_screen_get_default (), parse_expand_tilde(command), &error))
  740. +    {
  741. +        GtkWidget *message = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR,
  742. +            GTK_BUTTONS_CLOSE, "%s", error->message);
  743. +        gtk_dialog_run (GTK_DIALOG (message));
  744. +        gtk_widget_destroy (message);
  745. +    }
  746. +
  747. +}
  748. +
  749. +static void
  750. +launcher_name_exec_update (GtkWidget *label)
  751. +{
  752. +    gchar *exec, *stdout;
  753. +    exec = g_object_get_data (G_OBJECT (label), "exec");
  754. +    if (g_spawn_command_line_sync (exec, &stdout, NULL, NULL, NULL))
  755. +        gtk_label_set_text (GTK_LABEL (label), g_strstrip(stdout));
  756. +    else
  757. +        gtk_label_set_text (GTK_LABEL (label), "execution error");
  758. +    g_free (stdout);
  759. +}
  760. +
  761. +static void
  762. +deskmenu_construct_item (Deskmenu *deskmenu)
  763. +{
  764. +    DeskmenuItem *item = deskmenu->current_item;
  765. +    GtkWidget *menu_item;
  766. +    gchar *name, *icon, *command;
  767. +
  768. +    switch (item->type)
  769. +    {
  770. +        case DESKMENU_ITEM_LAUNCHER:
  771. +            if (item->name_exec)
  772. +            {
  773. +                GtkWidget *label;
  774. +                GHook *hook;
  775. +                
  776. +                name = g_strstrip (item->name->str);
  777. +
  778. +                menu_item = gtk_image_menu_item_new ();
  779. +                label = gtk_label_new_with_mnemonic (NULL);
  780. +                gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  781. +
  782. +                g_object_set_data (G_OBJECT (label), "exec", g_strdup (name));
  783. +                gtk_container_add (GTK_CONTAINER (menu_item), label);
  784. +                hook = g_hook_alloc (deskmenu->show_hooks);
  785. +
  786. +                hook->data = (gpointer) label;
  787. +                hook->func = (GHookFunc *) launcher_name_exec_update;
  788. +                g_hook_append (deskmenu->show_hooks, hook);
  789. +            }
  790. +            else
  791. +            {
  792. +                if (item->name)
  793. +                    name = g_strstrip (item->name->str);
  794. +                else
  795. +                    name = "";
  796. +
  797. +                menu_item = gtk_image_menu_item_new_with_mnemonic (name);
  798. +
  799. +            }
  800. +
  801. +            if (item->icon)
  802. +            {
  803. +                icon = g_strstrip (item->icon->str);
  804. +                gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
  805. +                    gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU));
  806. +            }
  807. +        
  808. +            if (item->command)
  809. +            {
  810. +                command = g_strstrip (item->command->str);
  811. +                g_object_set_data (G_OBJECT (menu_item), "deskmenu", deskmenu);
  812. +                g_signal_connect (G_OBJECT (menu_item), "activate",
  813. +                    G_CALLBACK (launcher_activated), g_strdup (command));
  814. +            }
  815. +
  816. +            gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
  817. +                menu_item);
  818. +            break;
  819. +
  820. +#if HAVE_WNCK
  821. +        case DESKMENU_ITEM_WINDOWLIST:
  822. +            menu_item = gtk_menu_item_new_with_mnemonic ("_Windows");
  823. +
  824. +            DeskmenuWindowlist *windowlist = deskmenu_windowlist_new ();
  825. +
  826. +            gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item),
  827. +                windowlist->menu);
  828. +            gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
  829. +                menu_item);
  830. +            break;
  831. +
  832. +        case DESKMENU_ITEM_VIEWPORTLIST:
  833. +            menu_item = gtk_menu_item_new_with_mnemonic ("_Viewports");
  834. +
  835. +            DeskmenuVplist *vplist = deskmenu_vplist_new ();
  836. +
  837. +            if (item->wrap
  838. +                && strcmp (g_strstrip (item->wrap->str), "true") == 0)
  839. +                vplist->wrap = TRUE;
  840. +
  841. +            gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item),
  842. +                vplist->menu);
  843. +            gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
  844. +                menu_item);
  845. +            break;
  846. +#endif
  847. +        case DESKMENU_ITEM_RELOAD:
  848. +            menu_item = gtk_image_menu_item_new_with_mnemonic ("_Reload");
  849. +            gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
  850. +                gtk_image_new_from_stock (GTK_STOCK_REFRESH,
  851. +                    GTK_ICON_SIZE_MENU));
  852. +            g_signal_connect (G_OBJECT (menu_item), "activate",
  853. +                G_CALLBACK (quit), NULL);    
  854. +            gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
  855. +                menu_item);
  856. +            break;
  857. +
  858. +        default:
  859. +            break;
  860. +    }
  861. +
  862. +}
  863. +/* The handler functions. */
  864. +
  865. +static void
  866. +start_element (GMarkupParseContext *context,
  867. +               const gchar         *element_name,
  868. +               const gchar        **attr_names,
  869. +               const gchar        **attr_values,
  870. +               gpointer             user_data,
  871. +               GError             **error)
  872. +{
  873. +    Deskmenu *deskmenu = DESKMENU (user_data);
  874. +    DeskmenuElementType element_type;
  875. +    const gchar **ncursor = attr_names, **vcursor = attr_values;
  876. +    GtkWidget *item, *menu;
  877. +
  878. +    element_type = GPOINTER_TO_INT (g_hash_table_lookup
  879. +        (deskmenu->element_hash, element_name));
  880. +
  881. +    if ((deskmenu->menu && !deskmenu->current_menu)
  882. +       || (!deskmenu->menu && element_type != DESKMENU_ELEMENT_MENU))
  883. +    {
  884. +        gint line_num, char_num;
  885. +        g_markup_parse_context_get_position (context, &line_num, &char_num);    
  886. +        g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
  887. +            "Error on line %d char %d: Element '%s' declared outside of "
  888. +            "toplevel menu element", line_num, char_num, element_name);
  889. +        return;
  890. +    }
  891. +
  892. +    switch (element_type)
  893. +    {
  894. +        case DESKMENU_ELEMENT_MENU:
  895. +
  896. +            if (deskmenu->current_item != NULL)
  897. +            {
  898. +                gint line_num, char_num;
  899. +                g_markup_parse_context_get_position (context, &line_num,
  900. +                    &char_num);    
  901. +                g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
  902. +                    "Error on line %d char %d: Element 'menu' cannot be nested "
  903. +                    "inside of an item element", line_num, char_num);
  904. +                return;
  905. +            }
  906. +
  907. +            if (!deskmenu->menu)
  908. +            {
  909. +                deskmenu->menu = gtk_menu_new ();
  910. +                g_object_set_data (G_OBJECT (deskmenu->menu), "parent menu",
  911. +                    NULL);
  912. +                deskmenu->current_menu = deskmenu->menu;
  913. +            }
  914. +            else
  915. +            {
  916. +                gchar *name = NULL;
  917. +                while (*ncursor)
  918. +                {
  919. +                    if (strcmp (*ncursor, "name") == 0)
  920. +                        name = g_strdup (*vcursor);
  921. +                    else
  922. +                        g_set_error (error, G_MARKUP_ERROR,
  923. +                            G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
  924. +                            "Unknown attribute: %s", *ncursor);
  925. +                    ncursor++;
  926. +                    vcursor++;
  927. +                }
  928. +                if (name)
  929. +                    item = gtk_menu_item_new_with_mnemonic (name);
  930. +                else
  931. +                    item = gtk_menu_item_new_with_mnemonic ("");
  932. +                gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
  933. +                    item);
  934. +                menu = gtk_menu_new ();
  935. +                g_object_set_data (G_OBJECT (menu), "parent menu",
  936. +                    deskmenu->current_menu);
  937. +                deskmenu->current_menu = menu;
  938. +                gtk_menu_item_set_submenu (GTK_MENU_ITEM (item),
  939. +                    deskmenu->current_menu);
  940. +                g_free (name);
  941. +            }
  942. +            break;
  943. +        
  944. +        case DESKMENU_ELEMENT_SEPARATOR:
  945. +            break; /* build it in the end function */
  946. +
  947. +        case DESKMENU_ELEMENT_ITEM:
  948. +
  949. +            if (deskmenu->current_item != NULL)
  950. +            {
  951. +                gint line_num, char_num;
  952. +                g_markup_parse_context_get_position (context, &line_num,
  953. +                    &char_num);    
  954. +                g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
  955. +                    "Error on line %d char %d: Element 'item' cannot be nested "
  956. +                    "inside of another item element", line_num, char_num);
  957. +                return;
  958. +            }
  959. +
  960. +            deskmenu->current_item = g_slice_new0 (DeskmenuItem);
  961. +                while (*ncursor)
  962. +                {
  963. +                    if (strcmp (*ncursor, "type") == 0)
  964. +                        deskmenu->current_item->type = GPOINTER_TO_INT
  965. +                        (g_hash_table_lookup (deskmenu->item_hash, *vcursor));
  966. +                    else
  967. +                        g_set_error (error, G_MARKUP_ERROR,
  968. +                            G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
  969. +                            "Unknown attribute: %s", *ncursor);
  970. +                    ncursor++;
  971. +                    vcursor++;
  972. +                }
  973. +            break;
  974. +
  975. +        case DESKMENU_ELEMENT_NAME:
  976. +             while (*ncursor)
  977. +                {
  978. +                    if ((strcmp (*ncursor, "mode") == 0)
  979. +                        && (strcmp (*vcursor, "exec") == 0))
  980. +                        deskmenu->current_item->name_exec = TRUE;
  981. +                    ncursor++;
  982. +                    vcursor++;
  983. +                } /* no break here to let it fall through */
  984. +        case DESKMENU_ELEMENT_ICON:
  985. +        case DESKMENU_ELEMENT_COMMAND:
  986. +        case DESKMENU_ELEMENT_WRAP:
  987. +            if (deskmenu->current_item)
  988. +                deskmenu->current_item->current_element = element_type;
  989. +            break;
  990. +
  991. +        default:
  992. +            g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
  993. +                "Unknown element: %s", element_name);
  994. +            break;
  995. +    }
  996. +}
  997. +
  998. +static void
  999. +text (GMarkupParseContext *context,
  1000. +      const gchar         *text,
  1001. +      gsize                text_len,
  1002. +      gpointer             user_data,
  1003. +      GError             **error)
  1004. +{
  1005. +    Deskmenu *deskmenu = DESKMENU (user_data);
  1006. +    DeskmenuItem *item = deskmenu->current_item;
  1007. +
  1008. +    if (!(item && item->current_element))
  1009. +        return;
  1010. +
  1011. +    switch (item->current_element)
  1012. +    {
  1013. +        case DESKMENU_ELEMENT_NAME:
  1014. +            if (!item->name)
  1015. +                item->name = g_string_new_len (text, text_len);
  1016. +            else
  1017. +                g_string_append_len (item->name, text, text_len);
  1018. +            break;
  1019. +
  1020. +        case DESKMENU_ELEMENT_ICON:
  1021. +            if (!item->icon)
  1022. +                item->icon = g_string_new_len (text, text_len);
  1023. +            else
  1024. +                g_string_append_len (item->icon, text, text_len);
  1025. +            break;
  1026. +
  1027. +        case DESKMENU_ELEMENT_COMMAND:
  1028. +            if (!item->command)
  1029. +                item->command = g_string_new_len (text, text_len);
  1030. +            else
  1031. +                g_string_append_len (item->command, text, text_len);
  1032. +            break;
  1033. +
  1034. +        case DESKMENU_ELEMENT_WRAP:
  1035. +            if (!item->wrap)
  1036. +                item->wrap = g_string_new_len (text, text_len);
  1037. +            else
  1038. +                g_string_append_len (item->wrap, text, text_len);
  1039. +            break;
  1040. +
  1041. +        default:
  1042. +            break;
  1043. +    }
  1044. +
  1045. +}
  1046. +
  1047. +static void
  1048. +end_element (GMarkupParseContext *context,
  1049. +             const gchar         *element_name,
  1050. +             gpointer             user_data,
  1051. +             GError             **error)
  1052. +{
  1053. +
  1054. +    DeskmenuElementType element_type;
  1055. +    Deskmenu *deskmenu = DESKMENU (user_data);
  1056. +    GtkWidget *parent, *item;
  1057. +    element_type = GPOINTER_TO_INT (g_hash_table_lookup
  1058. +        (deskmenu->element_hash, element_name));
  1059. +
  1060. +    switch (element_type)
  1061. +    {
  1062. +        case DESKMENU_ELEMENT_MENU:
  1063. +
  1064. +            g_return_if_fail (deskmenu->current_item == NULL);
  1065. +
  1066. +            parent = g_object_get_data (G_OBJECT (deskmenu->current_menu),
  1067. +                "parent menu");
  1068. +
  1069. +            deskmenu->current_menu = parent;
  1070. +
  1071. +            break;
  1072. +
  1073. +        case DESKMENU_ELEMENT_SEPARATOR:
  1074. +            item = gtk_separator_menu_item_new ();
  1075. +            gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
  1076. +                item);
  1077. +            break;
  1078. +
  1079. +        case DESKMENU_ELEMENT_ITEM:
  1080. +
  1081. +            g_return_if_fail (deskmenu->current_item != NULL);
  1082. +
  1083. +            /* finally make the item ^_^ */
  1084. +            deskmenu_construct_item (deskmenu);
  1085. +
  1086. +            /* free data used to make it */
  1087. +            if (deskmenu->current_item->name)
  1088. +                g_string_free (deskmenu->current_item->name, TRUE);
  1089. +            if (deskmenu->current_item->icon)
  1090. +                g_string_free (deskmenu->current_item->icon, TRUE);
  1091. +            if (deskmenu->current_item->command)
  1092. +                g_string_free (deskmenu->current_item->command, TRUE);
  1093. +            if (deskmenu->current_item->wrap)
  1094. +                g_string_free (deskmenu->current_item->wrap, TRUE);
  1095. +            g_slice_free (DeskmenuItem, deskmenu->current_item);
  1096. +            deskmenu->current_item = NULL;
  1097. +            break;
  1098. +
  1099. +        default:
  1100. +            break;
  1101. +    }
  1102. +}
  1103. +
  1104. +/* The list of what handler does what. */
  1105. +static GMarkupParser parser = {
  1106. +    start_element,
  1107. +    end_element,
  1108. +    text,
  1109. +    NULL,
  1110. +    NULL
  1111. +};
  1112. +
  1113. +
  1114. +/* Class init */
  1115. +static void
  1116. +deskmenu_class_init (DeskmenuClass *deskmenu_class)
  1117. +{
  1118. +    dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (deskmenu_class),
  1119. +        &dbus_glib_deskmenu_object_info);
  1120. +}
  1121. +
  1122. +/* Instance init */
  1123. +static void
  1124. +deskmenu_init (Deskmenu *deskmenu)
  1125. +{
  1126. +
  1127. +    deskmenu->show_hooks = g_slice_new0 (GHookList);
  1128. +
  1129. +    g_hook_list_init (deskmenu->show_hooks, sizeof (GHook));
  1130. +
  1131. +
  1132. +    deskmenu->menu = NULL;
  1133. +    deskmenu->current_menu = NULL;
  1134. +    deskmenu->current_item = NULL;
  1135. +
  1136. +    deskmenu->envp = NULL;
  1137. +
  1138. +    deskmenu->item_hash = g_hash_table_new (g_str_hash, g_str_equal);
  1139. +
  1140. +    g_hash_table_insert (deskmenu->item_hash, "launcher",
  1141. +        GINT_TO_POINTER (DESKMENU_ITEM_LAUNCHER));
  1142. +#if HAVE_WNCK
  1143. +    g_hash_table_insert (deskmenu->item_hash, "windowlist",
  1144. +        GINT_TO_POINTER (DESKMENU_ITEM_WINDOWLIST));
  1145. +    g_hash_table_insert (deskmenu->item_hash, "viewportlist",
  1146. +        GINT_TO_POINTER (DESKMENU_ITEM_VIEWPORTLIST));
  1147. +#endif
  1148. +    g_hash_table_insert (deskmenu->item_hash, "reload",
  1149. +        GINT_TO_POINTER (DESKMENU_ITEM_RELOAD));
  1150. +
  1151. +    deskmenu->element_hash = g_hash_table_new (g_str_hash, g_str_equal);
  1152. +    
  1153. +    g_hash_table_insert (deskmenu->element_hash, "menu",
  1154. +        GINT_TO_POINTER (DESKMENU_ELEMENT_MENU));
  1155. +    g_hash_table_insert (deskmenu->element_hash, "separator",
  1156. +        GINT_TO_POINTER (DESKMENU_ELEMENT_SEPARATOR));
  1157. +    g_hash_table_insert (deskmenu->element_hash, "item",
  1158. +        GINT_TO_POINTER (DESKMENU_ELEMENT_ITEM));
  1159. +    g_hash_table_insert (deskmenu->element_hash, "name",
  1160. +        GINT_TO_POINTER (DESKMENU_ELEMENT_NAME));
  1161. +    g_hash_table_insert (deskmenu->element_hash, "icon",
  1162. +        GINT_TO_POINTER (DESKMENU_ELEMENT_ICON));
  1163. +    g_hash_table_insert (deskmenu->element_hash, "command",
  1164. +        GINT_TO_POINTER (DESKMENU_ELEMENT_COMMAND));
  1165. +    g_hash_table_insert (deskmenu->element_hash, "wrap",
  1166. +        GINT_TO_POINTER (DESKMENU_ELEMENT_WRAP));
  1167. +
  1168. +}
  1169. +
  1170. +static void
  1171. +deskmenu_parse_file (Deskmenu *deskmenu,
  1172. +                     gchar *configpath)
  1173. +{
  1174. +    GError *error = NULL;
  1175. +    gboolean success = FALSE;
  1176. +    gchar *text;
  1177. +    gsize length;
  1178. +    
  1179. +    if (!configpath)
  1180. +        configpath = g_build_path (G_DIR_SEPARATOR_S,
  1181. +                                   g_get_user_config_dir (),
  1182. +                                   "compiz",
  1183. +                                   "deskmenu",
  1184. +                                   "menu.xml",
  1185. +                                   NULL);
  1186. +
  1187. +    GMarkupParseContext *context = g_markup_parse_context_new (&parser,
  1188. +        0, deskmenu, NULL);
  1189. +
  1190. +    if (!g_file_get_contents (configpath, &text, &length, NULL))
  1191. +    {
  1192. +        const gchar* const *cursor = g_get_system_config_dirs ();
  1193. +        gchar *path = NULL;
  1194. +        while (*cursor)
  1195. +        {
  1196. +            g_free (configpath);
  1197. +            g_free (path);
  1198. +            path = g_strdup (*cursor);
  1199. +            configpath = g_build_path (G_DIR_SEPARATOR_S,
  1200. +                                       path,
  1201. +                                       "compiz",
  1202. +                                       "deskmenu",
  1203. +                                       "menu.xml",
  1204. +                                       NULL);
  1205. +
  1206. +            if (g_file_get_contents (configpath, &text, &length, NULL))
  1207. +            {
  1208. +                success = TRUE;
  1209. +                g_free (path);
  1210. +                break;
  1211. +            }
  1212. +            cursor++;
  1213. +        }
  1214. +    }
  1215. +    else
  1216. +    {
  1217. +        success = TRUE;
  1218. +    }
  1219. +
  1220. +    if (!success)
  1221. +    {
  1222. +        g_printerr ("Couldn't find a menu file\n");
  1223. +        exit (1);
  1224. +    }
  1225. +
  1226. +    if (!g_markup_parse_context_parse (context, text, length, &error)
  1227. +        || !g_markup_parse_context_end_parse (context, &error))
  1228. +    {
  1229. +        g_printerr ("Parse of %s failed with message: %s \n",
  1230. +            configpath, error->message);
  1231. +        g_error_free (error);
  1232. +        exit (1);
  1233. +    }
  1234. +
  1235. +    g_free(text);
  1236. +    g_free (configpath);
  1237. +    g_markup_parse_context_free (context);
  1238. +
  1239. +    gtk_widget_show_all (deskmenu->menu);
  1240. +}
  1241. +
  1242. +/* The show method */
  1243. +gboolean
  1244. +deskmenu_show (Deskmenu *deskmenu,
  1245. +               gchar **env,
  1246. +               GError  **error)
  1247. +{
  1248. +    g_hook_list_invoke (deskmenu->show_hooks, FALSE);
  1249. +
  1250. +    if (deskmenu->envp)
  1251. +        g_strfreev (deskmenu->envp);
  1252. +
  1253. +    deskmenu->envp = g_strdupv (env);
  1254. +
  1255. +    gtk_menu_popup (GTK_MENU (deskmenu->menu),
  1256. +                    NULL, NULL, NULL, NULL,
  1257. +                    0, 0);
  1258. +    return TRUE;
  1259. +}
  1260. +
  1261. +/* The reload method */
  1262. +gboolean
  1263. +deskmenu_reload (Deskmenu *deskmenu,
  1264. +               GError  **error)
  1265. +{
  1266. +    gtk_main_quit ();
  1267. +    return TRUE;
  1268. +}
  1269. +
  1270. +int
  1271. +main (int    argc,
  1272. +      char **argv)
  1273. +{
  1274. +    DBusGConnection *connection;
  1275. +    GError *error = NULL;
  1276. +    GObject *deskmenu;
  1277. +
  1278. +    g_type_init ();
  1279. +
  1280. +    gchar *filename = NULL;
  1281. +    GOptionContext *context;
  1282. +    GOptionEntry entries[] =
  1283. +    {
  1284. +        { "menu", 'm', 0, G_OPTION_ARG_FILENAME, &filename,
  1285. +            "Use FILE instead of the default menu file", "FILE" },
  1286. +        { NULL, 0, 0, 0, NULL, NULL, NULL }
  1287. +    };
  1288. +
  1289. +    context = g_option_context_new (NULL);
  1290. +    g_option_context_add_main_entries (context, entries, NULL);
  1291. +    g_option_context_add_group (context, gtk_get_option_group (TRUE));
  1292. +    if (!g_option_context_parse (context, &argc, &argv, &error))
  1293. +    {
  1294. +        g_printerr ("option parsing failed: %s", error->message);
  1295. +        g_error_free (error);
  1296. +        exit (1);
  1297. +    }
  1298. +    g_option_context_free (context);
  1299. +
  1300. +    /* Obtain a connection to the session bus */
  1301. +    connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
  1302. +    if (connection == NULL)
  1303. +    {
  1304. +        g_printerr ("Failed to open connection to bus: %s", error->message);
  1305. +        g_error_free (error);
  1306. +        exit (1);
  1307. +    }
  1308. +
  1309. +#if HAVE_WNCK
  1310. +    wnck_set_client_type (WNCK_CLIENT_TYPE_PAGER);
  1311. +#endif
  1312. +
  1313. +    gtk_init (&argc, &argv);
  1314. +
  1315. +    deskmenu = g_object_new (DESKMENU_TYPE, NULL);
  1316. +
  1317. +    deskmenu_parse_file (DESKMENU (deskmenu), filename);
  1318. +
  1319. +    dbus_g_connection_register_g_object (connection,
  1320. +                                         DESKMENU_PATH_DBUS,
  1321. +                                         deskmenu);
  1322. +
  1323. +       if (!dbus_bus_request_name (dbus_g_connection_get_connection (connection),
  1324. +                                                       DESKMENU_SERVICE_DBUS,
  1325. +                                DBUS_NAME_FLAG_REPLACE_EXISTING,
  1326. +                                                       NULL))
  1327. +        return 1;
  1328. +
  1329. +    gtk_main ();
  1330. +
  1331. +    return 0;
  1332. +}
  1333. +