Guest User

somehow unable to access the parser variable in pipe function even though it's static

a guest
Nov 12th, 2010
108
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 27.81 KB | None | 0 0
  1. /*
  2.  * compiz-deskmenu is free software; you can redistribute it and/or modify
  3.  * it under the terms of the GNU General Public License as published by
  4.  * the Free Software Foundation; either version 2 of the License, or
  5.  * (at your option) any later version.
  6.  *
  7.  * compiz-deskmenu is distributed in the hope that it will be useful,
  8.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10.  * GNU General Public License for more details.
  11.  *
  12.  * You should have received a copy of the GNU General Public License
  13.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  14.  *
  15.  * Copyright 2008 Christopher Williams <[email protected]>
  16.  */
  17.  
  18.  /*
  19. Roadmap:
  20. Necessary:
  21.     TODO: Add tilde expansion for icons in both the editor and the menu
  22.     TODO: pipe menu capabilities
  23.     TODO: Possibly migrate it to the libxml parser to allow this, study libxml2 parser
  24.     TODO: Add a viewport # indicator for the window list for accesiblity reasons
  25. For fun, might not implement:
  26.     TODO: Add ability to call up menus from the menu.xml file by name, if this is really, really needed or requested
  27.     TODO: Add ability to "detach" menus to keep certain menus open even after launch, if this is really requested for fun or usability
  28.     * http://www.xmlsoft.org/html/libxml-tree.html
  29.     * http://xmlsoft.org/tutorial/index.html
  30.     * http://www.xmlsoft.org/html/libxml-parser.html
  31.  */
  32.  
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <dbus/dbus-glib-lowlevel.h>
  36. #include <gtk/gtk.h>
  37.  
  38. #define HAVE_WNCK 1
  39.  
  40. #if HAVE_WNCK
  41. #include "deskmenu-wnck.h"
  42. #endif
  43.  
  44. #include "deskmenu-menu.h"
  45. #include "deskmenu-glue.h"
  46.  
  47.  
  48. G_DEFINE_TYPE(Deskmenu, deskmenu, G_TYPE_OBJECT)
  49.  
  50. GQuark
  51. deskmenu_error_quark (void)
  52. {
  53.     static GQuark quark = 0;
  54.     if (!quark)
  55.         quark = g_quark_from_static_string ("deskmenu_error");
  56.     return quark;
  57. }
  58.  
  59. static void
  60. quit (GtkWidget *widget,
  61.       gpointer   data)
  62. {
  63.     gtk_main_quit ();
  64. }
  65.  
  66. //stolen from openbox, possibly move this outside in order to make it a function to parse launchers and icon location
  67. gchar *parse_expand_tilde(const gchar *f)
  68. {
  69. gchar *ret;
  70. GRegex *regex;
  71.  
  72. if (!f)
  73.     return NULL;
  74.  
  75. regex = g_regex_new("(?:^|(?<=[ \\t]))~(?:(?=[/ \\t])|$)",
  76.                     G_REGEX_MULTILINE | G_REGEX_RAW, 0, NULL);
  77. ret = g_regex_replace_literal(regex, f, -1, 0, g_get_home_dir(), 0, NULL);
  78. g_regex_unref(regex);
  79.  
  80. return ret;
  81. }
  82. //end stolen
  83.  
  84. //This is how menu command is launched
  85. static void
  86. launcher_activated (GtkWidget *widget,
  87.                     gchar     *command)
  88. {
  89.     GError *error = NULL;
  90.     Deskmenu *deskmenu;
  91.    
  92.     deskmenu = g_object_get_data (G_OBJECT (widget), "deskmenu");
  93.     if (!gdk_spawn_command_line_on_screen (gdk_screen_get_default (), parse_expand_tilde(command), &error))
  94.     {
  95.         GtkWidget *message = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR,
  96.             GTK_BUTTONS_CLOSE, "%s", error->message);
  97.         gtk_dialog_run (GTK_DIALOG (message));
  98.         gtk_widget_destroy (message);
  99.     }
  100.  
  101. }
  102.  
  103. //place & in front of stdout for standard stdout, how a command is launched as an exec
  104. static void
  105. launcher_name_exec_update (GtkWidget *label)
  106. {
  107.     gchar *exec, *stdout;
  108.     exec = g_object_get_data (G_OBJECT (label), "exec");
  109.     if (g_spawn_command_line_sync (parse_expand_tilde(exec), &stdout, NULL, NULL, NULL))
  110.         gtk_label_set_text (GTK_LABEL (label), g_strstrip(stdout));
  111.     else
  112.         gtk_label_set_text (GTK_LABEL (label), "execution error");
  113.     g_free (stdout);
  114. }
  115.  
  116. //TODO: Will be used for making entries based on pipemenus, hopefully. Examine lines 144-175,308-344 of menu.c o' openbox, parse.c's 191-212
  117. /*
  118. static void
  119. pipe_entries_update (gchar *command,
  120.                     Deskmenu *deskmenu)
  121. {
  122.     gchar *stdout;
  123.     gsize length;
  124.  
  125.     GMarkupParseContext *context = g_markup_parse_context_new (&parser,
  126.        0, deskmenu, NULL); //somehow this can't get the parser variable, yet deskmenu_parse_file can
  127.     //deskmenu = g_object_get_data (G_OBJECT (menu_item), "deskmenu");
  128.     if (g_spawn_command_line_sync (parse_expand_tilde(command), &stdout, NULL, NULL, NULL)) {
  129.         length = strlen(stdout); //possibly ineffecient, but it needs to look at all of the pipe
  130.         //feed the stdout of the pipeitem script to the parser for a moment
  131.         g_markup_parse_context_parse (context, g_markup_escape_text (stdout,length), length, NULL);
  132.     }
  133.     else {
  134.         //don't break the program or make the pipeitem disappear, instead, show an error message
  135.         //gtk_image_menu_item_new_with_mnemonic ("execution error");
  136.     }
  137.     g_free (stdout);
  138. }
  139. */
  140.  
  141. static void
  142. deskmenu_construct_item (Deskmenu *deskmenu)
  143. {
  144.     DeskmenuItem *item = deskmenu->current_item;
  145.     GtkWidget *menu_item;
  146.     gchar *name, *icon, *command;
  147.     gint w, h;
  148. //constructs the items in menu
  149.     switch (item->type)
  150.     {
  151.         case DESKMENU_ITEM_LAUNCHER:
  152.             if (item->name_exec)
  153.             {
  154.                 GtkWidget *label;
  155.                 GHook *hook;
  156.  
  157.                 name = g_strstrip (item->name->str);
  158.  
  159.                 menu_item = gtk_image_menu_item_new ();
  160.                 label = gtk_label_new_with_mnemonic (NULL);
  161.                 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  162.  
  163.                 g_object_set_data (G_OBJECT (label), "exec", g_strdup (name));
  164.                 gtk_container_add (GTK_CONTAINER (menu_item), label);
  165.                 hook = g_hook_alloc (deskmenu->show_hooks);
  166.  
  167.                 hook->data = (gpointer) label;
  168.                 hook->func = (GHookFunc *) launcher_name_exec_update;
  169.                 g_hook_append (deskmenu->show_hooks, hook);
  170.             }
  171.             else
  172.             {
  173.                 if (item->name)
  174.                     name = g_strstrip (item->name->str);
  175.                 else
  176.                     name = "";
  177.  
  178.                 menu_item = gtk_image_menu_item_new_with_mnemonic (name);
  179.  
  180.             }
  181.             if (item->icon)
  182.             {
  183.                 icon = g_strstrip (item->icon->str);
  184.                 if (item->icon_file) {
  185.                     gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);
  186.                     gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM
  187.                        (menu_item), gtk_image_new_from_pixbuf (gdk_pixbuf_new_from_file_at_size (icon, w, h, NULL)));
  188.                    }
  189.                 else {
  190.                     gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
  191.                         gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU));
  192.                     }
  193.             }
  194.  
  195.             if (item->command)
  196.             {
  197.                 command = g_strstrip (item->command->str);
  198.                 g_object_set_data (G_OBJECT (menu_item), "deskmenu", deskmenu);
  199.                 g_signal_connect (G_OBJECT (menu_item), "activate",
  200.                     G_CALLBACK (launcher_activated), g_strdup (command));
  201.             }
  202.  
  203.             gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
  204.                 menu_item);
  205.             break;
  206.             /*
  207.             @h@case DESKMENU_ITEM_PIPE: //make this work someday
  208.             @h@if (item->command) //TODO: Make this actually construct dynamic menus
  209.             @h@{
  210.             @h@ command = g_strstrip (item->command->str);
  211.             @h@ //g_object_set_data (G_OBJECT (menu_item), "deskmenu", deskmenu);
  212.             @h@ pipe_entries_update (g_strdup (command), deskmenu);
  213.             @h@}
  214.             @h@else{
  215.             @h@ printf("Where is your command?");
  216.             @h@}
  217.             @h@break;
  218.             @h@*/
  219. #if HAVE_WNCK
  220.         case DESKMENU_ITEM_WINDOWLIST:
  221.             menu_item = gtk_image_menu_item_new_with_mnemonic ("_Windows");
  222.  
  223.             DeskmenuWindowlist *windowlist = deskmenu_windowlist_new ();
  224.             gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item),
  225.                 windowlist->menu);
  226.             gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
  227.                 menu_item);
  228.             if (item->icon)
  229.             {
  230.                 windowlist->images = TRUE;
  231.                 icon = g_strstrip (item->icon->str);
  232.                 if (item->icon_file) {
  233.                     gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);
  234.                     gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM
  235.                        (menu_item), gtk_image_new_from_pixbuf (gdk_pixbuf_new_from_file_at_size (icon, w, h, NULL)));
  236.                 }
  237.                 else {
  238.                     gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
  239.                         gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU));
  240.                 }
  241.             }
  242.             break;
  243.  
  244.         case DESKMENU_ITEM_VIEWPORTLIST:
  245.             menu_item = gtk_image_menu_item_new_with_mnemonic ("_Viewports");
  246.  
  247.             DeskmenuVplist *vplist = deskmenu_vplist_new ();
  248.             if (item->wrap
  249.                 && strcmp (g_strstrip (item->wrap->str), "true") == 0)
  250.                 vplist->wrap = TRUE;
  251.  
  252.             gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item),
  253.                 vplist->menu);
  254.             gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
  255.                 menu_item);
  256.             if (item->icon)
  257.             {
  258.                 vplist->images = TRUE;
  259.                 icon = g_strstrip (item->icon->str);
  260.                 if (item->icon_file) {
  261.                     gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);
  262.                     gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM
  263.                        (menu_item), gtk_image_new_from_pixbuf (gdk_pixbuf_new_from_file_at_size (icon, w, h, NULL)));
  264.                 }
  265.                 else {
  266.                     gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
  267.                         gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU));
  268.                 }
  269.             }
  270.             break;
  271. #endif
  272.         case DESKMENU_ITEM_RELOAD:
  273.             menu_item = gtk_image_menu_item_new_with_mnemonic ("_Reload");
  274.             if (item->icon)
  275.             {
  276.                 icon = g_strstrip (item->icon->str);
  277.                 if (item->icon_file) {
  278.                     gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);
  279.                     gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM
  280.                        (menu_item), gtk_image_new_from_pixbuf (gdk_pixbuf_new_from_file_at_size (icon, w, h, NULL)));
  281.                 }
  282.                 else {
  283.                     gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
  284.                         gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU));
  285.                 }
  286.             }
  287.             g_signal_connect (G_OBJECT (menu_item), "activate",
  288.                 G_CALLBACK (quit), NULL);
  289.             gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
  290.                 menu_item);
  291.             break;
  292.  
  293.         default:
  294.             break;
  295.     }
  296.  
  297. }
  298. /* The handler functions. */
  299.  
  300. static void
  301. start_element (GMarkupParseContext *context,
  302.                const gchar         *element_name,
  303.                const gchar        **attr_names,
  304.                const gchar        **attr_values,
  305.                gpointer             user_data,
  306.                GError             **error)
  307. {
  308.     Deskmenu *deskmenu = DESKMENU (user_data);
  309.     DeskmenuElementType element_type;
  310.     const gchar **ncursor = attr_names, **vcursor = attr_values;
  311.     GtkWidget *item, *menu;
  312.  
  313.     element_type = GPOINTER_TO_INT (g_hash_table_lookup
  314.         (deskmenu->element_hash, element_name));
  315.  
  316.     //TODO: maybe this could be edited to see the new compiz-deskmenu element, if this is needed in order to make pipes
  317.     if ((deskmenu->menu && !deskmenu->current_menu)
  318.        || (!deskmenu->menu && element_type != DESKMENU_ELEMENT_MENU))
  319.     {
  320.         gint line_num, char_num;
  321.         g_markup_parse_context_get_position (context, &line_num, &char_num);
  322.         g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
  323.             "Error on line %d char %d: Element '%s' declared outside of "
  324.             "toplevel menu element", line_num, char_num, element_name);
  325.         return;
  326.     }
  327.  
  328.     switch (element_type)
  329.     {
  330.         case DESKMENU_ELEMENT_MENU:
  331.  
  332.             if (deskmenu->current_item != NULL)
  333.             {
  334.                 gint line_num, char_num;
  335.                 g_markup_parse_context_get_position (context, &line_num,
  336.                     &char_num);
  337.                 g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
  338.                     "Error on line %d char %d: Element 'menu' cannot be nested "
  339.                     "inside of an item element", line_num, char_num);
  340.                 return;
  341.             }
  342.             //TODO: maybe this could be moved to see the new compiz-deskmenu element, if this is needed in order to make pipes
  343.             if (!deskmenu->menu)
  344.             {
  345.                 deskmenu->menu = gtk_menu_new ();
  346.                 g_object_set_data (G_OBJECT (deskmenu->menu), "parent menu",
  347.                     NULL);
  348.                 deskmenu->current_menu = deskmenu->menu;
  349.             }
  350.             else
  351.             {
  352.                 gchar *name = NULL;
  353.                 gchar *icon = NULL;
  354.                 gboolean name_exec = FALSE;
  355.                 gboolean icon_file = FALSE;
  356.                 gint w, h;
  357.                 while (*ncursor)
  358.                 {
  359.                     if (strcmp (*ncursor, "name") == 0)
  360.                         name = g_strdup (*vcursor);
  361.                     else if (strcmp (*ncursor, "icon") == 0)
  362.                         icon = g_strdup (*vcursor);
  363.                     else if ((strcmp (*ncursor, "mode") == 0)
  364.                         && (strcmp (*vcursor, "exec") == 0))
  365.                         name_exec = TRUE;
  366.                     else if ((strcmp (*ncursor, "mode1") == 0)
  367.                         && (strcmp (*vcursor, "file") == 0))
  368.                         icon_file = TRUE;
  369.                     else
  370.                         g_set_error (error, G_MARKUP_ERROR,
  371.                             G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
  372.                             "Unknown attribute: %s", *ncursor);
  373.                     ncursor++;
  374.                     vcursor++;
  375.                 }
  376.                 if (name_exec)
  377.                 {
  378.                     GtkWidget *label;
  379.                     GHook *hook;
  380.                
  381.                     item = gtk_image_menu_item_new ();
  382.                     label = gtk_label_new_with_mnemonic (NULL);
  383.                     gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  384.                
  385.                     g_object_set_data (G_OBJECT (label), "exec", g_strdup (name));
  386.                     gtk_container_add (GTK_CONTAINER (item), label);
  387.                     hook = g_hook_alloc (deskmenu->show_hooks);
  388.                
  389.                     hook->data = (gpointer) label;
  390.                     hook->func = (GHookFunc *) launcher_name_exec_update;
  391.                     g_hook_append (deskmenu->show_hooks, hook);
  392.                 }
  393.                 else
  394.                 {
  395.                     if (name)
  396.                         item = gtk_image_menu_item_new_with_mnemonic (name); //allow menus to have icons
  397.                
  398.                     else
  399.                         item = gtk_image_menu_item_new_with_mnemonic ("");
  400.                     gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
  401.                         item);
  402.                 }
  403.                 if (icon)
  404.                 {
  405.                     if (icon_file) {
  406.                     gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);
  407.                     gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM
  408.                        (item), gtk_image_new_from_pixbuf (gdk_pixbuf_new_from_file_at_size (icon, w, h, NULL)));
  409.                     }
  410.                     else {
  411.                     gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
  412.                         gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU));
  413.                     }
  414.                 }
  415.                 menu = gtk_menu_new ();
  416.                 g_object_set_data (G_OBJECT (menu), "parent menu",
  417.                     deskmenu->current_menu);
  418.                 deskmenu->current_menu = menu;
  419.                 gtk_menu_item_set_submenu (GTK_MENU_ITEM (item),
  420.                     deskmenu->current_menu);
  421.                 g_free (name);
  422.                 g_free (icon);
  423.             }
  424.             break;
  425.  
  426.         case DESKMENU_ELEMENT_SEPARATOR:
  427.             break; /* build it in the end function */
  428.  
  429.         case DESKMENU_ELEMENT_ITEM:
  430.  
  431.             if (deskmenu->current_item != NULL)
  432.             {
  433.                 gint line_num, char_num;
  434.                 g_markup_parse_context_get_position (context, &line_num,
  435.                     &char_num);
  436.                 g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
  437.                     "Error on line %d char %d: Element 'item' cannot be nested "
  438.                     "inside of another item element", line_num, char_num);
  439.                 return;
  440.             }
  441.  
  442.             deskmenu->current_item = g_slice_new0 (DeskmenuItem);
  443.                 while (*ncursor)
  444.                 {
  445.                     if (strcmp (*ncursor, "type") == 0)
  446.                         deskmenu->current_item->type = GPOINTER_TO_INT
  447.                         (g_hash_table_lookup (deskmenu->item_hash, *vcursor));
  448.                     else
  449.                         g_set_error (error, G_MARKUP_ERROR,
  450.                             G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
  451.                             "Unknown attribute: %s", *ncursor);
  452.                     ncursor++;
  453.                     vcursor++;
  454.                 }
  455.             break;
  456.  
  457.         case DESKMENU_ELEMENT_NAME:
  458.              while (*ncursor)
  459.                 {
  460.                     if ((strcmp (*ncursor, "mode") == 0)
  461.                         && (strcmp (*vcursor, "exec") == 0))
  462.                         deskmenu->current_item->name_exec = TRUE;
  463.                     ncursor++;
  464.                     vcursor++;
  465.                 } /* no break here to let it fall through */
  466.         case DESKMENU_ELEMENT_ICON:
  467.                 while (*ncursor)
  468.                 {
  469.                     if ((strcmp (*ncursor, "mode1") == 0)
  470.                         && (strcmp (*vcursor, "file") == 0))
  471.                         deskmenu->current_item->icon_file = TRUE;
  472.                     ncursor++;
  473.                     vcursor++;
  474.                 } /* no break here to let it fall through */
  475.         case DESKMENU_ELEMENT_COMMAND:
  476.         case DESKMENU_ELEMENT_WRAP:
  477.             if (deskmenu->current_item)
  478.                 deskmenu->current_item->current_element = element_type;
  479.             break;
  480.         default:
  481.             g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
  482.                 "Unknown element: %s", element_name);
  483.             break;
  484.     }
  485. }
  486. //dealing with empty attributes
  487. static void
  488. text (GMarkupParseContext *context,
  489.       const gchar         *text,
  490.       gsize                text_len,
  491.       gpointer             user_data,
  492.       GError             **error)
  493. {
  494.     Deskmenu *deskmenu = DESKMENU (user_data);
  495.     DeskmenuItem *item = deskmenu->current_item;
  496.  
  497.     if (!(item && item->current_element))
  498.         return;
  499.  
  500.     switch (item->current_element)
  501.     {
  502.         case DESKMENU_ELEMENT_NAME:
  503.             if (!item->name)
  504.                 item->name = g_string_new_len (text, text_len);
  505.             else
  506.                 g_string_append_len (item->name, text, text_len);
  507.             break;
  508.  
  509.         case DESKMENU_ELEMENT_ICON:
  510.             if (!item->icon)
  511.                 item->icon = g_string_new_len (text, text_len);
  512.             else
  513.                 g_string_append_len (item->icon, text, text_len);
  514.             break;
  515.  
  516.         case DESKMENU_ELEMENT_COMMAND:
  517.             if (!item->command)
  518.                 item->command = g_string_new_len (text, text_len);
  519.             else
  520.                 g_string_append_len (item->command, text, text_len);
  521.             break;
  522.  
  523.         case DESKMENU_ELEMENT_WRAP:
  524.             if (!item->wrap)
  525.                 item->wrap = g_string_new_len (text, text_len);
  526.             else
  527.                 g_string_append_len (item->wrap, text, text_len);
  528.             break;
  529.  
  530.         default:
  531.             break;
  532.     }
  533.  
  534. }
  535.  
  536. static void
  537. end_element (GMarkupParseContext *context,
  538.              const gchar         *element_name,
  539.              gpointer             user_data,
  540.              GError             **error)
  541. {
  542.  
  543.     DeskmenuElementType element_type;
  544.     Deskmenu *deskmenu = DESKMENU (user_data);
  545.     GtkWidget *parent, *item;
  546.     element_type = GPOINTER_TO_INT (g_hash_table_lookup
  547.         (deskmenu->element_hash, element_name));
  548.  
  549.     switch (element_type)
  550.     {
  551.         case DESKMENU_ELEMENT_MENU:
  552.  
  553.             g_return_if_fail (deskmenu->current_item == NULL);
  554.  
  555.             parent = g_object_get_data (G_OBJECT (deskmenu->current_menu),
  556.                 "parent menu");
  557.  
  558.             deskmenu->current_menu = parent;
  559.  
  560.             break;
  561.  
  562.         case DESKMENU_ELEMENT_SEPARATOR:
  563.             item = gtk_separator_menu_item_new ();
  564.             gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
  565.                 item);
  566.             break;
  567.  
  568.         case DESKMENU_ELEMENT_ITEM:
  569.  
  570.             g_return_if_fail (deskmenu->current_item != NULL);
  571.  
  572.             /* finally make the item ^_^ */
  573.             deskmenu_construct_item (deskmenu);
  574.  
  575.             /* free data used to make it */
  576.             if (deskmenu->current_item->name)
  577.                 g_string_free (deskmenu->current_item->name, TRUE);
  578.             if (deskmenu->current_item->icon)
  579.                 g_string_free (deskmenu->current_item->icon, TRUE);
  580.             if (deskmenu->current_item->command)
  581.                 g_string_free (deskmenu->current_item->command, TRUE);
  582.             if (deskmenu->current_item->wrap)
  583.                 g_string_free (deskmenu->current_item->wrap, TRUE);
  584.             g_slice_free (DeskmenuItem, deskmenu->current_item);
  585.             deskmenu->current_item = NULL;
  586.             break;
  587.         default:
  588.             break;
  589.     }
  590. }
  591.  
  592. /* The list of what handler does what. */
  593. //this parses menus
  594. static GMarkupParser parser = {
  595.     start_element,
  596.     end_element,
  597.     text,
  598.     NULL,
  599.     NULL
  600. };
  601.  
  602. /* Class init */
  603. static void
  604. deskmenu_class_init (DeskmenuClass *deskmenu_class)
  605. {
  606.     dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (deskmenu_class),
  607.         &dbus_glib_deskmenu_object_info);
  608. }
  609.  
  610. /* Instance init, matches up words to types */
  611. static void
  612. deskmenu_init (Deskmenu *deskmenu)
  613. {
  614.  
  615.     deskmenu->show_hooks = g_slice_new0 (GHookList);
  616.  
  617.     g_hook_list_init (deskmenu->show_hooks, sizeof (GHook));
  618.  
  619.  
  620.     deskmenu->menu = NULL;
  621.     deskmenu->current_menu = NULL;
  622.     deskmenu->current_item = NULL;
  623.  
  624.     deskmenu->envp = NULL;
  625.  
  626.     deskmenu->item_hash = g_hash_table_new (g_str_hash, g_str_equal);
  627.  
  628.     g_hash_table_insert (deskmenu->item_hash, "launcher",
  629.         GINT_TO_POINTER (DESKMENU_ITEM_LAUNCHER));
  630. #if HAVE_WNCK
  631.     g_hash_table_insert (deskmenu->item_hash, "windowlist",
  632.         GINT_TO_POINTER (DESKMENU_ITEM_WINDOWLIST));
  633.     g_hash_table_insert (deskmenu->item_hash, "viewportlist",
  634.         GINT_TO_POINTER (DESKMENU_ITEM_VIEWPORTLIST));
  635. #endif
  636.     g_hash_table_insert (deskmenu->item_hash, "reload",
  637.         GINT_TO_POINTER (DESKMENU_ITEM_RELOAD));
  638.     g_hash_table_insert (deskmenu->item_hash, "pipe",
  639.         GINT_TO_POINTER (DESKMENU_ITEM_PIPE));
  640.  
  641.     deskmenu->element_hash = g_hash_table_new (g_str_hash, g_str_equal);
  642.    
  643.     g_hash_table_insert (deskmenu->element_hash, "menu",
  644.         GINT_TO_POINTER (DESKMENU_ELEMENT_MENU));
  645.     g_hash_table_insert (deskmenu->element_hash, "separator",
  646.         GINT_TO_POINTER (DESKMENU_ELEMENT_SEPARATOR));
  647.     g_hash_table_insert (deskmenu->element_hash, "item",
  648.         GINT_TO_POINTER (DESKMENU_ELEMENT_ITEM));
  649.     g_hash_table_insert (deskmenu->element_hash, "name",
  650.         GINT_TO_POINTER (DESKMENU_ELEMENT_NAME));
  651.     g_hash_table_insert (deskmenu->element_hash, "icon",
  652.         GINT_TO_POINTER (DESKMENU_ELEMENT_ICON));
  653.     g_hash_table_insert (deskmenu->element_hash, "command",
  654.         GINT_TO_POINTER (DESKMENU_ELEMENT_COMMAND));
  655.     g_hash_table_insert (deskmenu->element_hash, "wrap",
  656.         GINT_TO_POINTER (DESKMENU_ELEMENT_WRAP));
  657.  
  658. }
  659.  
  660. //Openbox's menu.c has info for constructing menu from pipe output
  661. static void
  662. deskmenu_parse_file (Deskmenu *deskmenu,
  663.                      gchar *configpath)
  664. {
  665.     GError *error = NULL;
  666.     gboolean success = FALSE;
  667.     gchar *text;
  668.     gsize length;
  669.  
  670.     if (!configpath)
  671.         configpath = g_build_path (G_DIR_SEPARATOR_S,
  672.                                    g_get_user_config_dir (),
  673.                                    "compiz",
  674.                                    "deskmenu",
  675.                                    "menu.xml",
  676.                                    NULL);
  677. //this is only inside THIS function...and that's a problem for making pipe menus
  678. //needs to somehow remain global AND a const variable so both this and the pipemaker can use it without getting
  679. //until then, I can't test whether it parses correctly for the pipes
  680.     GMarkupParseContext *context = g_markup_parse_context_new (&parser,
  681.         0, deskmenu, NULL);
  682.  
  683.     if (!g_file_get_contents (configpath, &text, &length, NULL))
  684.     {
  685.         const gchar* const *cursor = g_get_system_config_dirs ();
  686.         gchar *path = NULL;
  687.         while (*cursor)
  688.         {
  689.             g_free (configpath);
  690.             g_free (path);
  691.             path = g_strdup (*cursor);
  692.             configpath = g_build_path (G_DIR_SEPARATOR_S,
  693.                                        path,
  694.                                        "compiz",
  695.                                        "deskmenu",
  696.                                        "menu.xml",
  697.                                        NULL);
  698.  
  699.             if (g_file_get_contents (configpath, &text, &length, NULL))
  700.             {
  701.                 success = TRUE;
  702.                 g_free (path);
  703.                 break;
  704.             }
  705.             cursor++;
  706.         }
  707.     }
  708.     else
  709.     {
  710.         success = TRUE;
  711.     }
  712.  
  713.     if (!success)
  714.     {
  715.         g_printerr ("Couldn't find a menu file\n");
  716.         exit (1);
  717.     }
  718.  
  719.     if (!g_markup_parse_context_parse (context, text, length, &error)
  720.         || !g_markup_parse_context_end_parse (context, &error))
  721.     {
  722.         g_printerr ("Parse of %s failed with message: %s \n",
  723.             configpath, error->message);
  724.         g_error_free (error);
  725.         exit (1);
  726.     }
  727.  
  728.     g_free(text);
  729.     g_free (configpath);
  730.     g_markup_parse_context_free (context);
  731.  
  732.     gtk_widget_show_all (deskmenu->menu);
  733. }
  734.  
  735. /* The show method */
  736. gboolean
  737. deskmenu_show (Deskmenu *deskmenu,
  738.                gchar **env,
  739.                GError  **error)
  740. {
  741.     g_hook_list_invoke (deskmenu->show_hooks, FALSE);
  742.  
  743.     if (deskmenu->envp)
  744.         g_strfreev (deskmenu->envp);
  745.  
  746.     deskmenu->envp = g_strdupv (env);
  747.  
  748.     gtk_menu_popup (GTK_MENU (deskmenu->menu),
  749.                     NULL, NULL, NULL, NULL,
  750.                     0, 0);
  751.     return TRUE;
  752. }
  753.  
  754. /* The reload method */
  755. gboolean
  756. deskmenu_reload (Deskmenu *deskmenu,
  757.                GError  **error)
  758. {
  759.     gtk_main_quit ();
  760.     return TRUE;
  761. }
  762.  
  763. int
  764. main (int    argc,
  765.       char **argv)
  766. {
  767.     DBusGConnection *connection;
  768.     GError *error = NULL;
  769.     GObject *deskmenu;
  770.  
  771.     g_type_init ();
  772.  
  773.     gchar *filename = NULL;
  774.     GOptionContext *context;
  775.     GOptionEntry entries[] =
  776.     {
  777.         { "menu", 'm', 0, G_OPTION_ARG_FILENAME, &filename,
  778.             "Use FILE instead of the default menu file", "FILE" },
  779.         { NULL, 0, 0, 0, NULL, NULL, NULL }
  780.     };
  781.  
  782.     context = g_option_context_new (NULL);
  783.     g_option_context_add_main_entries (context, entries, NULL);
  784.     g_option_context_add_group (context, gtk_get_option_group (TRUE));
  785.     if (!g_option_context_parse (context, &argc, &argv, &error))
  786.     {
  787.         g_printerr ("option parsing failed: %s", error->message);
  788.         g_error_free (error);
  789.         exit (1);
  790.     }
  791.     g_option_context_free (context);
  792.  
  793.     /* Obtain a connection to the session bus */
  794.     connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
  795.     if (connection == NULL)
  796.     {
  797.         g_printerr ("Failed to open connection to bus: %s", error->message);
  798.         g_error_free (error);
  799.         exit (1);
  800.     }
  801.  
  802. #if HAVE_WNCK
  803.     wnck_set_client_type (WNCK_CLIENT_TYPE_PAGER);
  804. #endif
  805.  
  806.     gtk_init (&argc, &argv);
  807.  
  808.     deskmenu = g_object_new (DESKMENU_TYPE, NULL);
  809.  
  810.     deskmenu_parse_file (DESKMENU (deskmenu), filename);
  811.  
  812.     dbus_g_connection_register_g_object (connection,
  813.                                          DESKMENU_PATH_DBUS,
  814.                                          deskmenu);
  815.  
  816.     if (!dbus_bus_request_name (dbus_g_connection_get_connection (connection),
  817.                                 DESKMENU_SERVICE_DBUS,
  818.                                 DBUS_NAME_FLAG_REPLACE_EXISTING,
  819.                                 NULL))
  820.         return 1;
  821.  
  822.     gtk_main ();
  823.  
  824.     return 0;
  825. }
Advertisement
Add Comment
Please, Sign In to add comment