All pastes #2092411 Raw Edit

Something

public c v1 · immutable
#2092411 ·published 2011-10-22 04:16 UTC
rendered paste body
/* * compiz-deskmenu is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * compiz-deskmenu is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program.  If not, see <http://www.gnu.org/licenses/>. * * Copyright 2008 Christopher Williams <christopherw@verizon.net> */  /*Roadmap:Necessary:	TODO: Add a viewport # indicator for the window list for accesiblity reasons difficulty: hard	TODO: Add configuration for menu icon size difficulty: easy	TODO: Add toggle of tearables difficulty: easy	TODO: Add a sane icon dialog difficulty: medium-hardFor fun, might not implement:TODO: Add ability to call up menus from the menu.xml file by name, if this is really, really needed or requested */#include <stdlib.h>#include <string.h>#include <dbus/dbus-glib-lowlevel.h>#include <gtk/gtk.h>#include <glib/gprintf.h>#define HAVE_WNCK 1#if HAVE_WNCK#include "deskmenu-wnck.h"#endif#include "deskmenu-utils.h"#include "deskmenu-menu.h"#include "deskmenu-glue.h"G_DEFINE_TYPE(Deskmenu, deskmenu, G_TYPE_OBJECT) //this is calling deskmenu_class_initstatic voidstart_element (GMarkupParseContext *context,               const gchar         *element_name,               const gchar        **attr_names,               const gchar        **attr_values,               gpointer             user_data,               GError             **error);static voidtext (GMarkupParseContext *context,      const gchar         *text,      gsize                text_len,      gpointer             user_data,      GError             **error);static voidend_element (GMarkupParseContext *context,             const gchar         *element_name,             gpointer             user_data,             GError             **error);static GMarkupParser parser = {    start_element,    end_element,    text,    NULL,    NULL};static GHashTable *item_hash;static GHashTable *element_hash;static voiddeskmenu_free_item (DeskmenuObject *dm_object);GQuarkdeskmenu_error_quark (void){    static GQuark quark = 0;    if (!quark)        quark = g_quark_from_static_string ("deskmenu_error");    return quark;}static voidquit (GtkWidget *widget,      gpointer   data){    gtk_main_quit ();}//This is how menu command is launchedstatic voidlauncher_activated (GtkWidget *widget,                    gchar     *command){    GError *error = NULL;	if (!gdk_spawn_command_line_on_screen (gdk_screen_get_default (), parse_expand_tilde(command), &error))    {        deskmenu_widget_error(error);    }}//This is how a recent document is openedstatic voidrecent_activated (GtkRecentChooser *chooser,                  gchar     *command){    GError *error = NULL;	gchar *full_command, *file;	file = gtk_recent_chooser_get_current_uri (chooser);	full_command = get_full_command(command, file);		if (!gdk_spawn_command_line_on_screen (gdk_screen_get_default (), parse_expand_tilde(full_command), &error))    {        deskmenu_widget_error(error);    }}/* prototype code for pipemenu */static voidpipe_menu_recreate (GtkWidget *item, gchar *command) {	gchar *stdout;	gchar **stdout2 = (gchar *)&stdout;	gchar *cache_entries = g_object_get_data (G_OBJECT(item), "cached");	GtkWidget *submenu;	submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM(item));	if (submenu)	{		if (strcmp (cache_entries, "yes") != 0)		{			gtk_widget_destroy (submenu);			submenu = NULL;		}	}	if (!submenu)	{		submenu = gtk_menu_new();		if (g_spawn_command_line_sync (parse_expand_tilde(command), stdout2, NULL, NULL, NULL))		{			GError *error = NULL;			DeskmenuObject *dm_object = g_object_get_data (G_OBJECT(item), "menu");			dm_object->current_menu = submenu;			dm_object->make_from_pipe = TRUE;			if (gtk_menu_get_tearoff_state (GTK_MENU(dm_object->menu)))			{				gtk_menu_shell_append (GTK_MENU_SHELL (dm_object->current_menu), 					gtk_tearoff_menu_item_new());			}			GMarkupParseContext *context = g_markup_parse_context_new (&parser,				0, dm_object, NULL);			g_markup_parse_context_parse (context, (const gchar *)stdout, strlen((const char *)stdout), &error);			g_markup_parse_context_free (context);			if (error)			{				g_print(error->message); //spit out the message manually				if (dm_object->current_item)				{					//force reset					deskmenu_free_item(dm_object);				}				g_error_free (error);			}			g_free(stdout);			dm_object->make_from_pipe = FALSE;		}		else		{			GtkWidget *empty_item = gtk_menu_item_new_with_label ("Unable to get output");			gtk_widget_set_sensitive (empty_item, FALSE);			gtk_menu_shell_append (GTK_MENU_SHELL (submenu), empty_item);		}		gtk_widget_show_all(submenu);		gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);	}}static voidlauncher_name_exec_update (GtkWidget *label){    gchar *exec, *stdout;    exec = g_object_get_data (G_OBJECT (label), "exec");    if (g_spawn_command_line_sync (exec, &stdout, NULL, NULL, NULL))        gtk_label_set_text (GTK_LABEL (label), g_strstrip((gchar *)stdout));    else        gtk_label_set_text (GTK_LABEL (label), "execution error");    g_free (stdout);}static GtkWidget *make_recent_documents_list (gboolean images, gchar *command, int limit, int age, gchar *sort_type){	GtkWidget *widget = gtk_recent_chooser_menu_new ();    if (images)    {		gtk_recent_chooser_set_show_icons (GTK_RECENT_CHOOSER(widget), TRUE);    }	else	{		gtk_recent_chooser_set_show_icons (GTK_RECENT_CHOOSER(widget), FALSE);	}	g_signal_connect (G_OBJECT (widget), "item-activated", G_CALLBACK (recent_activated), g_strdup (command));    if (age)    {		GtkRecentFilter *filter = gtk_recent_filter_new ();		gtk_recent_filter_add_pattern (filter, "*");        gtk_recent_filter_add_age (filter, age);        gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER(widget), filter);    }	if (sort_type) {			if (strcmp (sort_type, "most used") == 0)			{				gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER(widget), GTK_RECENT_SORT_MRU);			}			else			{				gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER(widget), GTK_RECENT_SORT_LRU);			}	}	gtk_recent_chooser_set_limit (GTK_RECENT_CHOOSER(widget), limit);	return widget;}static voiddeskmenu_construct_item (DeskmenuObject *dm_object){    DeskmenuItem *item = dm_object->current_item;    GtkWidget *menu_item, *submenu;    gchar *name, *icon, *command, *vpicon;    gboolean images;    gint w, h;//constructs the items in menu    switch (item->type)    {        case DESKMENU_ITEM_LAUNCHER:            if (item->name_exec)            {                GtkWidget *label;                GHook *hook;                                name = g_strstrip (item->name->str);                menu_item = gtk_image_menu_item_new ();                label = gtk_label_new_with_mnemonic (NULL);                gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);                g_object_set_data (G_OBJECT (label), "exec", g_strdup (name));                gtk_container_add (GTK_CONTAINER (menu_item), label);                hook = g_hook_alloc (dm_object->show_hooks);                hook->data = (gpointer) label;                hook->func = (GHookFunc *) launcher_name_exec_update;                g_hook_append (dm_object->show_hooks, hook);            }            else            {                if (item->name)                    name = g_strstrip (item->name->str);                else                    name = "";                menu_item = gtk_image_menu_item_new_with_mnemonic (name);				            }            if (item->icon)            {                icon = g_strstrip (item->icon->str);                if (item->icon_file) {					gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);                	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM					   (menu_item), gtk_image_new_from_pixbuf (gdk_pixbuf_new_from_file_at_size (parse_expand_tilde(icon), w, h, NULL)));				   }				else {					gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),						gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU));					}            }			if (item->command_pipe)			{				command = g_strstrip (item->command->str);				if (item->cache_output)				{					g_object_set_data(G_OBJECT(menu_item), "cached", g_strdup("yes"));				}				else				{					g_object_set_data(G_OBJECT(menu_item), "cached", g_strdup("no"));				}				g_object_set_data(G_OBJECT(menu_item), "menu", dm_object);				g_signal_connect (G_OBJECT (menu_item), "activate", 					G_CALLBACK (pipe_menu_recreate), g_strdup(command));				submenu = gtk_menu_new();				gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), submenu);			}			else			{				if (item->command)				{					command = g_strstrip (item->command->str);					g_signal_connect (G_OBJECT (menu_item), "activate",						G_CALLBACK (launcher_activated), g_strdup (command));				}			}            gtk_menu_shell_append (GTK_MENU_SHELL (dm_object->current_menu),                menu_item);            break;#if HAVE_WNCK        case DESKMENU_ITEM_WINDOWLIST:            menu_item = gtk_image_menu_item_new_with_mnemonic ("_Windows");			images = FALSE;			gboolean this_vp = FALSE;			gboolean mini_only = FALSE;            if (item->icon)            {				images = TRUE;                icon = g_strstrip (item->icon->str);                if (item->icon_file) {					gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);                	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM					   (menu_item), gtk_image_new_from_pixbuf (gdk_pixbuf_new_from_file_at_size (parse_expand_tilde(icon), w, h, NULL)));				}				else {					gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),						gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU));				}            }            if (item->thisvp                && strcmp (g_strstrip (item->thisvp->str), "true") == 0)                this_vp = TRUE;            if (item->mini_only                && strcmp (g_strstrip (item->mini_only->str), "true") == 0)                mini_only = TRUE;            g_object_set_data(G_OBJECT(menu_item), "windowlist", deskmenu_windowlist_initialize (images, this_vp, mini_only));            g_signal_connect (G_OBJECT (menu_item), "activate", 					G_CALLBACK (refresh_windowlist_item), NULL);			submenu = gtk_menu_new();			gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), submenu);            gtk_menu_shell_append (GTK_MENU_SHELL (dm_object->current_menu),                menu_item);            break;        case DESKMENU_ITEM_VIEWPORTLIST:            menu_item = gtk_image_menu_item_new_with_mnemonic ("_Viewports");            gboolean wrap, file;            wrap = FALSE;            images = FALSE;            file = FALSE;            if (item->wrap                && strcmp (g_strstrip (item->wrap->str), "true") == 0)                wrap = TRUE;            if (item->icon)            {				images = TRUE;                icon = g_strstrip (item->icon->str);                if (item->icon_file) {					gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);                	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM					   (menu_item), gtk_image_new_from_pixbuf (gdk_pixbuf_new_from_file_at_size (parse_expand_tilde(icon), w, h, NULL)));				}				else {					gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),						gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU));				}            }            if (item->vpicon)            {                vpicon = g_strstrip (parse_expand_tilde(item->vpicon->str));                if (item->vpicon_file) {					file = TRUE;				}            }            else	    {	       vpicon = "";	    }            g_object_set_data(G_OBJECT(menu_item), "vplist", deskmenu_vplist_initialize (wrap, images, file, vpicon));            g_signal_connect (G_OBJECT (menu_item), "activate", 					G_CALLBACK (refresh_viewportlist_item), NULL);			submenu = gtk_menu_new();			gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), submenu);            gtk_menu_shell_append (GTK_MENU_SHELL (dm_object->current_menu),                menu_item);            break;#endif        case DESKMENU_ITEM_RELOAD:            menu_item = gtk_image_menu_item_new_with_mnemonic ("Reload");            if (item->icon)            {                icon = g_strstrip (item->icon->str);                if (item->icon_file) {					gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);                	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM					   (menu_item), gtk_image_new_from_pixbuf (gdk_pixbuf_new_from_file_at_size (parse_expand_tilde(icon), w, h, NULL)));				}				else {					gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),						gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU));				}            }            g_signal_connect (G_OBJECT (menu_item), "activate",                 G_CALLBACK (quit), NULL);             gtk_menu_shell_append (GTK_MENU_SHELL (dm_object->current_menu),                menu_item);            break;        case DESKMENU_ITEM_DOCUMENTS:            menu_item = gtk_image_menu_item_new_with_mnemonic ("Recent Doc_uments");			gint limit, age;			gchar *sort_type;			images = FALSE;			sort_type = "least used";			age = 25;            if (item->icon)            {				images = TRUE;                icon = g_strstrip (item->icon->str);                if (item->icon_file) {					gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);                	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM					   (menu_item), gtk_image_new_from_pixbuf (gdk_pixbuf_new_from_file_at_size (parse_expand_tilde(icon), w, h, NULL)));				}				else {					gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),						gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU));				}            }            if (item->age)            {                age = atoi(g_strstrip (item->age->str));            }            if (item->sort_type) {				sort_type = g_strstrip (item->sort_type->str);			}            if (item->quantity)            {                limit = atoi(g_strstrip (item->quantity->str));            }			else			{				limit = -1;			}			if (item->command)			{				command = g_strstrip (item->command->str);			}			else			{				command = g_strdup ("xdg-open");			}			GtkWidget *docs = make_recent_documents_list(images, command, limit, age, sort_type);			gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item),                docs);            gtk_menu_shell_append (GTK_MENU_SHELL (dm_object->current_menu),                menu_item);            break;        default:            break;    }}static voiddeskmenu_free_item (DeskmenuObject *dm_object) {	/* free data used to make it */    if (dm_object->current_item->name)        g_string_free (dm_object->current_item->name, TRUE);    if (dm_object->current_item->icon)        g_string_free (dm_object->current_item->icon, TRUE);    if (dm_object->current_item->command)        g_string_free (dm_object->current_item->command, TRUE);    if (dm_object->current_item->wrap)        g_string_free (dm_object->current_item->wrap, TRUE);    if (dm_object->current_item->vpicon)        g_string_free (dm_object->current_item->vpicon, TRUE);    if (dm_object->current_item->mini_only)        g_string_free (dm_object->current_item->mini_only, TRUE);    if (dm_object->current_item->thisvp)        g_string_free (dm_object->current_item->thisvp, TRUE);    if (dm_object->current_item->sort_type)        g_string_free (dm_object->current_item->sort_type, TRUE);    if (dm_object->current_item->quantity)        g_string_free (dm_object->current_item->quantity, TRUE);    if (dm_object->current_item->age)        g_string_free (dm_object->current_item->age, TRUE);    dm_object->current_item = NULL;}/* The handler functions. */static voidstart_element (GMarkupParseContext *context,               const gchar         *element_name,               const gchar        **attr_names,               const gchar        **attr_values,               gpointer             user_data,               GError             **error){	DeskmenuObject *dm_object = user_data;    DeskmenuElementType element_type;    const gchar **ncursor = attr_names, **vcursor = attr_values;    GtkWidget *item, *menu;    gint w, h;    element_type = GPOINTER_TO_INT (g_hash_table_lookup        (element_hash, element_name));    if ((dm_object->menu && !dm_object->current_menu)       || (!dm_object->menu && element_type != DESKMENU_ELEMENT_MENU))    {        gint line_num, char_num;        g_markup_parse_context_get_position (context, &line_num, &char_num);        g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,            "Error on line %d char %d: Element '%s' declared outside of "            "toplevel menu element", line_num, char_num, element_name);        return;    }    switch (element_type)    {        case DESKMENU_ELEMENT_MENU:            if (dm_object->current_item != NULL)            {                gint line_num, char_num;                g_markup_parse_context_get_position (context, &line_num,                    &char_num);                g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,                    "Error on line %d char %d: Element 'menu' cannot be nested "                    "inside of an item element", line_num, char_num);                return;            }            if (!dm_object->menu)            {	            /*if (strcmp (*ncursor, "size") == 0) {                    deskmenu->w = g_strdup (*vcursor);                    deskmenu->h = g_strdup (*vcursor);                    }                else {	                gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, deskmenu->w, deskmenu->h);                }*/                dm_object->menu = gtk_menu_new ();                g_object_set_data (G_OBJECT (dm_object->menu), "parent menu",                    NULL);                dm_object->current_menu = dm_object->menu;            }            else            {                gchar *name = NULL;                gchar *icon = NULL;                gboolean name_exec = FALSE;                gboolean icon_file = FALSE;                while (*ncursor)                {                    if (strcmp (*ncursor, "name") == 0)                        name = g_strdup (*vcursor);                    else if (strcmp (*ncursor, "icon") == 0)						icon = g_strdup (*vcursor);                    else if ((strcmp (*ncursor, "mode") == 0)                        && (strcmp (*vcursor, "exec") == 0))                        name_exec = TRUE;                    else if ((strcmp (*ncursor, "mode1") == 0)                        && (strcmp (*vcursor, "file") == 0))                        icon_file = TRUE;					else                        g_set_error (error, G_MARKUP_ERROR,                            G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,                            "Unknown attribute: %s", *ncursor);                    ncursor++;                    vcursor++;                }				if (name_exec)				{					GtkWidget *label;					GHook *hook;						item = gtk_image_menu_item_new ();					label = gtk_label_new_with_mnemonic (NULL);					gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);						g_object_set_data (G_OBJECT (label), "exec", g_strdup (name));					gtk_container_add (GTK_CONTAINER (item), label);					hook = g_hook_alloc (dm_object->show_hooks);						hook->data = (gpointer) label;					hook->func = (GHookFunc *) launcher_name_exec_update;					g_hook_append (dm_object->show_hooks, hook);				}				else				{					if (name)						item = gtk_image_menu_item_new_with_mnemonic (name);					else						item = gtk_image_menu_item_new_with_mnemonic ("");				}                if (icon)				{					if (icon_file) {					gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);                	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM					   (item), gtk_image_new_from_pixbuf (gdk_pixbuf_new_from_file_at_size (parse_expand_tilde(icon), w, h, NULL)));					}					else {					gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),						gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU));					}				}				gtk_menu_shell_append (GTK_MENU_SHELL (dm_object->current_menu), item);                menu = gtk_menu_new ();                g_object_set_data (G_OBJECT (menu), "parent menu",                    dm_object->current_menu);                dm_object->current_menu = menu;                gtk_menu_item_set_submenu (GTK_MENU_ITEM (item),                    dm_object->current_menu);                if (!dm_object->make_from_pipe)				{					GtkWidget *pin = gtk_tearoff_menu_item_new();					gtk_menu_shell_append (GTK_MENU_SHELL (dm_object->current_menu), 						pin); //add a pin menu item					dm_object->pin_items = g_slist_prepend (dm_object->pin_items, pin);				}				else				{					if (gtk_menu_get_tearoff_state (GTK_MENU(dm_object->menu)))					{						GtkWidget *pin = gtk_tearoff_menu_item_new();						gtk_menu_shell_append (GTK_MENU_SHELL (dm_object->current_menu), 							pin); //add a pin menu item					}				}				                g_free (name);                g_free (icon);            }            break;        case DESKMENU_ELEMENT_SEPARATOR:        if (dm_object->current_item != NULL)            {                gint line_num, char_num;                g_markup_parse_context_get_position (context, &line_num,                    &char_num);                g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,                    "Error on line %d char %d: Element 'menu' cannot be nested "                    "inside of an item element", line_num, char_num);                return;            }        else {                gchar *name = NULL;                gchar *icon = NULL;                gboolean name_exec = FALSE;                gboolean icon_file = FALSE;                gboolean decorate = FALSE;                gint w, h;                item = gtk_separator_menu_item_new();                while (*ncursor)                {                    if (strcmp (*ncursor, "name") == 0) {                        name = g_strdup (*vcursor);						if (!decorate)						{							decorate = TRUE;						}					}                    else if (strcmp (*ncursor, "icon") == 0) {						icon = g_strdup (*vcursor);						if (!decorate)						{							decorate = TRUE;						}					}                    else if ((strcmp (*ncursor, "mode") == 0)                        && (strcmp (*vcursor, "exec") == 0))                        name_exec = TRUE;                    else if ((strcmp (*ncursor, "mode1") == 0)                        && (strcmp (*vcursor, "file") == 0))                        icon_file = TRUE;					else                        g_set_error (error, G_MARKUP_ERROR,                            G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,                            "Unknown attribute: %s", *ncursor);                    ncursor++;                    vcursor++;                }				if (decorate)				{					GtkWidget *box = gtk_hbox_new (FALSE, 3);					gtk_container_add (GTK_CONTAINER(item), GTK_WIDGET(box));					if (name_exec)					{						GtkWidget *label;						GHook *hook;								label = gtk_label_new_with_mnemonic (NULL);								g_object_set_data (G_OBJECT (label), "exec", g_strdup (name));						gtk_box_pack_end (GTK_BOX(box), label,															TRUE,															FALSE,															0);						hook = g_hook_alloc (dm_object->show_hooks);								hook->data = (gpointer) label;						hook->func = (GHookFunc *) launcher_name_exec_update;						g_hook_append (dm_object->show_hooks, hook);					}					else					{						gtk_box_pack_end (GTK_BOX(box), gtk_label_new_with_mnemonic (name),						TRUE,						FALSE,						0);					}					if (icon)					{						GtkWidget *image;						if (icon_file) {							gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);							image = gtk_image_new_from_pixbuf (gdk_pixbuf_new_from_file_at_size (parse_expand_tilde(icon), w, h, NULL));						}						else {							image = gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU);						}						gtk_box_pack_start (GTK_BOX(box), image,                                 FALSE,                                 FALSE,                                 0);					}					gtk_widget_set_state (item, GTK_STATE_PRELIGHT); /*derive colors from menu hover*/					g_free (name);					g_free (icon);				}				gtk_menu_shell_append (GTK_MENU_SHELL (dm_object->current_menu), item);			}            break;        case DESKMENU_ELEMENT_ITEM:            if (dm_object->current_item != NULL)            {                gint line_num, char_num;                g_markup_parse_context_get_position (context, &line_num,                    &char_num);                g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,                    "Error on line %d char %d: Element 'item' cannot be nested "                    "inside of another item element", line_num, char_num);                return;            }            dm_object->current_item = g_slice_new0 (DeskmenuItem);                while (*ncursor)                {                    if (strcmp (*ncursor, "type") == 0)                        dm_object->current_item->type = GPOINTER_TO_INT                        (g_hash_table_lookup (item_hash, *vcursor));                    else                        g_set_error (error, G_MARKUP_ERROR,                            G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,                            "Unknown attribute: %s", *ncursor);                    ncursor++;                    vcursor++;                }            break;        case DESKMENU_ELEMENT_NAME:             while (*ncursor)                {                    if ((strcmp (*ncursor, "mode") == 0)                        && (strcmp (*vcursor, "exec") == 0))                        dm_object->current_item->name_exec = TRUE;                    ncursor++;                    vcursor++;                } /* no break here to let it fall through */        case DESKMENU_ELEMENT_ICON:                while (*ncursor)                {                    if ((strcmp (*ncursor, "mode1") == 0)                        && (strcmp (*vcursor, "file") == 0))                        dm_object->current_item->icon_file = TRUE;                    ncursor++;                    vcursor++;                } /* no break here to let it fall through */        case DESKMENU_ELEMENT_VPICON:                while (*ncursor)                {                    if ((strcmp (*ncursor, "mode1") == 0)                        && (strcmp (*vcursor, "file") == 0))                        dm_object->current_item->vpicon_file = TRUE;                    ncursor++;                    vcursor++;                } /* no break here to let it fall through */        case DESKMENU_ELEMENT_COMMAND:                while (*ncursor)                {                    if ((strcmp (*ncursor, "mode2") == 0)                        && (strcmp (*vcursor, "pipe") == 0))                        dm_object->current_item->command_pipe = TRUE;                    if (dm_object->current_item->command_pipe == TRUE                        && (strcmp (*ncursor, "cache") == 0)                        && (strcmp (*vcursor, "true") == 0))                        dm_object->current_item->cache_output = TRUE;                    ncursor++;                    vcursor++;                } /* no break here to let it fall through */        case DESKMENU_ELEMENT_WRAP:            if (dm_object->current_item)                dm_object->current_item->current_element = element_type;            break;        case DESKMENU_ELEMENT_THISVP:            if (dm_object->current_item)                dm_object->current_item->current_element = element_type;            break;        case DESKMENU_ELEMENT_MINIONLY:            if (dm_object->current_item)                dm_object->current_item->current_element = element_type;            break;        case DESKMENU_ELEMENT_QUANTITY:            if (dm_object->current_item)                dm_object->current_item->current_element = element_type;            break;        case DESKMENU_ELEMENT_SORT:            if (dm_object->current_item)                dm_object->current_item->current_element = element_type;            break;        case DESKMENU_ELEMENT_AGE:            if (dm_object->current_item)                dm_object->current_item->current_element = element_type;            break;        default:            g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,                "Unknown element: %s", element_name);            break;    }}//dealing with empty attributesstatic voidtext (GMarkupParseContext *context,      const gchar         *text,      gsize                text_len,      gpointer             user_data,      GError             **error){    DeskmenuObject *dm_object = user_data;    DeskmenuItem *item = dm_object->current_item;    if (!(item && item->current_element))        return;    switch (item->current_element)    {        case DESKMENU_ELEMENT_NAME:            if (!item->name)                item->name = g_string_new_len (text, text_len);            else                g_string_append_len (item->name, text, text_len);            break;        case DESKMENU_ELEMENT_ICON:            if (!item->icon)                item->icon = g_string_new_len (text, text_len);            else                g_string_append_len (item->icon, text, text_len);            break;        case DESKMENU_ELEMENT_VPICON:            if (!item->vpicon)                item->vpicon = g_string_new_len (text, text_len);            else                g_string_append_len (item->vpicon, text, text_len);            break;        case DESKMENU_ELEMENT_COMMAND:            if (!item->command)                item->command = g_string_new_len (text, text_len);            else                g_string_append_len (item->command, text, text_len);            break;        case DESKMENU_ELEMENT_WRAP:            if (!item->wrap)                item->wrap = g_string_new_len (text, text_len);            else                g_string_append_len (item->wrap, text, text_len);            break;        case DESKMENU_ELEMENT_THISVP:            if (!item->thisvp)                item->thisvp = g_string_new_len (text, text_len);            else                g_string_append_len (item->thisvp, text, text_len);            break;        case DESKMENU_ELEMENT_MINIONLY:            if (!item->mini_only)                item->mini_only = g_string_new_len (text, text_len);            else                g_string_append_len (item->mini_only, text, text_len);            break;        case DESKMENU_ELEMENT_AGE:            if (!item->age)                item->age = g_string_new_len (text, text_len);            else                g_string_append_len (item->age, text, text_len);            break;        case DESKMENU_ELEMENT_QUANTITY:            if (!item->quantity)                item->quantity = g_string_new_len (text, text_len);            else                g_string_append_len (item->quantity, text, text_len);            break;        case DESKMENU_ELEMENT_SORT:            if (!item->sort_type)                item->sort_type = g_string_new_len (text, text_len);            else                g_string_append_len (item->sort_type, text, text_len);            break;        default:            break;    }}static voidend_element (GMarkupParseContext *context,             const gchar         *element_name,             gpointer             user_data,             GError             **error){    DeskmenuElementType element_type;    DeskmenuObject *dm_object = user_data;    GtkWidget *parent;    element_type = GPOINTER_TO_INT (g_hash_table_lookup        (element_hash, element_name));    switch (element_type)    {        case DESKMENU_ELEMENT_MENU:            g_return_if_fail (dm_object->current_item == NULL);            parent = g_object_get_data (G_OBJECT (dm_object->current_menu),                "parent menu");            dm_object->current_menu = parent;            break;/* separator building is now dealt with in the beginning */        case DESKMENU_ELEMENT_ITEM:            g_return_if_fail (dm_object->current_item != NULL);            /* finally make the item ^_^ */            deskmenu_construct_item (dm_object);			deskmenu_free_item(dm_object);            break;        default:            break;    }}/* Class init */static void deskmenu_class_init (DeskmenuClass *deskmenu_class){    dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (deskmenu_class),        &dbus_glib_deskmenu_object_info);}/* Instance init, matches up words to types, note how there's no handler for pipe since it'sreplaced in its own chunk */static void deskmenu_init (Deskmenu *deskmenu){    deskmenu->pinnable = FALSE;    deskmenu->file_cache = g_hash_table_new (g_str_hash, g_str_equal);}static voidset_up_item_hash (void) {	item_hash= g_hash_table_new (g_str_hash, g_str_equal);    g_hash_table_insert (item_hash, "launcher",        GINT_TO_POINTER (DESKMENU_ITEM_LAUNCHER));#if HAVE_WNCK    g_hash_table_insert (item_hash, "windowlist",        GINT_TO_POINTER (DESKMENU_ITEM_WINDOWLIST));    g_hash_table_insert (item_hash, "viewportlist",        GINT_TO_POINTER (DESKMENU_ITEM_VIEWPORTLIST));#endif    g_hash_table_insert (item_hash, "documents",        GINT_TO_POINTER (DESKMENU_ITEM_DOCUMENTS));    g_hash_table_insert (item_hash, "reload",        GINT_TO_POINTER (DESKMENU_ITEM_RELOAD));}static voidset_up_element_hash (void) {	element_hash = g_hash_table_new (g_str_hash, g_str_equal);        g_hash_table_insert (element_hash, "menu",         GINT_TO_POINTER (DESKMENU_ELEMENT_MENU));    g_hash_table_insert (element_hash, "separator",        GINT_TO_POINTER (DESKMENU_ELEMENT_SEPARATOR));    g_hash_table_insert (element_hash, "item",         GINT_TO_POINTER (DESKMENU_ELEMENT_ITEM));    g_hash_table_insert (element_hash, "name",         GINT_TO_POINTER (DESKMENU_ELEMENT_NAME));    g_hash_table_insert (element_hash, "icon",         GINT_TO_POINTER (DESKMENU_ELEMENT_ICON));    g_hash_table_insert (element_hash, "vpicon",         GINT_TO_POINTER (DESKMENU_ELEMENT_VPICON));    g_hash_table_insert (element_hash, "command",         GINT_TO_POINTER (DESKMENU_ELEMENT_COMMAND));    g_hash_table_insert (element_hash, "thisvp",         GINT_TO_POINTER (DESKMENU_ELEMENT_THISVP));    g_hash_table_insert (element_hash, "minionly",         GINT_TO_POINTER (DESKMENU_ELEMENT_MINIONLY));    g_hash_table_insert (element_hash, "wrap",         GINT_TO_POINTER (DESKMENU_ELEMENT_WRAP));    g_hash_table_insert (element_hash, "sort",         GINT_TO_POINTER (DESKMENU_ELEMENT_SORT));    g_hash_table_insert (element_hash, "quantity",         GINT_TO_POINTER (DESKMENU_ELEMENT_QUANTITY));    g_hash_table_insert (element_hash, "age",         GINT_TO_POINTER (DESKMENU_ELEMENT_AGE));}static DeskmenuObject*deskmenu_object_init (void) {	DeskmenuObject *dm_object = g_slice_new0 (DeskmenuObject);	dm_object->menu = NULL;    dm_object->current_menu = NULL;    dm_object->current_item = NULL;    dm_object->make_from_pipe = FALSE;    dm_object->pin_items = NULL;	dm_object->show_hooks = g_slice_new0 (GHookList);    g_hook_list_init (dm_object->show_hooks, sizeof (GHook));		return dm_object;}static DeskmenuObject*deskmenu_parse_file (gchar *filename){    GError *error = NULL;	DeskmenuObject *dm_object = deskmenu_object_init();    GMarkupParseContext *context = g_markup_parse_context_new (&parser,        0, dm_object, NULL);		gchar *text;    gsize length;    g_file_get_contents (filename, &text, &length, NULL); //cache already handled file existence check		if (!g_markup_parse_context_parse (context, text, strlen(text), &error)        || !g_markup_parse_context_end_parse (context, &error))    {        g_printerr ("Parse failed with message: %s \n", error->message);        g_error_free (error);        exit (1);    }	g_free(text); //free the joined array    g_markup_parse_context_free (context); //free the parser    gtk_widget_show_all (dm_object->menu);    return dm_object;}static DeskmenuObject *check_file_cache (Deskmenu *deskmenu, gchar *filename) {	DeskmenuObject *dm_object;	gchar *user_default = g_build_path (G_DIR_SEPARATOR_S,  g_get_user_config_dir (),									"compiz",									"boxmenu",									"menu.xml",									NULL);		//TODO: add a size column to cache for possible autorefresh		g_print("Checking cache...\n");		if (strlen(filename) == 0)    filename = g_build_path (G_DIR_SEPARATOR_S,                               g_get_user_config_dir (),                               "compiz",                               "boxmenu",                               "menu.xml",                               NULL);	if (strcmp(filename, user_default) == 0) {		g_print("Looking up default menu...\n");			/*			set default filename to be [configdir]/compiz/boxmenu/menu.xml			*/			gboolean success = FALSE;		if (!g_file_test(filename, G_FILE_TEST_EXISTS)) {				g_print("Getting default system menu...\n");				const gchar* const *cursor = g_get_system_config_dirs ();				gchar *path = NULL;				while (*cursor)				{					g_free (path);					path = g_strdup (*cursor);					filename = g_build_path (G_DIR_SEPARATOR_S,											path,											"compiz",											"boxmenu",											"menu.xml",											NULL);								if (g_file_test(filename, G_FILE_TEST_EXISTS))					{						if (g_hash_table_lookup(deskmenu->file_cache, filename) == NULL)						{							g_hash_table_insert (deskmenu->file_cache, g_strdup(filename), deskmenu_parse_file(filename));							g_print("Prepared default system menu!\n");						}						else						{							g_print("Retrieving default system menu!\n");						}						g_free (path);						success = TRUE;						break;					}						cursor++;				}			}		else			{				if (g_hash_table_lookup(deskmenu->file_cache, user_default) == NULL)				{					if (g_file_test(filename, G_FILE_TEST_EXISTS)) {						g_print("Preparing default menu!\n");						g_hash_table_insert (deskmenu->file_cache, g_strdup(filename), deskmenu_parse_file(filename));						success = TRUE;					}				}				else				{					g_print("Retrieving cached default user menu...\n");					success = TRUE;				}			}		if (!success)		{			g_printerr ("Couldn't find a menu file...\n");			exit (1);				}	}	else {		if (g_hash_table_lookup(deskmenu->file_cache, filename) == NULL) {			if (g_file_test(filename, G_FILE_TEST_EXISTS))				{					g_print("Preparing new non-default menu...\n");					g_hash_table_insert (deskmenu->file_cache, g_strdup(filename), deskmenu_parse_file(filename));				}				else {					if (g_hash_table_lookup(deskmenu->file_cache, user_default) != NULL)					{						g_print("Couldn't find specified file, loading default...\n");						filename = user_default;					}					else					{						g_printerr ("Couldn't find a menu file...\n");						exit (1);					}				}		}	}		dm_object = g_hash_table_lookup (deskmenu->file_cache, filename);		g_printf("Done loading %s!\n", filename);		return dm_object;}#if HAVE_WNCKgbooleandeskmenu_vplist (Deskmenu *deskmenu,				gboolean toggle_wrap, 				gboolean toggle_images, 				gboolean toggle_file, 				gchar *viewport_icon) {	DeskmenuVplist *vplist = deskmenu_vplist_initialize(toggle_wrap, toggle_images, toggle_file, g_strstrip(viewport_icon));	deskmenu_vplist_new (vplist);    gtk_menu_popup (GTK_MENU (vplist->menu),                    NULL, NULL, NULL, NULL,                    0, 0);	return TRUE;}gbooleandeskmenu_windowlist (Deskmenu *deskmenu, 					 gboolean images,					 gboolean thisvp,					 gboolean mini_only) {	DeskmenuWindowlist *windowlist = deskmenu_windowlist_initialize (images, thisvp, mini_only);	deskmenu_windowlist_new(windowlist);    gtk_menu_popup (GTK_MENU (windowlist->menu),                    NULL, NULL, NULL, NULL,                    0, 0);	return TRUE;}#endifgbooleandeskmenu_documentlist (Deskmenu *deskmenu, 					   gboolean images, 					   gchar *command, 					   int limit, 					   int age, 					   gchar *sort_type) {	GtkWidget *menu = make_recent_documents_list (images, g_strdup(command), limit, age, g_strstrip(sort_type));	    gtk_menu_popup (GTK_MENU (menu),                    NULL, NULL, NULL, NULL,                    0, 0);	return TRUE;}/* The show method */static voiddeskmenu_show (DeskmenuObject *dm_object,			   Deskmenu *deskmenu,               GError  **error){	GSList *list = NULL, *iterator = NULL;	list = dm_object->pin_items;    g_hook_list_invoke (dm_object->show_hooks, FALSE);	if (deskmenu->pinnable)	{		gtk_menu_set_tearoff_state (GTK_MENU (dm_object->menu), TRUE); 		for (iterator = list; iterator; iterator = iterator->next) {			gtk_widget_show (iterator->data);			gtk_widget_set_no_show_all (iterator->data, FALSE);		}	}	else {		gtk_menu_popup (GTK_MENU (dm_object->menu),                    NULL, NULL, NULL, NULL,                    0, 0);        for (iterator = list; iterator; iterator = iterator->next) {			gtk_widget_hide (iterator->data);			gtk_widget_set_no_show_all (iterator->data, TRUE);		}	}}gbooleandeskmenu_pin (Deskmenu *deskmenu,			gboolean pin){	deskmenu->pinnable = pin;	return TRUE;}gbooleandeskmenu_reload (Deskmenu *deskmenu,               GError  **error){    gtk_main_quit ();    return TRUE;}/* The dbus method for binary client */gbooleandeskmenu_control (Deskmenu *deskmenu, gchar *filename, gchar *workingd, GError  **error){	chdir (workingd);	DeskmenuObject *dm_object = check_file_cache (deskmenu, g_strstrip(filename));	deskmenu_show(dm_object, deskmenu, error);	return TRUE;}//precache backend, currently needs GUIstatic voiddeskmenu_precache (Deskmenu *deskmenu, gchar *filename){	GError *error = NULL;	GKeyFile *config = g_key_file_new ();	int i = 0;		(void *)check_file_cache(deskmenu, ""); //always cache default menu		g_print("Attempting to precache files in config...");	if (!filename)	{		filename = g_build_path (G_DIR_SEPARATOR_S,                                   g_get_user_config_dir (),                                   "compiz",                                   "boxmenu",                                   "precache.ini",                                   NULL);	}	if (!g_key_file_load_from_file (config, filename, G_KEY_FILE_NONE, NULL))	{		g_print("Configuration not found, will not precache files...");	}	else	{		g_print("Configuration found! Starting precache...");		gchar **files = g_key_file_get_keys (config, "Files", NULL, &error);		gchar *feed = "";				while (files[i])		{			feed = g_key_file_get_string (config, "Files", files[i], &error);			(void *)check_file_cache(deskmenu, parse_expand_tilde(feed));			i++;		}		g_strfreev(files);		g_free(feed);	}	g_key_file_free (config);}intmain (int    argc,      char **argv){	DBusGConnection *connection;    GError *error = NULL;    GObject *deskmenu;    g_type_init ();     connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);    if (connection == NULL)    {        g_printerr ("Failed to open connection to bus: %s", error->message);        g_error_free (error);        exit (1);    }	g_print ("Starting the daemon...\n");	GOptionContext *context;	gchar *file = NULL;    GOptionEntry entries[] =    {        { "config", 'c', 0, G_OPTION_ARG_FILENAME, &file,            "Use FILE instead of the default daemon configuration", "FILE" },        { NULL, 0, 0, 0, NULL, NULL, NULL }    };    context = g_option_context_new (NULL);    g_option_context_add_main_entries (context, entries, NULL);	error = NULL;    if (!g_option_context_parse (context, &argc, &argv, &error))    {        g_printerr ("option parsing failed: %s", error->message);        g_error_free (error);        return 1;    }    g_set_prgname ("Compiz Boxmenu");	g_option_context_free (context);#if HAVE_WNCK    wnck_set_client_type (WNCK_CLIENT_TYPE_PAGER);#endif    gtk_init (&argc, &argv);	    deskmenu = g_object_new (DESKMENU_TYPE, NULL);    dbus_g_connection_register_g_object (connection, DESKMENU_PATH_DBUS, deskmenu);	if (!dbus_bus_request_name (dbus_g_connection_get_connection (connection),						        DESKMENU_SERVICE_DBUS,                                DBUS_NAME_FLAG_REPLACE_EXISTING,						        NULL))        return 1;		set_up_element_hash();	set_up_item_hash();	deskmenu_precache(DESKMENU(deskmenu), file);    gtk_main ();    return 0;}