aboutsummaryrefslogtreecommitdiff
path: root/src/MenuCreator.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/MenuCreator.cc')
-rw-r--r--src/MenuCreator.cc421
1 files changed, 421 insertions, 0 deletions
diff --git a/src/MenuCreator.cc b/src/MenuCreator.cc
new file mode 100644
index 0000000..cdec5c7
--- /dev/null
+++ b/src/MenuCreator.cc
@@ -0,0 +1,421 @@
1// MenuCreator.cc for Fluxbox
2// Copyright (c) 2004 Henrik Kinnunen (fluxgen at users.sourceforge.net)
3// and Simon Bowden (rathnor at users.sourceforge.net)
4//
5// Permission is hereby granted, free of charge, to any person obtaining a
6// copy of this software and associated documentation files (the "Software"),
7// to deal in the Software without restriction, including without limitation
8// the rights to use, copy, modify, merge, publish, distribute, sublicense,
9// and/or sell copies of the Software, and to permit persons to whom the
10// Software is furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in
13// all copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21// DEALINGS IN THE SOFTWARE.
22
23// $Id: MenuCreator.cc,v 1.1 2004/05/02 20:59:29 fluxgen Exp $
24
25#include "MenuCreator.hh"
26
27#include "Screen.hh"
28#include "CommandParser.hh"
29#include "fluxbox.hh"
30#include "CommandParser.hh"
31#include "Window.hh"
32#include "I18n.hh"
33
34#include "FbMenu.hh"
35#include "IconMenu.hh"
36#include "WorkspaceMenu.hh"
37#include "LayerMenu.hh"
38#include "SendToMenu.hh"
39
40#include "FbMenuParser.hh"
41#include "StyleMenuItem.hh"
42
43#include "FbTk/MultiButtonMenuItem.hh"
44#include "FbTk/RefCount.hh"
45#include "FbTk/MacroCommand.hh"
46#include "FbTk/SimpleCommand.hh"
47#include "FbTk/StringUtil.hh"
48#include "FbTk/Directory.hh"
49
50#include <iostream>
51using namespace std;
52
53template <>
54void LayerMenuItem<FluxboxWindow>::click(int button, int time) {
55 m_object->moveToLayer(m_layernum);
56}
57
58static FbTk::Menu *createStyleMenu(FbTk::Menu &parent, const std::string &label,
59 const std::string &directory) {
60 // perform shell style ~ home directory expansion
61 string stylesdir(FbTk::StringUtil::expandFilename(directory));
62
63 if (!FbTk::Directory::isDirectory(stylesdir))
64 return 0;
65
66 FbTk::Directory dir(stylesdir.c_str());
67
68 // create a vector of all the filenames in the directory
69 // add sort it
70 std::vector<std::string> filelist(dir.entries());
71 for (size_t file_index = 0; file_index < dir.entries(); ++file_index)
72 filelist[file_index] = dir.readFilename();
73
74 std::sort(filelist.begin(), filelist.end(), less<string>());
75
76 // for each file in directory add filename and path to menu
77 for (size_t file_index = 0; file_index < dir.entries(); file_index++) {
78 std::string style(stylesdir + '/' + filelist[file_index]);
79 // add to menu only if the file is a regular file, and not a
80 // .file or a backup~ file
81 if ((FbTk::Directory::isRegularFile(style) &&
82 (filelist[file_index][0] != '.') &&
83 (style[style.length() - 1] != '~')) ||
84 FbTk::Directory::isRegularFile(style + "/theme.cfg"))
85 parent.insert(new StyleMenuItem(filelist[file_index], style));
86 }
87 // update menu graphics
88 parent.update();
89 Fluxbox::instance()->saveMenuFilename(stylesdir.c_str());
90}
91
92static void translateMenuItem(Parser &parse,
93 const std::string &str_key,
94 const std::string &str_label,
95 const std::string &str_cmd,
96 FbTk::Menu &menu);
97
98
99static void parseMenu(Parser &pars, FbTk::Menu &menu) {
100 Parser::Item item, item2, item3;
101 while (!pars.eof()) {
102 pars>>item>>item2>>item3;
103 if (item.second == "end")
104 return;
105 translateMenuItem(pars,
106 item.second,
107 item2.second,
108 item3.second,
109 menu);
110
111 }
112}
113
114static void translateMenuItem(Parser &parse,
115 const std::string &str_key,
116 const std::string &str_label,
117 const std::string &str_cmd,
118 FbTk::Menu &menu) {
119
120 const int screen_number = menu.screenNumber();
121 static I18n &i18n = *I18n::instance();
122 using namespace FBNLS;
123
124#define SCREENNLS(a, b) i18n.getMessage(ScreenSet, a, b)
125
126 if (str_key == "end") {
127 return;
128 } else if (str_key == "nop") {
129 menu.insert(str_label.c_str());
130 } else if (str_key == "icons") {
131 FbTk::Menu *submenu = MenuCreator::createMenuType("iconmenu", menu.screenNumber());
132 if (submenu == 0)
133 return;
134 if (str_label.empty())
135 menu.insert(i18n.getMessage(IconSet, IconIcons, "Icons"));
136 else
137 menu.insert(str_label.c_str(), submenu);
138 } else if (str_key == "exit") { // exit
139 FbTk::RefCount<FbTk::Command> exit_cmd(CommandParser::instance().parseLine("exit"));
140 if (str_label.empty())
141 menu.insert(SCREENNLS(ScreenExit, "Exit"), exit_cmd);
142 else
143 menu.insert(str_label.c_str(), exit_cmd);
144 } else if (str_key == "exec") {
145 // execute and hide menu
146 using namespace FbTk;
147 RefCount<Command> exec_cmd(CommandParser::instance().parseLine("exec " + str_cmd));
148 RefCount<Command> hide_menu(new SimpleCommand<FbTk::Menu>(menu,
149 &Menu::hide));
150 MacroCommand *exec_and_hide = new FbTk::MacroCommand();
151 exec_and_hide->add(hide_menu);
152 exec_and_hide->add(exec_cmd);
153 RefCount<Command> exec_and_hide_cmd(exec_and_hide);
154 menu.insert(str_label.c_str(), exec_and_hide_cmd);
155 }
156 else if (str_key == "style") { // style
157 menu.insert(new StyleMenuItem(str_label, str_cmd));
158 } else if (str_key == "config") {
159 BScreen *screen = Fluxbox::instance()->findScreen(screen_number);
160 if (screen != 0)
161 menu.insert(str_label.c_str(), &screen->configMenu());
162 } // end of config
163 else if (str_key == "include") { // include
164 string newfile = FbTk::StringUtil::expandFilename(str_label);
165 // inject this file into the current menu
166 MenuCreator::createFromFile(newfile, menu);
167 Fluxbox::instance()->saveMenuFilename(newfile.c_str());
168 } // end of include
169 else if (str_key == "submenu") {
170
171 FbTk::Menu *submenu = MenuCreator::createMenu("", screen_number);
172 if (submenu == 0)
173 return;
174
175 if (str_cmd.size())
176 submenu->setLabel(str_cmd.c_str());
177 else
178 submenu->setLabel(str_label.c_str());
179
180 parseMenu(parse, *submenu);
181 submenu->update();
182 menu.insert(str_label.c_str(), submenu);
183 // save to screen list so we can delete it later
184 BScreen *screen = Fluxbox::instance()->findScreen(screen_number);
185 if (screen != 0)
186 screen->saveMenu(*submenu);
187
188 } // end of submenu
189 else if (str_key == "restart") {
190 FbTk::RefCount<FbTk::Command> restart_fb(CommandParser::instance().
191 parseLine("restart"));
192 if (str_label.empty())
193 menu.insert(SCREENNLS(ScreenRestart, "Restart"), restart_fb);
194 else
195 menu.insert(str_label.c_str(), restart_fb);
196 } // end of restart
197 else if (str_key == "reconfig") { // reconf
198 //
199 //!! TODO: NLS
200 //
201 FbTk::RefCount<FbTk::Command>
202 reconfig_fb_cmd(CommandParser::instance().
203 parseLine("reconfigure"));
204 menu.insert(str_label.c_str(), reconfig_fb_cmd);
205
206 } else if (str_key == "stylesdir" || str_key == "stylesmenu") {
207 createStyleMenu(menu, str_label,
208 str_key == "stylesmenu" ? str_cmd : str_label);
209 } // end of stylesdir
210 else if (str_key == "workspaces") {
211 BScreen *screen = Fluxbox::instance()->findScreen(screen_number);
212 if (screen != 0) {
213 screen->getWorkspacemenu().setInternalMenu();
214 menu.insert(str_label.c_str(), &screen->getWorkspacemenu());
215 }
216 } else if (str_key == "separator") {
217 menu.insert("---"); //!! TODO: this will be better in the future
218 } else { // ok, if we didn't find any special menu item we try with command parser
219 // we need to attach command with arguments so command parser can parse it
220 string line = str_key + " " + str_cmd;
221 FbTk::RefCount<FbTk::Command> command(CommandParser::instance().parseLine(line));
222 if (*command != 0)
223 menu.insert(str_label.c_str(), command);
224 }
225#undef SCREENNLS
226
227}
228
229
230static void parseWindowMenu(Parser &parse, FbTk::Menu &menu, FluxboxWindow &win) {
231
232 Parser::Item item, item2, item3;
233 while (!parse.eof()) {
234 parse>>item>>item2>>item3;
235 if (MenuCreator::createWindowMenuItem(item.second, item2.second, menu, win))
236 continue;
237
238 if (item.second == "end") {
239 return;
240 } else if (item.second == "submenu") {
241 FbTk::Menu *submenu = MenuCreator::createMenu(item2.second, menu.screenNumber());
242 parseWindowMenu(parse, *submenu, win);
243 submenu->update();
244 menu.insert(item2.second.c_str(), submenu);
245
246 } else { // try non window menu specific stuff
247 translateMenuItem(parse, item.second, item2.second, item3.second, menu);
248 }
249 }
250}
251
252FbTk::Menu *MenuCreator::createMenu(const std::string &label, int screen_number) {
253 BScreen *screen = Fluxbox::instance()->findScreen(screen_number);
254 if (screen == 0)
255 return 0;
256
257 FbTk::Menu *menu = new FbMenu(screen->menuTheme(),
258 screen->imageControl(),
259 *screen->layerManager().
260 getLayer(Fluxbox::instance()->getMenuLayer()));
261 if (!label.empty())
262 menu->setLabel(label.c_str());
263
264 return menu;
265}
266
267bool getStart(FbMenuParser &parser, std::string &label) {
268 Parser::Item item, item2, item3;
269 while (!parser.eof()) {
270 // get first begin line
271 parser>>item>>item2>>item3;
272 if (item.second == "begin") {
273 break;
274 }
275 }
276 if (parser.eof())
277 return false;
278 label = item2.second;
279 return true;
280}
281
282FbTk::Menu *MenuCreator::createFromFile(const std::string &filename, int screen_number) {
283 FbMenuParser parser(filename);
284 if (!parser.isLoaded())
285 return 0;
286
287 std::string label;
288 if (!getStart(parser, label))
289 return 0;
290
291 FbTk::Menu *menu = createMenu(label, screen_number);
292 if (menu != 0)
293 parseMenu(parser, *menu);
294
295 return menu;
296}
297
298
299void MenuCreator::createFromFile(const std::string &filename,
300 FbTk::Menu &inject_into) {
301
302 std::string real_filename = FbTk::StringUtil::expandFilename(filename);
303 FbMenuParser parser(real_filename);
304 if (!parser.isLoaded())
305 return;
306
307 std::string label;
308 if (!getStart(parser, label))
309 return;
310
311 parseMenu(parser, inject_into);
312}
313
314
315void MenuCreator::createFromFile(const std::string &filename,
316 FbTk::Menu &inject_into,
317 FluxboxWindow &win) {
318 std::string real_filename = FbTk::StringUtil::expandFilename(filename);
319 FbMenuParser parser(real_filename);
320 if (!parser.isLoaded())
321 return;
322
323 std::string label;
324
325 if (!getStart(parser, label))
326 return;
327
328 parseWindowMenu(parser, inject_into, win);
329}
330
331
332FbTk::Menu *MenuCreator::createMenuType(const std::string &type, int screen_num) {
333 BScreen *screen = Fluxbox::instance()->findScreen(screen_num);
334 if (screen == 0)
335 return 0;
336 if (type == "iconmenu") {
337 return new IconMenu(*screen);
338 } else if (type == "workspacemenu") {
339 return new WorkspaceMenu(*screen);
340 }
341
342}
343
344bool MenuCreator::createWindowMenuItem(const std::string &type,
345 const std::string &label,
346 FbTk::Menu &menu,
347 FluxboxWindow &win) {
348 static I18n &i18n = *I18n::instance();
349 typedef FbTk::RefCount<FbTk::Command> RefCmd;
350 typedef FbTk::SimpleCommand<FluxboxWindow> WindowCmd;
351 using namespace FBNLS;
352
353#define WINDOWNLS(a, b) std::string real_label = label; if (label.empty()) real_label = i18n.getMessage(FBNLS::WindowmenuSet, a, b)
354
355 if (type == "shade") {
356 WINDOWNLS(WindowmenuShade, "Shade");
357 RefCmd shade_cmd(new WindowCmd(win, &FluxboxWindow::shade));
358 menu.insert(real_label.c_str(), shade_cmd);
359 } else if (type == "maximize") {
360 WINDOWNLS(WindowmenuMaximize, "Maximize");
361 RefCmd maximize_cmd(new WindowCmd(win, &FluxboxWindow::maximizeFull));
362 RefCmd maximize_vert_cmd(new WindowCmd(win, &FluxboxWindow::maximizeVertical));
363 RefCmd maximize_horiz_cmd(new WindowCmd(win, &FluxboxWindow::maximizeHorizontal));
364 FbTk::MultiButtonMenuItem *maximize_item = new FbTk::MultiButtonMenuItem(3, real_label.c_str());
365 // create maximize item with:
366 // button1: Maximize normal
367 // button2: Maximize Vertical
368 // button3: Maximize Horizontal
369 maximize_item->setCommand(1, maximize_cmd);
370 maximize_item->setCommand(2, maximize_vert_cmd);
371 maximize_item->setCommand(3, maximize_horiz_cmd);
372 menu.insert(maximize_item);
373 } else if (type == "iconify") {
374 WINDOWNLS(WindowmenuIconify, "Iconify");
375 RefCmd iconify_cmd(new WindowCmd(win, &FluxboxWindow::iconify));
376 menu.insert(real_label.c_str(), iconify_cmd);
377 } else if (type == "close") {
378 WINDOWNLS(WindowmenuClose, "Close");
379 RefCmd close_cmd(new WindowCmd(win, &FluxboxWindow::close));
380 menu.insert(real_label.c_str(), close_cmd);
381 } else if (type == "lower") {
382 WINDOWNLS(WindowmenuLower, "Lower");
383 RefCmd lower_cmd(new WindowCmd(win, &FluxboxWindow::lower));
384 menu.insert(real_label.c_str(), lower_cmd);
385 } else if (type == "raise") {
386 WINDOWNLS(WindowmenuRaise, "Raise");
387 RefCmd raise_cmd(new WindowCmd(win, &FluxboxWindow::raise));
388 menu.insert(real_label.c_str(), raise_cmd);
389 } else if (type == "stick") {
390 WINDOWNLS(WindowmenuStick, "Stick");
391 RefCmd stick_cmd(new WindowCmd(win, &FluxboxWindow::stick));
392 menu.insert(real_label.c_str(), stick_cmd);
393 } else if (type == "extramenus") {
394 FluxboxWindow::ExtraMenus::iterator it = win.extraMenus().begin();
395 FluxboxWindow::ExtraMenus::iterator it_end = win.extraMenus().end();
396 for (; it != it_end; ++it) {
397 it->second->disableTitle();
398 menu.insert(it->first, it->second);
399 }
400
401 } else if (type == "sendto") {
402 WINDOWNLS(WindowmenuSendTo, "Send To ...");
403 menu.insert(real_label.c_str(), new SendToMenu(win));
404 } else if (type == "layer") {
405 WINDOWNLS(WindowmenuLayer, "Layer ...");
406 BScreen *screen = Fluxbox::instance()->findScreen(menu.screenNumber());
407 if (screen == 0)
408 return false;
409 menu.insert(real_label.c_str(),
410 new LayerMenu<FluxboxWindow>(screen->menuTheme(),
411 screen->imageControl(),
412 *screen->layerManager().getLayer(Fluxbox::instance()->getMenuLayer()),
413 &win,
414 false));
415
416 } else
417 return false;
418#undef WINDOWNLS
419
420 return true;
421}