diff --git a/ede-panel/Panel.cpp b/ede-panel/Panel.cpp index 7ceb2d7..675f9af 100644 --- a/ede-panel/Panel.cpp +++ b/ede-panel/Panel.cpp @@ -375,6 +375,9 @@ void Panel::show(void) { void Panel::hide(void) { Fl::remove_handler(x_events); + + /* strange; this is not called when panel goes out :S */ + mgr.clear(); save_config(); } diff --git a/ede-panel/applets/cpu-monitor/CpuMonitor.cpp b/ede-panel/applets/cpu-monitor/CpuMonitor.cpp index 0a494f5..00caa28 100644 --- a/ede-panel/applets/cpu-monitor/CpuMonitor.cpp +++ b/ede-panel/applets/cpu-monitor/CpuMonitor.cpp @@ -148,9 +148,9 @@ void CPUMonitor::clear() if(!cpu) return; for (int i = 0; i < samples(); i++) - delete cpu[i]; + delete [] cpu[i]; - delete cpu; + delete [] cpu; cpu = 0; m_old_samples = -1; diff --git a/ede-panel/applets/start-menu/MenuRules.h b/ede-panel/applets/start-menu/MenuRules.h index fed3141..ca7bb66 100644 --- a/ede-panel/applets/start-menu/MenuRules.h +++ b/ede-panel/applets/start-menu/MenuRules.h @@ -1,3 +1,23 @@ +/* + * $Id$ + * + * Copyright (C) 2012 Sanel Zukan + * + * This program 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. + * + * This program 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + #ifndef __MENURULES_H__ #define __MENURULES_H__ diff --git a/ede-panel/applets/start-menu/StartMenu.cpp b/ede-panel/applets/start-menu/StartMenu.cpp index a801418..460cd73 100644 --- a/ede-panel/applets/start-menu/StartMenu.cpp +++ b/ede-panel/applets/start-menu/StartMenu.cpp @@ -1,21 +1,64 @@ +/* + * $Id$ + * + * Copyright (C) 2012 Sanel Zukan + * + * This program 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. + * + * This program 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + #include "Applet.h" +#include #include #include #include #include #include +#include +#include #include "XdgMenuReader.h" #include "ede-icon.h" +/* by default is enabled */ +#define EDE_PANEL_MENU_AUTOUPDATE 1 + +#ifdef EDE_PANEL_MENU_AUTOUPDATE + #include + EDELIB_NS_USING(DirWatch) + EDELIB_NS_USING_LIST(4, (DW_CREATE, DW_MODIFY, DW_DELETE, DW_REPORT_RENAME)) + + /* when menu needs to be update, after how long to do real update */ + #define MENU_UPDATE_TIMEOUT 5.0 + + /* elapsed seconds between changes reports from DirWatch; to prevent event throttling */ + #define MENU_UPDATE_DIFF 5 +#endif + EDELIB_NS_USING(MenuBase) +EDELIB_NS_USING(str_ends) /* some of this code was ripped from Fl_Menu_Button.cxx */ - class StartMenu : public MenuBase { private: - MenuItem *mcontent; + XdgMenuContent *mcontent, *mcontent_pending; + + time_t last_reload; + bool menu_opened; + + void setup_menu(XdgMenuContent *m); public: StartMenu(); ~StartMenu(); @@ -23,9 +66,35 @@ public: void popup(void); void draw(void); int handle(int e); + + void reload_menu(void); + bool can_reload(void); }; -StartMenu::StartMenu() : MenuBase(0, 0, 80, 25, "EDE"), mcontent(NULL) { +#ifdef EDE_PANEL_MENU_AUTOUPDATE +static void menu_update_cb(void *data) { + StartMenu *m = (StartMenu*)data; + m->reload_menu(); + E_DEBUG(E_STRLOC ": Scheduled menu update done\n"); +} + +static void folder_changed_cb(const char *dir, const char *w, int flags, void *data) { + StartMenu *m = (StartMenu*)data; + + /* skip file renaming */ + if(flags == DW_REPORT_RENAME) return; + + if(w == NULL) w = ""; + + /* add timeout for update so all filesystem changes gets applied */ + if(str_ends(w, ".desktop") && m->can_reload()) { + E_DEBUG(E_STRLOC ": Scheduled menu update due changes inside inside '%s' folder ('%s':%i) in %i secs.\n", dir, w, flags, MENU_UPDATE_TIMEOUT); + Fl::add_timeout(MENU_UPDATE_TIMEOUT, menu_update_cb, m); + } +} +#endif + +StartMenu::StartMenu() : MenuBase(0, 0, 80, 25, "EDE"), mcontent(NULL), mcontent_pending(NULL), last_reload(0), menu_opened(false) { down_box(FL_NO_BOX); labelfont(FL_HELVETICA_BOLD); labelsize(14); @@ -33,21 +102,51 @@ StartMenu::StartMenu() : MenuBase(0, 0, 80, 25, "EDE"), mcontent(NULL) { tooltip(_("Click here to choose and start common programs")); + /* load menu */ mcontent = xdg_menu_load(); + setup_menu(mcontent); - if(mcontent) { - /* skip the first item, since it often contains only one submenu */ - if(mcontent->submenu()) { - MenuItem *mc = mcontent + 1; - menu(mc); - } else { - menu(mcontent); - } - } +#ifdef EDE_PANEL_MENU_AUTOUPDATE + /* + * setup listeners on menu folders + * TODO: this list is constructed twice: the first time when menu was loaded and now + */ + StrList lst; + xdg_menu_applications_location(lst); + + DirWatch::init(); + + StrListIt it = lst.begin(), ite = lst.end(); + for(; it != ite; ++it) + DirWatch::add(it->c_str(), DW_CREATE | DW_MODIFY | DW_DELETE); + + DirWatch::callback(folder_changed_cb, this); +#endif } StartMenu::~StartMenu() { - xdg_menu_delete(mcontent); + if(mcontent) xdg_menu_delete(mcontent); + if(mcontent_pending) xdg_menu_delete(mcontent_pending); + +#ifdef EDE_PANEL_MENU_AUTOUPDATE + DirWatch::shutdown(); +#endif +} + +void StartMenu::setup_menu(XdgMenuContent *m) { + if(m == NULL) { + menu(NULL); + return; + } + + MenuItem *item = xdg_menu_to_fltk_menu(m); + + /* skip the first item, since it often contains only one submenu */ + if(item && item->submenu()) { + menu(item + 1); + } else { + menu(item); + } } static StartMenu *pressed_menu_button = 0; @@ -78,6 +177,8 @@ void StartMenu::draw(void) { } void StartMenu::popup(void) { + menu_opened = true; + const MenuItem *m; pressed_menu_button = this; @@ -93,6 +194,20 @@ void StartMenu::popup(void) { picked(m); pressed_menu_button = 0; Fl::release_widget_pointer(mb); + + menu_opened = false; + + /* if we have menu that wants to be updated, swap them as soon as menu window was closed */ + if(mcontent_pending) { + XdgMenuContent *tmp = mcontent; + + mcontent = mcontent_pending; + setup_menu(mcontent); + + mcontent_pending = tmp; + xdg_menu_delete(mcontent_pending); + mcontent_pending = NULL; + } } int StartMenu::handle(int e) { @@ -158,11 +273,38 @@ int StartMenu::handle(int e) { return 0; } +/* to prevent throttling of dirwatch events */ +bool StartMenu::can_reload(void) { +#ifdef EDE_PANEL_MENU_AUTOUPDATE + time_t c, diff; + + c = time(NULL); + diff = difftime(c, last_reload); + last_reload = c; + + if(diff >= MENU_UPDATE_DIFF) return true; +#endif + + return false; +} + +void StartMenu::reload_menu(void) { + if(menu_opened) { + E_DEBUG("pending...\n"); + mcontent_pending = xdg_menu_load(); + } else { + xdg_menu_delete(mcontent); + + mcontent = xdg_menu_load(); + setup_menu(mcontent); + } +} + EDE_PANEL_APPLET_EXPORT ( StartMenu, EDE_PANEL_APPLET_OPTION_ALIGN_LEFT, "Main menu", - "0.1", + "0.2", "empty", "Sanel Zukan" ) diff --git a/ede-panel/applets/start-menu/XdgMenuReader.cpp b/ede-panel/applets/start-menu/XdgMenuReader.cpp index 537d9c5..797eceb 100644 --- a/ede-panel/applets/start-menu/XdgMenuReader.cpp +++ b/ede-panel/applets/start-menu/XdgMenuReader.cpp @@ -1,3 +1,23 @@ +/* + * $Id$ + * + * Copyright (C) 2012 Sanel Zukan + * + * This program 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. + * + * This program 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + #include #include #include @@ -6,9 +26,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -21,9 +39,7 @@ #include "MenuRules.h" #include "XdgMenuReader.h" -EDELIB_NS_USING(String) EDELIB_NS_USING(DesktopFile) -EDELIB_NS_USING(list) EDELIB_NS_USING(IconLoader) EDELIB_NS_USING(system_config_dirs) EDELIB_NS_USING(system_data_dirs) @@ -204,25 +220,11 @@ static void menu_parse_context_append_desktop_files(MenuParseContext *ctx, const static void menu_parse_context_append_desktop_files_from_xdg_data_dirs(MenuParseContext *ctx) { StrList lst; - if(system_data_dirs(lst) < 1) - return; + xdg_menu_applications_location(lst); StrListIt it = lst.begin(), it_end = lst.end(); - String tmp; - - for(; it != it_end; ++it) { - tmp = build_filename((*it).c_str(), "applications"); - menu_parse_context_append_desktop_files(ctx, tmp.c_str(), tmp.c_str()); - } - - /* - * Add user directory too; the spec is unclear about this, but official menu spec tests - * requires it. Also, users will be able to add menu items without superuser permissions. - */ - String user_dir = user_data_dir(); - - tmp = build_filename(user_dir.c_str(), "applications"); - menu_parse_context_append_desktop_files(ctx, tmp.c_str(), tmp.c_str()); + for(; it != it_end; ++it) + menu_parse_context_append_desktop_files(ctx, it->c_str(), it->c_str()); } static void scan_include_exclude_tag(TiXmlNode *elem, MenuRulesList &rules) { @@ -547,8 +549,8 @@ static MenuContext *menu_parse_context_to_menu_context(MenuParseContext *m, * figure out the name first; if returns false, either menu should not be displayed, or something * went wrong */ - String *n, *ic; - bool should_be_displayed; + String *n = NULL, *ic = NULL; + bool should_be_displayed = false; if(!menu_context_construct_name_and_get_icon(m, top, &n, &ic, &should_be_displayed)) return NULL; @@ -568,7 +570,6 @@ static MenuContext *menu_parse_context_to_menu_context(MenuParseContext *m, ctx->name = n; ctx->icon = ic; ctx->display_it = should_be_displayed; - //E_DEBUG("+ Menu: %s %i\n", ctx->name->c_str(), m->include_rules.size()); /* fill MenuContext items, depending on what list was passed */ @@ -868,9 +869,18 @@ void xdg_menu_dump_for_test_suite(void) { menu_all_parse_lists_clear(pl, cl); } -/* used only for xdg_menu_load() and xdg_menu_delete() */ -static MenuParseList global_parse_list; -static MenuContextList global_context_list; +/* public API */ + +struct XdgMenuContent { + MenuItem *fltk_menu; + + /* + * We are keeping them as fltk_menu references some objects, like text. + * This is since FLTK menu can't free label strings as MenuItem is plain struct. + */ + MenuParseList parse_list; + MenuContextList context_list; +}; static void item_cb(Fl_Widget*, void *en) { DesktopEntry *entry = (DesktopEntry*)en; @@ -1009,20 +1019,37 @@ static unsigned int construct_edelib_menu(MenuContextList &lst, MenuItem *mi, un return pos; } -MenuItem *xdg_menu_load(void) { - /* assure they are empty */ - E_RETURN_VAL_IF_FAIL(global_parse_list.empty() == true, NULL); - E_RETURN_VAL_IF_FAIL(global_context_list.empty() == true, NULL); +void xdg_menu_applications_location(StrList &lst) { + lst.clear(); + + if(system_data_dirs(lst) < 1) + return; + + StrListIt it = lst.begin(), it_end = lst.end(); + + for(; it != it_end; ++it) + *it = build_filename(it->c_str(), "applications"); + + /* + * Add user directory too; the spec is unclear about this, but official menu spec tests + * requires it. Also, users will be able to add menu items without superuser permissions. + */ + String user_dir = user_data_dir(); + lst.push_back(build_filename(user_dir.c_str(), "applications")); +} + +XdgMenuContent *xdg_menu_load(void) { + XdgMenuContent *content = new XdgMenuContent(); /* load everything */ - menu_all_parse_lists_load(global_parse_list, global_context_list); + menu_all_parse_lists_load(content->parse_list, content->context_list); - unsigned int sz = menu_context_list_count(global_context_list); + unsigned int sz = menu_context_list_count(content->context_list); E_RETURN_VAL_IF_FAIL(sz > 0, NULL); MenuItem *mi = new MenuItem[sz + 2]; /* plus logout + ending NULL */ - unsigned int pos = construct_edelib_menu(global_context_list, mi, 0); + unsigned int pos = construct_edelib_menu(content->context_list, mi, 0); mi[pos].text = NULL; /* @@ -1032,10 +1059,20 @@ MenuItem *xdg_menu_load(void) { MenuItem::init_extensions(&mi[pos]); E_ASSERT(pos <= sz + 2); - return mi; + + content->fltk_menu = mi; + return content; } -void xdg_menu_delete(MenuItem *m) { - delete [] m; - menu_all_parse_lists_clear(global_parse_list, global_context_list); +void xdg_menu_delete(XdgMenuContent *m) { + E_RETURN_IF_FAIL(m != NULL); + + delete [] m->fltk_menu; + menu_all_parse_lists_clear(m->parse_list, m->context_list); + delete m; +} + +MenuItem *xdg_menu_to_fltk_menu(XdgMenuContent *m) { + E_RETURN_VAL_IF_FAIL(m != NULL, NULL); + return m->fltk_menu; } diff --git a/ede-panel/applets/start-menu/XdgMenuReader.h b/ede-panel/applets/start-menu/XdgMenuReader.h index 8fc3c99..2428ec4 100644 --- a/ede-panel/applets/start-menu/XdgMenuReader.h +++ b/ede-panel/applets/start-menu/XdgMenuReader.h @@ -1,13 +1,45 @@ +/* + * $Id$ + * + * Copyright (C) 2012 Sanel Zukan + * + * This program 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. + * + * This program 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + #ifndef __XDGMENUREADER_H__ #define __XDGMENUREADER_H__ #include +#include +#include EDELIB_NS_USING(MenuItem) +EDELIB_NS_USING(String) +EDELIB_NS_USING(list) + +typedef list StrList; +typedef list::iterator StrListIt; void xdg_menu_dump_for_test_suite(void); +/* all locations where menu files are stored */ +void xdg_menu_applications_location(StrList &lst); -MenuItem *xdg_menu_load(void); -void xdg_menu_delete(MenuItem *it); +struct XdgMenuContent; + +XdgMenuContent *xdg_menu_load(void); +void xdg_menu_delete(XdgMenuContent *c); +MenuItem *xdg_menu_to_fltk_menu(XdgMenuContent *c); #endif