1
// ob_display.c - this file is part of openbox-menu
2
// Copyright (C) 2010-13 mimas <mimasgpc@free.fr>
4
// This program is free software; you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation; version 3 of the License.
8
// This program is distributed in the hope that it will be useful,
9
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
// GNU General Public License for more details.
13
// You should have received a copy of the GNU General Public License
14
// along with this program; if not, write to the Free Software
15
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
16
// MA 02110-1301, USA.
18
#include "openbox-menu.h"
20
const gchar *default_template =
21
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"
22
"<openbox_pipe_menu xmlns=\"http://openbox.org/\""
23
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
24
" xsi:schemaLocation=\"http://openbox.org/ >"
25
"%MENU%</openbox_pipe_menu>\n";
27
/****f* ob_display/menu_directory
29
* create a menu entry for a directory.
32
* this menu entry has to be closed by "</menu>".
35
menu_directory (MenuCacheApp *dir, OB_Menu *context)
37
gchar *dir_id = safe_name (menu_cache_item_get_id (MENU_CACHE_ITEM(dir)));
38
gchar *dir_name = safe_name (menu_cache_item_get_name (MENU_CACHE_ITEM(dir)));
41
if (!context->no_icons)
43
gchar *dir_icon = item_icon_path (MENU_CACHE_ITEM(dir));
45
g_string_append_printf (context->builder,
46
"<menu id=\"openbox-%s\" label=\"%s\" icon=\"%s\">\n",
47
dir_id, dir_name, dir_icon);
53
g_string_append_printf (context->builder,
54
"<menu id=\"openbox-%s\" label=\"%s\">\n",
62
/****f* ob_display/menu_application
64
* create a menu entry for an application.
67
menu_application (MenuCacheApp *app, OB_Menu *context)
69
gchar *exec_name = NULL;
70
gchar *exec_icon = NULL;
71
gchar *exec_cmd = NULL;
73
/* is comment (description) or name displayed ? */
74
if (context->comment && menu_cache_item_get_comment (MENU_CACHE_ITEM(app)))
75
exec_name = safe_name (menu_cache_item_get_comment (MENU_CACHE_ITEM(app)));
77
exec_name = safe_name (menu_cache_item_get_name (MENU_CACHE_ITEM(app)));
79
exec_cmd = clean_exec (app);
82
if (!context->no_icons)
84
exec_icon = item_icon_path (MENU_CACHE_ITEM(app));
85
g_string_append_printf (context->builder,
86
"<item label=\"%s\" icon=\"%s\"><action name=\"Execute\">",
93
g_string_append_printf (context->builder,
94
"<item label=\"%s\"><action name=\"Execute\">",
98
if (context->sn && menu_cache_app_get_use_sn (app))
99
g_string_append (context->builder,
100
"<startupnotify><enabled>yes</enabled></startupnotify>");
102
if (menu_cache_app_get_use_terminal (app))
103
g_string_append_printf (context->builder,
104
"<command><![CDATA[%s %s]]></command>\n</action></item>\n",
105
context->terminal_cmd,
108
g_string_append_printf (context->builder,
109
"<command><![CDATA[%s]]></command>\n</action></item>\n",
117
/****f* ob_display/menu_generate
119
* main routine of menu creation.
122
* It calls itself when 'dir' type is MENU_CACHE_TYPE_DIR.
125
menu_generate (MenuCacheDir *dir, OB_Menu *context)
129
for (l = menu_cache_dir_get_children (dir); l; l = l->next)
130
switch ((guint) menu_cache_item_get_type (MENU_CACHE_ITEM(l->data)))
132
case MENU_CACHE_TYPE_DIR:
133
menu_directory (l->data, context);
134
menu_generate (MENU_CACHE_DIR(l->data), context);
135
g_string_append (context->builder, "</menu>\n");
138
case MENU_CACHE_TYPE_SEP:
139
g_string_append (context->builder, "<separator />\n");
142
case MENU_CACHE_TYPE_APP:
143
if (app_is_visible (MENU_CACHE_APP(l->data), 0))
144
menu_application (l->data, context);
149
/****f* ob_display/get_header_footer_from_template
151
* Get header and footer string from a template file. If no template
152
* file provided, the default template will bu used.
158
* * a pointer to an array of strings that needs to be freed with g_strfreev.
160
gchar **get_header_footer_from_template (gchar *template)
162
gchar *content = NULL;
163
gchar **tokens = NULL;
165
if (template && g_file_get_contents (template, &content, NULL, NULL))
167
tokens = g_strsplit (content, "%MENU%", 2);
172
tokens = g_strsplit (default_template, "%MENU%", 2);
177
/****f* ob_display/menu_display
179
* it begins and closes the menu content, write it into a file or
184
* * file, the filename where the menu content should be written to.
185
* If file is 'NULL' then the menu content is displayed.
188
* Nothing. A MenuCacheReloadNotify callback returns void.
191
* A 16 KiB GString is allocated for the content of the pipemenu.
192
* This should be enough prevent too many allocations while building
195
* The size of the XML file created is around 8 KB in my computer but
196
* I don't have a lot of applications installed.
199
menu_display (MenuCache *menu, OB_Menu *context)
201
gchar **template_parts = NULL;
203
MenuCacheDir *dir = menu_cache_dup_root_dir (menu);
204
if (G_UNLIKELY(dir == NULL))
206
g_warning ("Can't get menu root directory");
207
context->code = MENU_DIR_ERROR;
211
GSList *l = menu_cache_dir_get_children (dir);
213
if (g_slist_length (l) != 0) {
214
context->builder = g_string_sized_new (16 * 1024);
216
template_parts = get_header_footer_from_template (context->template);
217
// TODO: check if template_parts array contains 2 strings.
219
g_string_append (context->builder, template_parts[0]); // add header
220
menu_generate (dir, context);
221
g_string_append (context->builder, template_parts[1]); // add footer
223
g_strfreev (template_parts);
225
gchar *buff = g_string_free (context->builder, FALSE);
227
/* Has menu content to be saved in a file ? */
230
if (!g_file_set_contents (context->output, buff, -1, NULL))
231
g_warning ("Can't write to %s\n", context->output);
233
g_message ("wrote to %s", context->output);
235
else /* No, so it's displayed on screen */
236
g_print ("%s", buff);
242
g_warning ("Menu seems to be empty. Check openbox-menu parameters.");
243
context->code = MENU_EMPTY_ERROR;
246
menu_cache_item_unref (MENU_CACHE_ITEM(dir));