From 55fc052fc6d4e308882f55aa8a1e5a44a8d4e003 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Tue, 2 Jan 2024 14:42:52 +0100 Subject: [PATCH 01/85] LC_CTYPE specific hints to Xft selection This is not as smart as libpango and similar but should instruct Xft sufficiently to select a Sans compatible font which actually brings the required codeset. Closes ice-wm/icewm#149 --- src/fontmacro.h | 15 ++++++++++----- src/yfontxft.cc | 10 ++++++++++ src/ylocale.cc | 9 +++++++++ src/ylocale.h | 1 + 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/fontmacro.h b/src/fontmacro.h index bf1dca4fb..d8f530e65 100644 --- a/src/fontmacro.h +++ b/src/fontmacro.h @@ -43,12 +43,17 @@ #endif +// Prefer DejaVu but fallback to some other Sans provider if needed, +// influenced by :lang= later in yfontxft.cc. + #define FQUOT(x) #x #define FSIZE(x) ":size=" FQUOT(x) -#define FSANS "DejaVu Sans" FSIZE(12) -#define FBOLD FSANS ":bold" -#define FSMAL "DejaVu Sans" FSIZE(10) ":bold" -#define FMONO "DejaVu Sans Mono:monospace" FSIZE(12) -#define FMONB FMONO ":bold" +#define FSANSTOK "DejaVu Sans,Sans" +#define FBOLDTOK ":bold" +#define FSANS FSANSTOK FSIZE(12) +#define FBOLD FSANS FBOLDTOK +#define FSMAL FSANSTOK FSIZE(10) FBOLDTOK +#define FMONO "DejaVu Sans Mono,Sans Mono:monospace" FSIZE(12) +#define FMONB FMONO FBOLDTOK #endif diff --git a/src/yfontxft.cc b/src/yfontxft.cc index 4d09c9d33..0c2837026 100644 --- a/src/yfontxft.cc +++ b/src/yfontxft.cc @@ -109,6 +109,16 @@ YXftFont::YXftFont(mstring name, bool use_xlfd): if (use_xlfd) { font = XftFontOpenXlfd(xapp->display(), xapp->screen(), fname); } else { + + if (fname.find(":lang=") < 0) + { + auto lclocale = mstring(YLocale::getLcType()).lower(); + if (lclocale.length() >= 5 && lclocale[2] == '_') { + fname = fname + ":lang=" + lclocale.substring(0,2) + "-" + + lclocale.substring(3,2); + } + } + font = XftFontOpenName(xapp->display(), xapp->screen(), fname); } if (font) { diff --git a/src/ylocale.cc b/src/ylocale.cc index 158ac19ff..f164b4c7c 100644 --- a/src/ylocale.cc +++ b/src/ylocale.cc @@ -313,6 +313,15 @@ char* YLocale::narrowString(const wchar_t* uStr, size_t uLen, size_t& lLen) { return dest; } +const char *YLocale::getLcType() +{ + auto cur_lctype = setlocale(LC_CTYPE, NULL); + if (cur_lctype == NULL) { + return "C"; + } + return cur_lctype; +} + const char *YLocale::getLocaleName() { #ifdef CONFIG_I18N return instance->converter->localeName(); diff --git a/src/ylocale.h b/src/ylocale.h index 75c2ef9dc..c02f9078e 100644 --- a/src/ylocale.h +++ b/src/ylocale.h @@ -27,6 +27,7 @@ class YLocale { static wchar_t* wideCharString(const char* str, size_t len, size_t& out); #endif static char* narrowString(const wchar_t* uStr, size_t uLen, size_t& lLen); + static const char* getLcType(); private: class YConverter* converter; From cc30c9afaeaa1ab82936309b4771d3dc90b23018 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Sat, 13 Jan 2024 19:09:09 +0100 Subject: [PATCH 02/85] Minor fixes and improvements on XDG menu - check presence of all RTLs (Sindhi and Urdu were ignored) - Simplify code, use standard algorithms / for-range loops - extract/unify the language/chartype fishing code --- src/fdomenu.cc | 105 +++++++++++++++++++++--------------------------- src/fontmacro.h | 2 +- src/yfontxft.cc | 8 ++-- src/ylocale.cc | 16 +++++--- src/ylocale.h | 2 +- 5 files changed, 61 insertions(+), 72 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 9b7eb6988..0a434e4d5 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -24,10 +24,11 @@ #include "sysdep.h" #include "intl.h" #include "appnames.h" -#include +#include "ylocale.h" #include #include +#include char const* ApplicationName; @@ -81,8 +82,15 @@ static int cmpUtf8(const void *p1, const void *p2) { class tDesktopInfo; typedef YVec tCharVec; tCharVec sys_folders, home_folders; -tCharVec* sys_home_folders[] = { &sys_folders, &home_folders, nullptr }; -tCharVec* home_sys_folders[] = { &home_folders, &sys_folders, nullptr }; +tCharVec* sys_home_folders[] = { &sys_folders, &home_folders }; +const char* rtls[] = { + "ar", // arabic + "fa", // farsi + "he", // hebrew + "ps", // pashto + "sd", // sindhi + "ur", // urdu +}; struct tListMeta { LPCSTR title, key, icon; @@ -100,13 +108,13 @@ struct tListMeta { GHashTable* meta_lookup_data; tListMeta* lookup_category(LPCSTR key) { - tListMeta* ret = (tListMeta*) g_hash_table_lookup(meta_lookup_data, key); - if (ret) - { + auto* ret = (tListMeta*) g_hash_table_lookup(meta_lookup_data, key); +#ifdef CONFIG_I18N // auto-translate the default title for the user's language - if (ret->title == nullptr) - ret->title = _(ret->key); - } + if (ret && !ret->title) + ret->title = gettext(ret->key); + //printf("Got title? %s -> %s\n", ret->key, ret->title); +#endif return ret; } @@ -709,31 +717,20 @@ bool launch(LPCSTR dfile, char** argv, int argc) { static void init() { #ifdef CONFIG_I18N - const char* loc = setlocale(LC_ALL, ""); - if (loc - && islower(*loc & 0xff) - && islower(loc[1] & 0xff) - && !isalpha(loc[2] & 0xff)) { - const char rtls[][4] = { - "ar", // arabic - "fa", // farsi - "he", // hebrew - "ps", // pashto - "sd", // sindhi - "ur", // urdu - }; - for (const char* rtl : rtls) { - if (rtl[0] == loc[0] && rtl[1] == loc[1]) { - right_to_left = true; - break; - } + setlocale(LC_ALL, ""); + + auto loc = YLocale::getCheckedExplicitLocale(false); + right_to_left = loc && std::any_of(rtls, rtls + ACOUNT(rtls), + [&](const char* rtl) { + return rtl[0] == loc[0] && rtl[1] == loc[1]; } - } -#endif + ); bindtextdomain(PACKAGE, LOCDIR); textdomain(PACKAGE); +#endif + meta_lookup_data = g_hash_table_new(g_str_hash, g_str_equal); for (unsigned i = 0; i < ACOUNT(spec::menuinfo); ++i) { @@ -745,7 +742,8 @@ static void init() { } const char* terminals[] = { terminal_option, getenv("TERMINAL"), TERM, - "urxvt", "alacritty", "roxterm", "xterm" }; + "urxvt", "alacritty", "roxterm", "xterm", + "x-terminal-emulator", "terminator" }; for (auto term : terminals) if (term && (terminal_command = path_lookup(term)) != nullptr) break; @@ -777,30 +775,6 @@ static void help(LPCSTR home, LPCSTR dirs, FILE* out, int xit) { exit(xit); } -void split_folders(const char* path_string, tCharVec& where) { - for (gchar** p = g_strsplit(path_string, ":", -1); *p; ++p) { - where.add(*p); - } -} - -void process_apps(const tCharVec& where) { - for (const gchar* const * p = where.data; p < where.data + where.size; - ++p) { - proc_dir_rec(*p, 0, insert_app_info, "applications", "desktop"); - } -} - -/** - * @return True if all categories received description data - */ -void load_folder_descriptions(const tCharVec& where) { - for (const gchar* const * p = where.data; p < where.data + where.size; - ++p) { - proc_dir_rec(*p, 0, pickup_folder_info, "desktop-directories", - "directory"); - } -} - #ifdef DEBUG_xxx void dbgPrint(const gchar *msg) { @@ -836,12 +810,12 @@ int main(int argc, char** argv) { return EXIT_SUCCESS; } - for (char** pArg = argv + 1; pArg < argv + argc; ++pArg) { + for (auto pArg = argv + 1; pArg < argv + argc; ++pArg) { if (is_version_switch(*pArg)) { g_fprintf(stdout, "icewm-menu-fdo " VERSION - ", Copyright 2015-2022 Eduard Bloch, 2017-2022 Bert Gijsbers.\n"); + ", Copyright 2015-2024 Eduard Bloch, 2017-2023 Bert Gijsbers.\n"); exit(0); } else if (is_copying_switch(*pArg)) @@ -895,14 +869,25 @@ int main(int argc, char** argv) { } init(); + + auto split_folders = [](const char* path_string, tCharVec& where) { + for (auto p = g_strsplit(path_string, ":", -1); *p; ++p) + where.add(*p); + }; split_folders(sysshare, sys_folders); split_folders(usershare, home_folders); - load_folder_descriptions(sys_folders); - load_folder_descriptions(home_folders); + for(auto& where: sys_home_folders) { + for (auto p = where->data; p < where->data + where->size; ++p) { + proc_dir_rec(*p, 0, pickup_folder_info, "desktop-directories", + "directory"); + } + } - process_apps(sys_folders); - process_apps(home_folders); + for(auto& where: sys_home_folders) { + for (auto p = where->data; p < where->data + where->size; ++p) + proc_dir_rec(*p, 0, insert_app_info, "applications", "desktop"); + } root.print(); diff --git a/src/fontmacro.h b/src/fontmacro.h index d8f530e65..77c8104b7 100644 --- a/src/fontmacro.h +++ b/src/fontmacro.h @@ -2,7 +2,7 @@ #define FONT_MACRO_H #ifndef CFGDIR -#error include config.h +#error config.h not included #endif #if !defined(FONTS_ADOBE) \ diff --git a/src/yfontxft.cc b/src/yfontxft.cc index 0c2837026..db649dbe4 100644 --- a/src/yfontxft.cc +++ b/src/yfontxft.cc @@ -112,10 +112,10 @@ YXftFont::YXftFont(mstring name, bool use_xlfd): if (fname.find(":lang=") < 0) { - auto lclocale = mstring(YLocale::getLcType()).lower(); - if (lclocale.length() >= 5 && lclocale[2] == '_') { - fname = fname + ":lang=" + lclocale.substring(0,2) + "-" - + lclocale.substring(3,2); + auto lclocale = mstring(YLocale::getCheckedExplicitLocale(true)); + if (lclocale) { + fname = (fname + ":lang=" + lclocale.substring(0,2) + "-" + + lclocale.substring(3,2)).lower(); } } diff --git a/src/ylocale.cc b/src/ylocale.cc index f164b4c7c..becd044ae 100644 --- a/src/ylocale.cc +++ b/src/ylocale.cc @@ -25,6 +25,7 @@ #include #include #include +#include const iconv_t invalid = iconv_t(-1); @@ -313,13 +314,16 @@ char* YLocale::narrowString(const wchar_t* uStr, size_t uLen, size_t& lLen) { return dest; } -const char *YLocale::getLcType() +const char *YLocale::getCheckedExplicitLocale(bool lctype) { - auto cur_lctype = setlocale(LC_CTYPE, NULL); - if (cur_lctype == NULL) { - return "C"; - } - return cur_lctype; + auto loc = setlocale(lctype ? LC_CTYPE : LC_MESSAGES, NULL); + if (loc == NULL) + return NULL; + return (islower(*loc & 0xff) + && islower(loc[1] & 0xff) + && !isalpha(loc[2] & 0xff)) + ? loc + : NULL; } const char *YLocale::getLocaleName() { diff --git a/src/ylocale.h b/src/ylocale.h index c02f9078e..47b8a8177 100644 --- a/src/ylocale.h +++ b/src/ylocale.h @@ -27,7 +27,7 @@ class YLocale { static wchar_t* wideCharString(const char* str, size_t len, size_t& out); #endif static char* narrowString(const wchar_t* uStr, size_t uLen, size_t& lLen); - static const char* getLcType(); + static const char* getCheckedExplicitLocale(bool lctype=true); private: class YConverter* converter; From efa4b66660254735fa8b152cb62c70bffa5ae0fd Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Sun, 14 Jan 2024 11:14:54 +0100 Subject: [PATCH 03/85] WIP: switched more glib containers to stl --- src/fdomenu.cc | 161 ++++++++++++++++++++++++++++--------------------- 1 file changed, 93 insertions(+), 68 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 0a434e4d5..6904b9922 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -21,7 +21,7 @@ #include "config.h" #include "base.h" -#include "sysdep.h" +//#include "sysdep.h" #include "intl.h" #include "appnames.h" #include "ylocale.h" @@ -29,6 +29,8 @@ #include #include #include +#include +#include char const* ApplicationName; @@ -75,9 +77,16 @@ struct auto_raii { typedef auto_raii auto_gfree; typedef auto_raii auto_gunref; +/* static int cmpUtf8(const void *p1, const void *p2) { return g_utf8_collate((LPCSTR ) p1, (LPCSTR ) p2); } +*/ +struct tLtUtf8 { + bool operator() (const std::string& a, const std::string& b) { + return g_utf8_collate(a.c_str(), b.c_str()) < 0; + } +} lessThanUtf8; class tDesktopInfo; typedef YVec tCharVec; @@ -104,11 +113,22 @@ struct tListMeta { SYSTEM_ICON = 16, }; short load_state_icon, load_state_title; + + LPCSTR get_title() const { + auto ret = title ? title : key; + //printf("gt: %s\n", ret); + return ret; + } }; -GHashTable* meta_lookup_data; -tListMeta* lookup_category(LPCSTR key) + +std::unordered_map meta_lookup_data, gh_directory_files; + +tListMeta* lookup_category(const std::string& key) { - auto* ret = (tListMeta*) g_hash_table_lookup(meta_lookup_data, key); + auto it = meta_lookup_data.find(key); + if (it == meta_lookup_data.end()) + return nullptr; + auto* ret = (tListMeta*) it->second; #ifdef CONFIG_I18N // auto-translate the default title for the user's language if (ret && !ret->title) @@ -176,28 +196,25 @@ extern t_menu_node root; struct t_menu_node { protected: // for leafs -> NULL, otherwise sub-menu contents - GTree* store; + std::map store; char* progCmd; const char* generic; public: const tListMeta *meta; t_menu_node(const tListMeta* desc): - store(nullptr), progCmd(nullptr), generic(nullptr), meta(desc) {} + progCmd(nullptr), generic(nullptr), meta(desc) {} - struct t_print_meta { + struct t_print_visitor { int count, level; t_menu_node* print_separated; }; - static gboolean print_node(gpointer /*key*/, gpointer value, gpointer pr_meta) { - ((t_menu_node*) value)->print((t_print_meta*) pr_meta); - return FALSE; - } - void print(t_print_meta *ctx) { - if (!meta) return; - LPCSTR title = Elvis(meta->title, meta->key); + void print(t_print_visitor *ctx) { + if (!meta) + return; + auto title = meta->get_title(); - if (!store) + if (store.empty()) { if (title && progCmd && filter_matched(title, flat_pfxes.empty() @@ -221,8 +238,7 @@ struct t_menu_node { return; } - if (!g_tree_nnodes(store)) - return; + // else: render as menu if (ctx->level == 1 && !no_sep_others && 0 == strcmp(meta->key, "Other")) { @@ -241,7 +257,11 @@ struct t_menu_node { printf("menu \"%s\" %s {\n", title, meta->icon); } ctx->level++; - g_tree_foreach(store, print_node, ctx); + + for(auto& it: this->store) { + ((t_menu_node*) it.second)->print(ctx); + } + if (ctx->level == 1 && ctx->print_separated) { fflush(stdout); @@ -270,15 +290,15 @@ struct t_menu_node { * Usual print method for the root node */ void print() { - t_print_meta ctx = {0,0,nullptr}; + t_print_visitor ctx = {0,0,nullptr}; print(&ctx); } - void add(t_menu_node* node) { - if (!store) - store = g_tree_new(cmpUtf8); - if (node->meta->title || node->meta->key) - g_tree_replace(store, (gpointer) Elvis(node->meta->title, node->meta->key), (gpointer) node); + t_menu_node* add(t_menu_node* node) { + auto nam = node->meta->get_title(); + if (nam) + store[nam] = node; + return node; } /** @@ -286,15 +306,10 @@ struct t_menu_node { * Creates one as needed or finds existing one. */ t_menu_node* get_subtree(const tListMeta* info) { - const char* title = Elvis(info->title, info->key); - if (store) { - void* existing = g_tree_lookup(store, title); - if (existing) - return (t_menu_node*) existing; - } - t_menu_node* tree = new t_menu_node(info); - add(tree); - return tree; + auto title = info->get_title(); + auto it = store.find(title); + return (it != store.end()) ? (t_menu_node*) it->second + : add(new t_menu_node(info)); } /** @@ -310,7 +325,7 @@ struct t_menu_node { tListMeta* pNewCatInfo = nullptr; tListMeta** ppLastMainCat = nullptr; - for (const char * const *pSubCatName = subCatCandidate->parent_sec; + for (auto pSubCatName = subCatCandidate->parent_sec; *pSubCatName; ++pSubCatName) { // stop nesting, add to the last visited/created submenu bool store_here = **pSubCatName == '|'; @@ -414,11 +429,11 @@ class tDesktopInfo { pInfo = g_desktop_app_info_new_from_filename(szFileName); if (!pInfo) return; -// tear down if not permitted + + // tear down if not permitted if (!g_app_info_should_show(*this)) { g_object_unref(pInfo); pInfo = nullptr; - return; } } @@ -445,20 +460,9 @@ class tDesktopInfo { } char * get_icon_path() const { - GIcon *pIcon = g_app_info_get_icon((GAppInfo*) pInfo); + auto pIcon = g_app_info_get_icon((GAppInfo*) pInfo); auto_gunref free_icon((GObject*) pIcon); - - if (pIcon) { - char *icon_path = g_icon_to_string(pIcon); - if (!icon_path) - return nullptr; - // if absolute then we are done here - if (icon_path[0] == '/') - return icon_path; - // err, not owned! auto_gfree free_orig_icon_path(icon_path); - return icon_path; - } - return nullptr; + return pIcon ? g_icon_to_string(pIcon) : nullptr; } }; @@ -543,6 +547,27 @@ struct t_menu_node_app : t_menu_node } }; +std::string get_stem(const std::string& full_path) { + LPCSTR dot(nullptr), start(full_path.c_str()); + for(auto p = start; ; ++p) + { + if ('/' == *p) + start = p + 1; + else if ('.' == *p) { + dot = p; + } + else if (!*p) { + if (!dot) + dot = p; + else if (dot < start) + dot = p; + + break; + } + } + return std::string(start, dot-start); +} + struct tFromTo { LPCSTR from; LPCSTR to;}; // match transformations applied by some DEs const tFromTo SameCatMap[] = { @@ -559,6 +584,7 @@ const tFromTo SameIconMap[] = { { "AudioVideo", "Audio" }, { "AudioVideo", "Video" } }; + typedef void (*tFuncInsertInfo)(LPCSTR szDesktopFile); void pickup_folder_info(LPCSTR szDesktopFile) { GKeyFile *kf = g_key_file_new(); @@ -570,18 +596,13 @@ void pickup_folder_info(LPCSTR szDesktopFile) { // looks like bad data if (!cat_name || !*cat_name) return; - // try a perfect match by name or file name - tListMeta* pCat = lookup_category(cat_name); + // try a perfect match by path or file name + auto pCat = lookup_category(cat_name); if (!pCat) { - gchar* bn(g_path_get_basename(szDesktopFile)); - auto_gfree cleanr(bn); - char* dot = strchr(bn, '.'); - if (dot) - { - *dot = 0x0; + auto bn = get_stem(szDesktopFile); + if (!bn.empty()) pCat = lookup_category(bn); - } } for (const tFromTo* p = SameCatMap; !pCat && p < SameCatMap+ACOUNT(SameCatMap); @@ -604,18 +625,19 @@ void pickup_folder_info(LPCSTR szDesktopFile) { if (pCat->load_state_title < tListMeta::SYSTEM_TRANSLATED) { char* cat_title = g_key_file_get_locale_string(kf, "Desktop Entry", "Name", nullptr, nullptr); - if (!cat_title) return; + if (!cat_title) + return; pCat->title = cat_title; char* cat_title_c = g_key_file_get_string(kf, "Desktop Entry", "Name", nullptr); bool same_trans = 0 == strcmp (cat_title_c, cat_title); - if (!same_trans) pCat->load_state_title = tListMeta::SYSTEM_TRANSLATED; + if (!same_trans) + pCat->load_state_title = tListMeta::SYSTEM_TRANSLATED; // otherwise: not sure, keep searching for a better translation } // something special, donate the icon to similar items unless they have a better one - for (const tFromTo* p = SameIconMap; p < SameIconMap + ACOUNT(SameIconMap); - ++p) { + for (auto p = SameIconMap; p < SameIconMap + ACOUNT(SameIconMap); ++p) { if (strcmp (pCat->key, p->from)) continue; @@ -626,7 +648,6 @@ void pickup_folder_info(LPCSTR szDesktopFile) { t->icon = pCat->icon; t->load_state_icon = tListMeta::FALLBACK_ICON; } - } } @@ -651,7 +672,7 @@ void insert_app_info(const char* szDesktopFile) { } void proc_dir_rec(LPCSTR syspath, unsigned depth, - tFuncInsertInfo process_keyfile, LPCSTR szSubfolder, + tFuncInsertInfo cb, LPCSTR szSubfolder, LPCSTR szFileSfx) { gchar *path = g_strjoin("/", syspath, szSubfolder, NULL); auto_gfree relmem_path(path); @@ -678,7 +699,7 @@ void proc_dir_rec(LPCSTR syspath, unsigned depth, } if (depth < ACOUNT(reclog)) { reclog[++depth] = buf.st_ino; - proc_dir_rec(szFullName, depth, process_keyfile, szSubfolder, + proc_dir_rec(szFullName, depth, cb, szSubfolder, szFileSfx); --depth; } @@ -688,7 +709,7 @@ void proc_dir_rec(LPCSTR syspath, unsigned depth, if (!S_ISREG(buf.st_mode)) continue; - process_keyfile(szFullName); + cb(szFullName); } } @@ -731,14 +752,16 @@ static void init() { #endif - meta_lookup_data = g_hash_table_new(g_str_hash, g_str_equal); + //meta_lookup_data = g_hash_table_new(g_str_hash, g_str_equal); + //gh_directory_files = g_hash_table_new(g_str_hash, g_str_equal); for (unsigned i = 0; i < ACOUNT(spec::menuinfo); ++i) { tListMeta& what = spec::menuinfo[i]; if (no_sub_cats && what.parent_sec) continue; // enforce non-const since we are not destroying that data ever, no key_destroy_func set! - g_hash_table_insert(meta_lookup_data, (gpointer) what.key, &what); +// g_hash_table_insert(meta_lookup_data, (gpointer) what.key, &what); + meta_lookup_data[what.key] = &what; } const char* terminals[] = { terminal_option, getenv("TERMINAL"), TERM, @@ -891,6 +914,8 @@ int main(int argc, char** argv) { root.print(); + //printf("What? %s\n", gettext("Building")); + if (nonempty(usershare) && usershare != getenv("XDG_DATA_HOME")) g_free(usershare); delete[] terminal_command; From 5b3c86c7c8b315140f69993ac5bcbc9cbddffb5b Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Sun, 14 Jan 2024 13:09:42 +0100 Subject: [PATCH 04/85] Workaround for gettext not applied on submenu --- src/fdomenu.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 6904b9922..3d2fff0f0 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -117,6 +117,9 @@ struct tListMeta { LPCSTR get_title() const { auto ret = title ? title : key; //printf("gt: %s\n", ret); + if (!load_state_title) { + return gettext(ret); + } return ret; } }; @@ -380,7 +383,8 @@ struct t_menu_node { if (!**pCatKey) continue; // empty? tListMeta *pResolved = lookup_category(*pCatKey); - if (!pResolved) continue; + if (!pResolved) + continue; if (!pResolved->parent_sec) matched_main_cats.add(pResolved); else @@ -391,7 +395,6 @@ struct t_menu_node { if (!no_sub_cats) { for (tListMeta** p = matched_sub_cats.data; p < matched_sub_cats.data + matched_sub_cats.size; ++p) { - try_add_to_subcat(pNode, *p, matched_main_cats); } } From 5f044870cfaf5c31641964c738b03fb54fe74725 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Sun, 14 Jan 2024 18:22:34 +0100 Subject: [PATCH 05/85] WIP: redesigning menu handling --- INSTALL | 6 +- VERSION | 2 +- configure.ac | 12 +- contrib/Additional_Categories.csv | 129 ++++ contrib/conv_cat.pl | 171 +++-- contrib/conv_cat.py | 122 ++++ src/CMakeLists.txt | 2 +- src/fdomenu.cc | 1099 +++++++++++++++++++++++++---- src/fdospecgen.h | 551 ++++++--------- 9 files changed, 1574 insertions(+), 520 deletions(-) create mode 100644 contrib/Additional_Categories.csv create mode 100644 contrib/conv_cat.py diff --git a/INSTALL b/INSTALL index 8865734f8..e82fd21de 100644 --- a/INSTALL +++ b/INSTALL @@ -1,8 +1,8 @@ Installation Instructions ************************* - Copyright (C) 1994-1996, 1999-2002, 2004-2016 Free Software -Foundation, Inc. + Copyright (C) 1994-1996, 1999-2002, 2004-2017, 2020-2021 Free +Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright @@ -225,7 +225,7 @@ order to use an ANSI C compiler: and if that doesn't work, install pre-built binaries of GCC for HP-UX. - HP-UX 'make' updates targets which have the same time stamps as their + HP-UX 'make' updates targets which have the same timestamps as their prerequisites, which makes it generally unusable when shipped generated files such as 'configure' are involved. Use GNU 'make' instead. diff --git a/VERSION b/VERSION index 1fcb9b404..1a5dadff2 100644 --- a/VERSION +++ b/VERSION @@ -1,2 +1,2 @@ PACKAGE=icewm -VERSION=3.2.0 +VERSION=3.4.6.130 diff --git a/configure.ac b/configure.ac index 2796ac149..195dff8fc 100644 --- a/configure.ac +++ b/configure.ac @@ -2,10 +2,10 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.69]) -AC_INIT([icewm],[3.5.0], +AC_INIT([icewm],[3.4.6.130], [https://github.com/bbidulock/icewm/issues], [icewm],[https://ice-wm.org]) -AC_REVISION([3.5.0]) +AC_REVISION([3.4.6.130]) # set better defaults AC_PREFIX_DEFAULT([/usr]) @@ -22,10 +22,10 @@ AC_CONFIG_AUX_DIR([scripts]) AC_USE_SYSTEM_EXTENSIONS AC_CANONICAL_TARGET -DATE='2024-05-20' +DATE='2024-09-24' AC_SUBST([DATE]) -MDOCDATE='May 20, 2024' +MDOCDATE='September 24, 2024' AC_SUBST([MDOCDATE]) BRANCH='icewm-1-4-BRANCH' @@ -37,7 +37,7 @@ TESTCASES="$TESTCASES iceview icesame iceicon icerun icelist icebar" # iceclock features='' # Initialize Automake -AM_INIT_AUTOMAKE([gnits 1.12 dist-lzip no-dist-gzip std-options -Wall color-tests silent-rules tar-pax]) +AM_INIT_AUTOMAKE([1.12 dist-lzip no-dist-gzip std-options -Wall color-tests silent-rules tar-pax]) AM_MAINTAINER_MODE AM_SILENT_RULES([yes]) @@ -87,7 +87,7 @@ LT_INIT([dlopen]) LT_LANG([C++]) AC_SUBST([LIBTOOL_DEPS]) -AM_GNU_GETTEXT_VERSION([0.19.2]) +AM_GNU_GETTEXT_VERSION([0.22]) AM_GNU_GETTEXT([external]) AC_ARG_ENABLE([i18n], diff --git a/contrib/Additional_Categories.csv b/contrib/Additional_Categories.csv new file mode 100644 index 000000000..dbaad928f --- /dev/null +++ b/contrib/Additional_Categories.csv @@ -0,0 +1,129 @@ +Additional Category,Description,Related Categories +Building,A tool to build applications,Development +Debugger,A tool to debug applications,Development +IDE,IDE application,Development +GUIDesigner,A GUI designer application,Development +Profiling,A profiling tool,Development +RevisionControl,Applications like cvs or subversion,Development +Translation,A translation tool,Development +Calendar,Calendar application,Office +ContactManagement,E.g. an address book,Office +Database,Application to manage a database,Office or Development or AudioVideo +Dictionary,A dictionary,Office or TextTools +Chart,Chart application,Office +Email,Email application,Office or Network +Finance,Application to manage your finance,Office +FlowChart,A flowchart application,Office +PDA,Tool to manage your PDA,Office +ProjectManagement,Project management application,Office or Development +Presentation,Presentation software,Office +Spreadsheet,A spreadsheet,Office +WordProcessor,A word processor,Office +2DGraphics,2D based graphical application,Graphics +VectorGraphics,"Application for viewing, creating, or processing vector graphics",Graphics;2DGraphics +RasterGraphics,"Application for viewing, creating, or processing raster (bitmap) graphics",Graphics;2DGraphics +3DGraphics,"Application for viewing, creating, or processing 3-D graphics",Graphics +Scanning,Tool to scan a file/text,Graphics +OCR,Optical character recognition application,Graphics;Scanning +Photography,"Camera tools, etc.",Graphics or Office +Publishing,Desktop Publishing applications and Color Management tools,Graphics or Office +Viewer,Tool to view e.g. a graphic or pdf file,Graphics or Office +TextTools,A text tool utility,Utility +DesktopSettings,Configuration tool for the GUI,Settings +HardwareSettings,"A tool to manage hardware components, like sound cards, video cards or printers",Settings +Printing,A tool to manage printers,HardwareSettings;Settings +PackageManager,A package manager application,Settings +Dialup,A dial-up program,Network +InstantMessaging,An instant messaging client,Network +Chat,A chat client,Network +IRCClient,An IRC client,Network +Feed,"RSS, podcast and other subscription based contents",Network +FileTransfer,Tools like FTP or P2P programs,Network +HamRadio,HAM radio software,Network or Audio +News,A news reader or a news ticker,Network +P2P,A P2P program,Network +RemoteAccess,A tool to remotely manage your PC,Network +Telephony,Telephony via PC,Network +TelephonyTools,"Telephony tools, to dial a number, manage PBX, ...",Utility +VideoConference,Video Conference software,Network +WebBrowser,A web browser,Network +WebDevelopment,A tool for web developers,Network or Development +Midi,An app related to MIDI,AudioVideo;Audio +Mixer,Just a mixer,AudioVideo;Audio +Sequencer,A sequencer,AudioVideo;Audio +Tuner,A tuner,AudioVideo;Audio +TV,A TV application,AudioVideo;Video +AudioVideoEditing,Application to edit audio/video files,Audio or Video or AudioVideo +Player,Application to play audio/video files,Audio or Video or AudioVideo +Recorder,Application to record audio/video files,Audio or Video or AudioVideo +DiscBurning,Application to burn a disc,AudioVideo +ActionGame,An action game,Game +AdventureGame,Adventure style game,Game +ArcadeGame,Arcade style game,Game +BoardGame,A board game,Game +BlocksGame,Falling blocks game,Game +CardGame,A card game,Game +KidsGame,A game for kids,Game +LogicGame,"Logic games like puzzles, etc",Game +RolePlaying,A role playing game,Game +Shooter,A shooter game,Game +Simulation,A simulation game,Game +SportsGame,A sports game,Game +StrategyGame,A strategy game,Game +Art,Software to teach arts,Education or Science +Construction, ,Education or Science +Music,Musical software,AudioVideo or Education +Languages,Software to learn foreign languages,Education or Science +Artificialtelligence,Artificial Intelligence software,Education or Science +Astronomy,Astronomy software,Education or Science +Biology,Biology software,Education or Science +Chemistry,Chemistry software,Education or Science +ComputerScience,Computer Science software,Education or Science +DataVisualization,Data visualization software,Education or Science +Economy,Economy software,Education or Science +Electricity,Electricity software,Education or Science +Geography,Geography software,Education or Science +Geology,Geology software,Education or Science +Geoscience,"Geoscience software, GIS",Education or Science +History,History software,Education or Science +Humanities,"Software for philosophy, psychology and other humanities",Education or Science +ImageProcessing,Image Processing software,Education or Science +Literature,Literature software,Education or Science +Maps,"Software for viewing maps, navigation, mapping, GPS",Education or Science or Utility +Math,Math software,Education or Science +NumericalAnalysis,Numerical analysis software,Education;Math or Science;Math +MedicalSoftware,Medical software,Education or Science +Physics,Physics software,Education or Science +Robotics,Robotics software,Education or Science +Spirituality,"Religious and spiritual software, theology",Education or Science or Utility +Sports,Sports software,Education or Science +ParallelComputing,Parallel computing software,Education;ComputerScience or Science;ComputerScience +Amusement,A simple amusement,  +Archiving,A tool to archive/backup data,Utility +Compression,A tool to manage compressed data/archives,Utility;Archiving +Electronics,"Electronics software, e.g. a circuit designer",  +Emulator,"Emulator of another platform, such as a DOS emulator",System or Game +Engineering,"Engineering software, e.g. CAD programs",  +FileTools,A file tool utility,Utility or System +FileManager,A file manager,System;FileTools +TerminalEmulator,A terminal emulator application,System +Filesystem,A file system tool,System +Monitor,Monitor application/applet that monitors some resource or activity,System or Network +Security,A security tool,Settings or System +Accessibility,Accessibility,Settings or Utility +Calculator,A calculator,Utility +Clock,A clock application/applet,Utility +TextEditor,A text editor,Utility +Documentation,Help or documentation,  +Adult,Application handles adult or explicit material,  +Core,"Important application, core to the desktop such as a file manager or a help browser",  +KDE,Application based on KDE libraries,QT +COSMIC,Application based on COSMIC libraries,  +GNOME,Application based on GNOME libraries,GTK +XFCE,Application based on XFCE libraries,GTK +DDE,Application based on DDE libraries,Qt +GTK,Application based on GTK+ libraries,  +Qt,Application based on Qt libraries,  +Motif,Application based on Motif libraries,  +Java,"Application based on Java GUI libraries, such as AWT or Swing",  +ConsoleOnly,Application that only works inside a terminal (text-based or command line application),  diff --git a/contrib/conv_cat.pl b/contrib/conv_cat.pl index 6515eb37c..cde590c01 100644 --- a/contrib/conv_cat.pl +++ b/contrib/conv_cat.pl @@ -1,43 +1,8 @@ #!/usr/bin/perl -print "// WARNING: this is an autogenerated file. Any change might be overwritten!\n"; -use strict; -my %grps, my %secs, my %hints; -$grps{"ANY"} = ''; - -for(<>) -{ - chomp; - (my $sec, my $pred) = split(/,/); - next if $sec eq "GTK" or $sec eq "Qt" or $sec eq "GNOME" or $sec eq "KDE" or $sec eq "XFCE" or $sec eq "Java" or $sec eq "ConsoleOnly"; - # key is sanitized name of the filter set or ANY for no filters - my $key = $pred; - $key=~ s/\W//g; - $key = "ANY" if(!$key); - $secs{$sec}=$key; - $hints{$sec}=$pred; - if($key && !defined($grps{$key})) - { - $pred=~s/ or /", "|", "/g; - $pred=~s/;/", "/g; - $grps{$key}=$pred; - } +use Data::Dumper; -} - -print "LPCSTR $_\[\] = { \"$grps{$_}\", \"|\", NULL };\n" for(sort keys %grps); -# start of the list, the end of the list are -print <) { - my $ptr = $secs{$_} ? "(char**) &$secs{$_}" : "NULL"; - print "// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes.".($hints{$_} ? " Context: $hints{$_}\n" : "\n"); - print " { N_(\"$_\"), \"$_\", \"folder\", $ptr, 0, 0}"; - print $_ eq $cats[-1] ? "\n" : ",\n"; + chomp; + my @toks = split(/\s*,\s*|\s*;\s*|\s+or\s+/); + # trim them + @toks = map { $_=~s/^\s*//; $_=~s/\s*$//; $_ } @toks; + #print Dumper(@toks); + push(@stable, \@toks); + # collect all seen subcategory strings + push(@scats, $toks[0]); + $scat_lookup{$toks[0]} = @toks[1..$#toks]; + #next if $sec eq "GTK" or $sec eq "Qt" or $sec eq "GNOME" or $sec eq "KDE" or $sec eq "XFCE" or $sec eq "Java" or $sec eq "ConsoleOnly"; + # key is sanitized name of the filter set or ANY for no filters + #my $subcat = shift(@toks); + # expand to all categories + #@toks = @cats unless @toks; + #push(@toks, "-") unless length(join("", @toks)); + ##$mapping{$key} = @toks; + #for my $maincat (uniq(@toks)) { +# next if ! length($maincat); +# if ($mapping{$subcat}) { +# push(@{$mapping{$subcat}}, $maincat); +# } +# else { +# $mapping{$subcat} = [$maincat] ; +# } +# } +} + +errrrror ab hier die referenzen mehrfach aufloesen bis alles nur noch auf maincats verweist + +# start of the list, the end of the list are +print " +#include \"intl.h\" +#include +namespace spec { + +using mstring = const char*; +using mapping = std::tuple; + +namespace mcat { + ".join("\n\t", map { " + // TRANSLATORS: This is a menu category name from https://specifications.freedesktop.org/menu-spec/menu-spec-1.0.html#category-registry . Please add spaces as needed but no double-quotes. + const auto x$_ = N_(\"$_\");" } @cats)." + + const mstring sall[] = { + ".join(",\n\t\t", map { "x$_" } @cats)." + }; +} + +namespace scat { + ".join("\n\t", map { " + // TRANSLATORS: This is a menu category name from https://specifications.freedesktop.org/menu-spec/menu-spec-1.0.html#category-registry . Please add spaces as needed but no double-quotes. + const auto x$_ = N_(\"$_\");" } @scats)." +} + +static mapping subcat_to_maincat[] = { +"; + +#print "const char* $_\[\] = { \"$grps{$_}\", \"|\", nullptr };\n" for(sort keys %grps); + +print " +// statically presorted list of sub category mapping. See fdomenu.cc for details. +"; + +my @scam; + +for my $x ( sort { ${$a}[0] cmp ${$b}[0]} (@stable)) { + my @l = @{$x}; + my $scat = shift(@l); + if (@l) { + for my $y (uniq( sort { $a cmp $b } (@l))) { + my $true_cat = $y; + while (! grep { $_ eq $y } @cats) { + + } + + if ( grep { $_ eq $y } @cats) { + push(@scam, "\t{ scat::x$scat, mcat::x$y /*, nullptr */ }"); + } + else { + my $true_cat = $y; + + push(@scam, "\t{ scat::x$scat, nullptr /*, scat::x$y */ }"); + } + } + } + else { + push(@scam, "\t{ scat::x$scat, nullptr /*, nullptr */ }"); + } +} +print join(",\n", uniq(@scam)); +print " + }; +} +"; + + +exit(0); + + +for my $subcatkey (sort(keys %mapping)) +{ + for my $mcatref (@{$mapping{$subcatkey}}) { + print "\t// TRANSLATORS: This is a menu category name from https://specifications.freedesktop.org/menu-spec/menu-spec-1.0.html#category-registry . Please add spaces as needed but no double-quotes.\n"; + print "\t{ \"$subcatkey\", \"$mcatref\" },\n"; + } + +# my $ptr = $secs{$_} ? "&$secs{$_}" : "nullptr"; +# print "// TRANSLATORS: This is a menu category name from https://specifications.freedesktop.org/menu-spec/menu-spec-1.0.html#category-registry . Please add spaces as needed but no double-quotes.".($hints{$_} ? " Context: $hints{$_}\n" : "\n"); +# print " { N_(\"$_\"), \"folder\", (const char**) $ptr}"; +# print $_ eq $cats[-1] ? "\n" : ",\n"; } print "}; } diff --git a/contrib/conv_cat.py b/contrib/conv_cat.py new file mode 100644 index 000000000..d9fbfe4eb --- /dev/null +++ b/contrib/conv_cat.py @@ -0,0 +1,122 @@ +import collections +import csv +import re +#import collections + +import sys +#print(csv.list_dialects(), file=sys.stderr) + +debug = True + +edges = collections.defaultdict(lambda: set()) +paths = collections.defaultdict(lambda: list()) + +def add_edges(key :str, multicand :list): + global edges + print(f"{key} -> {multicand}", file=sys.stderr) + edges[key] |= set(multicand) + + +with open('Additional_Categories.csv', newline='') as csvfile: + rdr = csv.reader(csvfile, dialect='unix') + for row in rdr: + #print(row) + assert(len(row) == 3) + multicand = list(map(lambda s: s.strip(), re.split(r'\sor\s', row[2]))) + add_edges(row[0], multicand) + + +#print(edges, file=sys.stderr) + + +def xxx(): + """ + Probably BS, trying to expand the graph, but fails on equally named nodes. + :return: + """ + global edges + keyz = list(edges.keys()) + for k in keyz: + temp = list(edges[k]) + newset = set() + for vv in temp: + xp = vv.split(';') + if len(xp) == 1: + continue + #print(f"multi cand? {k} <-> {vv}") + newset.add(xp[-1]) + chain = list(xp) + chain.append(k) + print(f"chain? {chain}", file=sys.stderr) + while len(chain) > 1: + add_edges(chain[-1], [chain[-2]]) + chain.pop(-1) + edges[k] = newset + + +for k, v in edges.items(): + for vv in v: + #print(f"XX: {vv}") + xp = [k] + list(reversed(vv.strip().split(';'))) + if debug: print(f"{len(xp)} -> {xp}", file=sys.stderr) + paths[len(xp)].append(xp) + +paths[1] = list(map(lambda x: [x], [ + "Accessibility", +"Settings", +"Screensavers", +"Accessories", +"Development", +"Education", +"Game", +"Graphics", +"Multimedia", +"Audio", +"Video", +"AudioVideo", +"Network", +"Office", +"Science", +"System", +"WINE", +"Editors", +"Utility"] + )) + +if debug: print(paths, file=sys.stderr) + +keysByLen = list(reversed(sorted(paths.keys()))) + +print(f"""/** + * WARNING: this file is autogenerated! Any change might be overwritten! + * + * Content is created using conv_cat.py with input from + * https://specifications.freedesktop.org/menu-spec/latest/additional-category-registry.html + * (i.e. the table transformed with LibreOffice to CSV format). + */ + +#ifndef FDO_GEN_MENU_STRUCTURE_H +#define FDO_GEN_MENU_STRUCTURE_H + +#include + +using t_menu_path = std::initializer_list; +using t_menu_path_table = std::initializer_list; +using t_menu_path_table_list = std::initializer_list; + +#define MENU_DEPTH_MAX {keysByLen[0]} + +constexpr t_menu_path_table_list valid_paths = {{""") + +for k in keysByLen: + print(f"\n\t// menu locations of depth {k}\n\t{{") + byFirst = sorted(paths[k], key=lambda l: l[0]) + for v in byFirst: + print("\t\t" + str(v).replace("'", '"').replace('[','{').replace(']','}') + ",") + print("\t},") + +print(f"""}}; + +#define SIZE_OF_MENU_TABLE {len(keysByLen)} + +#endif // FDO_GEN_MENU_STRUCTURE_H""") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bd8e509f8..0eb933bfe 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.13) PROJECT(ICEWM CXX) -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED on) INCLUDE(CheckIncludeFiles) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 3d2fff0f0..392196191 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -1,6 +1,6 @@ /* * FDOmenu - Menu code generator for icewm - * Copyright (C) 2015-2022 Eduard Bloch + * Copyright (C) 2015-2024 Eduard Bloch * * Inspired by icewm-menu-gnome2 and Freedesktop.org specifications * Using pure glib/gio code and a built-in menu structure instead @@ -28,12 +28,362 @@ #include #include +#include +// does not matter, string from C++11 is enough +//#include #include #include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +#include "fdospecgen.h" char const* ApplicationName; +/* +* Certain parts borrowed from apt-cacher-ng by its autor, either from older branches (C++11 compatible) or development branch. +*/ +#if 0 +constexpr unsigned int str2int(const char* str, int h = 0) +{ + //return strhash(str); + // same as pure constexpr + return !str[h] ? 5381 : (str2int(str, h+1) * 33) ^ str[h]; +} + +#define SPACECHARS " \f\n\r\t\v" +#define KVJUNK SPACECHARS "[]=" + +inline void trimFront(std::string &s, const char* junk = SPACECHARS, string::size_type start=0) +{ + auto pos = s.find_first_not_of(junk, start); + if(pos == std::string::npos) + s.clear(); + else if(pos>0) + s.erase(0, pos); +} +inline void trimBack(std::string &s, const string_view junk=SPACECHARS) +{ + auto pos = s.find_last_not_of(junk); + if(pos == std::string::npos) + s.clear(); + else if(pos>0) + s.erase(pos+1); +} +#define CSTR_AND_LEN(sz) sz, sizeof(sz) - 1 +#define LEN_AND_CSTR(sz) sizeof(sz) - 1, sz +#endif + +#define startsWith(where, what) (0==(where).compare(0, (what).size(), (what))) +#define startsWithSz(where, what) (0==(where).compare(0, sizeof((what))-1, (what))) +#define endsWith(where, what) ((where).size()>=(what).size() && \ + 0==(where).compare((where).size()-(what).size(), (what).size(), (what))) +#define endsWithSzAr(where, what) ((where).size()>=(sizeof((what))-1) && \ + 0==(where).compare((where).size()-(sizeof((what))-1), (sizeof((what))-1), (what))) + +/** + * Basic base implementation of a reference-counted class + */ +struct tLintRefcounted +{ +private: + size_t m_nRefCount = 0; +public: + inline void __inc_ref() noexcept + { + m_nRefCount++; + } + inline void __dec_ref() + { + if(--m_nRefCount == 0) + delete this; + } + virtual ~tLintRefcounted() {} + inline size_t __ref_cnt() { return m_nRefCount; } +}; + +/** + * Lightweight intrusive smart pointer with ordinary reference counting + */ +template +class lint_ptr +{ + T * m_ptr = nullptr; +public: + explicit lint_ptr() + { + } + /** + * @brief lint_ptr Captures the pointer and ensures that it's released when the refcount goes to zero, unless initialyTakeRef is set to false. + * If initialyTakeRef is false, the operation is asymmetric, i.e. one extra __dec_ref operation will happen in the end. + * + * @param rawPtr + * @param initialyTakeRef + */ + explicit lint_ptr(T *rawPtr, bool initialyTakeRef = true) : + m_ptr(rawPtr) + { + if(rawPtr && initialyTakeRef) + rawPtr->__inc_ref(); + } + T* construct() + { + reset(new T); + return m_ptr; + } + lint_ptr(const ::lint_ptr & orig) : + m_ptr(orig.m_ptr) + { + if(!m_ptr) return; + m_ptr->__inc_ref(); + } + lint_ptr(::lint_ptr && orig) + { + if (this == &orig) + return; + m_ptr = orig.m_ptr; + orig.m_ptr = nullptr; + } + inline ~lint_ptr() + { + if(!m_ptr) return; + m_ptr->__dec_ref(); + } + T* get() const + { + return m_ptr; + } + bool operator==(const T* raw) const + { + return get() == raw; + } + inline void reset(T *rawPtr) noexcept + { + if(rawPtr == m_ptr) // heh? + return; + reset(); + m_ptr = rawPtr; + if(rawPtr) + rawPtr->__inc_ref(); + } + inline void swap(lint_ptr& other) + { + std::swap(m_ptr, other.m_ptr); + } + inline void reset() noexcept + { + if(m_ptr) + m_ptr->__dec_ref(); + m_ptr = nullptr; + } + lint_ptr& operator=(const lint_ptr &other) + { + if(m_ptr == other.m_ptr) + return *this; + reset(other.m_ptr); + return *this; + } + lint_ptr& operator=(lint_ptr &&other) + { + if(m_ptr == other.m_ptr) + return *this; + + m_ptr = other.m_ptr; + other.m_ptr = nullptr; + return *this; + } + // pointer-like access options + explicit inline operator bool() const noexcept + { + return m_ptr; + } + inline T& operator*() const noexcept + { + return *m_ptr; + } + inline T* operator->() const noexcept + { + return m_ptr; + } + // pointer-like access options + inline bool operator<(const lint_ptr &vs) const noexcept + { + return m_ptr < vs.m_ptr; + } + // pointer-like access options + inline bool operator==(const lint_ptr &vs) const noexcept + { + return m_ptr == vs.m_ptr; + } + /** + * @brief release returns the pointer and makes this invalid while keeping the refcount + * @return Raw pointer + */ + T* release() noexcept + { + auto ret = m_ptr; + m_ptr = nullptr; + return ret; + } +}; + + +/*! + * \brief Simple and convenient split function, outputs resulting tokens into a string vector. + * Operates on user-provided vector, with or without purging the previous contents. + */ +vector & Tokenize(const string & in, const char *sep, + vector & inOutVec, bool bAppend = false, std::string::size_type nStartOffset = 0) +{ + if(!bAppend) + inOutVec.clear(); + + auto pos=nStartOffset, pos2=nStartOffset, oob=in.length(); + while (pos Categories; + + /// Translate with built-in l10n if needed + string& GetTranslatedName() { + if (NameLoc.empty()) { + NameLoc = gettext(Name.c_str()); + } + return NameLoc; + } + + DesktopFile(string filePath, const string &lang) { + std::ifstream dfile; + dfile.open(filePath); + string line; + std::smatch m; + while (dfile) { + line.clear(); + std::getline(dfile, line); + if (line.empty()) { + if (dfile.eof()) + break; + continue; + } + std::regex_search(line, m, line_matcher); + if (m.empty()) + continue; + if (m[3].matched && m[3].compare(lang)) + continue; + //for(auto x: m) cout << x << " - "; + //cout << " = " << m.size() << endl; + + if (m[1] == "Terminal") + Terminal = m[4].compare("true") == 0; + else if (m[1] == "Icon") + Icon = m[4]; + else if (m[1] == "Categories") { + Tokenize(m[4], ";", Categories); + } + else if (m[1] == "Exec") { + Exec = m[4]; + } + else if (m[1] == "Type") { + if (m[4] == "Application") + IsApp = true; + else if (m[4] == "Directory") + IsApp = false; + else continue; + } + else { // must be name + if (m[3].matched) + NameLoc = m[4]; + else + Name = m[4]; + } + + + //cout << m.size() << endl; + //cout << m[0] << " - " << m[1] << " - " << m[2] << " - " << m[3] < load(const string& path, const string& lang) { + try + { + auto ret = new DesktopFile(path, lang); + return lint_ptr(ret); + } + catch(const std::exception&) + { + return lint_ptr(); + } +} + +}; + + +#if 0 + #ifndef LPCSTR // mind the MFC // easier to read... typedef const char* LPCSTR; @@ -45,6 +395,7 @@ typedef const char* LPCSTR; #include #include #include "ycollections.h" +#endif // program options bool add_sep_before = false; @@ -63,7 +414,7 @@ auto flat_sep = " / "; char* terminal_command; char* terminal_option; -template +template struct auto_raii { T m_p; auto_raii(T xp) : @@ -74,37 +425,279 @@ struct auto_raii { TFreeFunc(m_p); } }; + + +const char* rtls[] = { + "ar", // arabic + "fa", // farsi + "he", // hebrew + "ps", // pashto + "sd", // sindhi + "ur", // urdu +}; + +#if 0 typedef auto_raii auto_gfree; typedef auto_raii auto_gunref; +auto cstr_deleter = [](char* ptr) +{ + free((void*) ptr); +}; +using cstr_unique = std::unique_ptr; + /* static int cmpUtf8(const void *p1, const void *p2) { return g_utf8_collate((LPCSTR ) p1, (LPCSTR ) p2); } */ + +/* struct tLtUtf8 { bool operator() (const std::string& a, const std::string& b) { - return g_utf8_collate(a.c_str(), b.c_str()) < 0; + //return g_utf8_collate(a.c_str(), b.c_str()) < 0; + //static auto& f = std::use_facet>(std::locale::classic); + } } lessThanUtf8; +*/ +struct tLessOp4Localized { + std::locale loc; // default locale + const std::collate& coll = std::use_facet >(loc); + bool operator() (const std::string& a, const std::string& b) { + return coll.compare (a.data(), a.data() + a.size(), + b.data(), b.data()+b.size()) < 0; + } +} locStringComper; class tDesktopInfo; typedef YVec tCharVec; tCharVec sys_folders, home_folders; -tCharVec* sys_home_folders[] = { &sys_folders, &home_folders }; -const char* rtls[] = { - "ar", // arabic - "fa", // farsi - "he", // hebrew - "ps", // pashto - "sd", // sindhi - "ur", // urdu +std::array sys_home_folders = { &sys_folders, &home_folders }; +std::array home_sys_folders = { &home_folders, &sys_folders }; + + +char const * const par_sec_dummy[] = { nullptr }; + +void decorate_and_print(); + + +// little adapter class to extract information we get from desktop files using GLib methods +class tDesktopInfo { + GDesktopAppInfo *pInfo = nullptr; + mutable std::string found_name; +public: + tDesktopInfo(LPCSTR szFileName) { + pInfo = g_desktop_app_info_new_from_filename(szFileName); + if (!pInfo) + return; + + // tear down if not permitted + if (!g_app_info_should_show(*this)) { + g_object_unref(pInfo); + pInfo = nullptr; + } + found_name = g_app_info_get_display_name((GAppInfo*) pInfo); + if (found_name.empty()) + found_name = g_desktop_app_info_get_generic_name(pInfo); + } + + inline operator GAppInfo*() { + return (GAppInfo*) pInfo; + } + + inline operator GDesktopAppInfo*() { + return pInfo; + } + + inline operator bool() { + return pInfo; + } + + //~tDesktopInfo() { + // XXX: call g_free on pInfo? free on d_file? + //} + + const std::string& get_name() const { + return found_name; + } + + bool operator<(const tDesktopInfo& other) const { + return locStringComper.operator()(get_name(), other.get_name()); + } + + char * get_icon_path() const { + auto pIcon = g_app_info_get_icon((GAppInfo*) pInfo); + auto_gunref free_icon((GObject*) pIcon); + return pIcon ? g_icon_to_string(pIcon) : nullptr; + } + + // split tokens into a list, to be cleared by g_strfreev + gchar** get_cat_tokens() { + + LPCSTR pCats = g_desktop_app_info_get_categories(pInfo); + if (!pCats) + pCats = "Other"; + if (0 == strncmp(pCats, "X-", 2)) + return (gchar**) malloc(0); + + return g_strsplit(pCats, ";", -1); + } + + std::string get_launch_cmd() { + LPCSTR cmdraw = g_app_info_get_commandline((GAppInfo*) pInfo); + if (!cmdraw || !*cmdraw) + return "-"; + using namespace std; + string ret(cmdraw); + auto p = ret.find_first_not_of(" \f\n\r\t\v"); + if (p != string::npos) + ret = ret.substr(p); + + // detect URLs and expansion patterns which wouldn't work with plain exec + auto use_direct_call = ret.find_first_of(":%") == string::npos; + + auto bForTerminal = false; + #if GLIB_VERSION_CUR_STABLE >= G_ENCODE_VERSION(2, 36) + bForTerminal = g_desktop_app_info_get_boolean(pInfo, "Terminal"); + #else + // cannot check terminal property, callback is as safe bet + use_direct_call = false; + #endif + + if (use_direct_call && !bForTerminal) // best case + return ret; + + if (bForTerminal && nonempty(terminal_command)) + return std::string(terminal_command) + " -e " + ret; + + // not simple command or needs a terminal started via launcher callback, or both + return std::string(ApplicationName) + " \"" + g_desktop_app_info_get_filename(pInfo) + "\""; + } }; -struct tListMeta { - LPCSTR title, key, icon; - LPCSTR const * const parent_sec; - enum eLoadFlags { +struct tMenuAnchor { + // list of application elements, ordered by the translated names + std::set translated_apps; + bool is_localized_builtin = false; + bool is_localized_system = false; + std::string icon_name = "folder"; + + static tMenuAnchor& find_menu_anchor(tDesktopInfo& dinfo); + void add(tDesktopInfo&& app) { translated_apps.emplace(std::move(app)); } +}; + +// helper to collect everything later +//struct tMenuAnchorKey { +// std::array levels = {0, 0, 0, 0}; +//}; + +using tMenuAnchorKey = std::array; + +// all pointer ordered which is okay, we operate on static entries +std::unordered_map all_content; +std::unordered_set seen_cats; +tMenuAnchor garbage_bin; + +tMenuAnchor& setup_anchor(tMenuAnchorKey key) { + for(auto x: key) if(x) seen_cats.emplace(x); + return all_content[key]; +} +/* +tMenuAnchor& setup_anchor(LPCSTR main_cat, LPCSTR sub_cat = nullptr, + LPCSTR sub_sub_cat = nullptr, + LPCSTR sub_sub_sub_cat = nullptr) { +return setup_anchor({main_cat, sub_cat, sub_sub_cat, sub_sub_sub_cat}); +} +*/ +LPCSTR dig_key(tMenuAnchorKey& key, LPCSTR prev_key, unsigned depth) { + + + + spec::mapping wanted(scat, nullptr, nullptr); + auto from_to = equal_range(spec::subcat_to_maincat, spec::subcat_to_maincat + ACOUNT(spec::subcat_to_maincat), + wanted, + [](const spec::mapping &a, const spec::mapping &b) { return strcmp(get<0>(a), get<0>(b)) < 0; } ); + + + depth++; + if(depth >= key.size()) + return; + key[depth] = dig_key(key, depth); +} + +tMenuAnchor& tMenuAnchor::find_menu_anchor(tDesktopInfo& dinfo) { + + LPCSTR pCats = g_desktop_app_info_get_categories(dinfo); + + if (!pCats) + pCats = "Other"; + if (0 == strncmp(pCats, "X-", 2)) + return garbage_bin; + + auto ppCats = dinfo.get_cat_tokens(); + if (!ppCats) + return garbage_bin; + + // Pigeonholing roughly by guessed menu structure + using namespace std; + static vector mcats, scats; + mcats.clear(); + scats.clear(); + + for(auto p = *ppCats; *p; p++) { + auto endex = spec::mcat::sall + ACOUNT(spec::mcat::sall); + auto is_mcat = binary_search(spec::mcat::sall, endex, + [](LPCSTR a, LPCSTR b) { return strcmp(a, b) < 0; } ); + (is_mcat ? mcats : scats).push_back(p); + } + + auto endex = spec::subcat_to_maincat + ACOUNT(spec::subcat_to_maincat); + bool found_subcat = false; + for(auto &mcat: mcats) { + for (auto &scat: scats) { + spec::mapping wanted(scat, nullptr, nullptr); + auto from_to = equal_range(spec::subcat_to_maincat, endex, wanted, + [](const spec::mapping &a, const spec::mapping &b) { return strcmp(get<0>(a), get<0>(b)) < 0; } ); + if (from_to.first == endex) + continue; + found_subcat = true; + + for(auto it = from_to.first; it != from_to.second; ++it) { + auto mc = get<0>(*it); + auto sc = get<1>(*it); + auto altsc = get<2>(*it); + if (mc) { + // perfect match, fast path + setup_anchor({mc, sc, 0, 0}).add(move(dinfo)); + } + else { + tMenuAnchorKey key = {} + for(unsigned i = 0; i < 4; ++i) { + + } + } + } + } + } + + + g_strfreev(ppCats); +} + + +struct tStaticMenuDescription { + LPCSTR key, icon; + const char ** parent_sec; +}; + +// shim class which describes the Menu related attributes, which can be fetched from static data or adjusted with localized or additional things from filesystem +class tListMeta { + LPCSTR title = nullptr, icon = nullptr, key = nullptr; + tStaticMenuDescription *builtin_data = nullptr; + tListMeta() {} + /* + enum eLoadFlags :char { NONE = 0, DEFAULT_TRANSLATED = 1, SYSTEM_TRANSLATED = 2, @@ -113,32 +706,61 @@ struct tListMeta { SYSTEM_ICON = 16, }; short load_state_icon, load_state_title; +*/ + std::unordered_map meta_lookup_data; + std::unordered_map known_directory_files; + +public: + tListMeta(const tDesktopInfo&); + static tListMeta make_dummy() { return tListMeta();} + LPCSTR get_key() const { + if (key) + return key; + if (builtin_data && builtin_data->key) + return builtin_data->key; + return ""; + } + LPCSTR get_icon() const { + if (icon) + return icon; + if (builtin_data && builtin_data->icon) + return builtin_data->icon; + return "-"; + } LPCSTR get_title() const { - auto ret = title ? title : key; - //printf("gt: %s\n", ret); - if (!load_state_title) { - return gettext(ret); - } - return ret; + if (title) + return title; + if (builtin_data && builtin_data->key) + return builtin_data->key; + return ""; + } + decltype(tStaticMenuDescription::parent_sec) get_parent_secs() const { + if (builtin_data) + return builtin_data->parent_sec; + return (const char**) &par_sec_dummy; } }; -std::unordered_map meta_lookup_data, gh_directory_files; tListMeta* lookup_category(const std::string& key) { + #ifdef OLD_IMP + auto it = meta_lookup_data.find(key); if (it == meta_lookup_data.end()) return nullptr; auto* ret = (tListMeta*) it->second; #ifdef CONFIG_I18N // auto-translate the default title for the user's language - if (ret && !ret->title) - ret->title = gettext(ret->key); + //if (ret && !ret->title) + // ret->title = gettext(ret->key); //printf("Got title? %s -> %s\n", ret->key, ret->title); #endif return ret; + #else +return nullptr; + #endif } std::stack flat_pfxes; @@ -228,14 +850,14 @@ struct t_menu_node { if (nonempty(generic) && !strcasestr(title, generic)) { if (right_to_left) { printf("prog \"(%s) %s%s\" %s %s\n", - generic, flat_pfx(), title, meta->icon, progCmd); + generic, flat_pfx(), title, meta->get_icon(), progCmd); } else { printf("prog \"%s%s (%s)\" %s %s\n", - flat_pfx(), title, generic, meta->icon, progCmd); + flat_pfx(), title, generic, meta->get_icon(), progCmd); } } else - printf("prog \"%s%s\" %s %s\n", flat_pfx(), title, meta->icon, progCmd); + printf("prog \"%s%s\" %s %s\n", flat_pfx(), title, meta->get_icon(), progCmd); } ctx->count++; return; @@ -244,7 +866,8 @@ struct t_menu_node { // else: render as menu if (ctx->level == 1 && !no_sep_others - && 0 == strcmp(meta->key, "Other")) { + && 0 == strcmp(meta->get_key(), "Other")) { + ctx->print_separated = this; return; } @@ -257,7 +880,7 @@ struct t_menu_node { if (flat_output) flat_add_level(title); else - printf("menu \"%s\" %s {\n", title, meta->icon); + printf("menu \"%s\" %s {\n", title, meta->get_icon()); } ctx->level++; @@ -328,7 +951,7 @@ struct t_menu_node { tListMeta* pNewCatInfo = nullptr; tListMeta** ppLastMainCat = nullptr; - for (auto pSubCatName = subCatCandidate->parent_sec; + for (auto pSubCatName = subCatCandidate->get_parent_secs(); *pSubCatName; ++pSubCatName) { // stop nesting, add to the last visited/created submenu bool store_here = **pSubCatName == '|'; @@ -356,7 +979,7 @@ struct t_menu_node { // empty filter means ANY if (**pSubCatName == '\0' - || 0 == strcmp(*pSubCatName, (**ppMainCat).key)) { + || 0 == strcmp(*pSubCatName, (**ppMainCat).get_key())) { // the category is enabled! skipping = false; pTree = &root; @@ -385,7 +1008,7 @@ struct t_menu_node { tListMeta *pResolved = lookup_category(*pCatKey); if (!pResolved) continue; - if (!pResolved->parent_sec) + if (!pResolved->get_parent_secs()) matched_main_cats.add(pResolved); else matched_sub_cats.add(pResolved); @@ -408,85 +1031,30 @@ struct t_menu_node { } }; -/* - * Two relevant columns from https://specifications.freedesktop.org/menu-spec/latest/apas02.html - * exported as CSV with , delimiter and with manual fix of HardwareSettings order. - * - * Powered by PERL! See contrib/conv_cat.pl - */ -#include "fdospecgen.h" -bool checkSuffix(const char* szFilename, const char* szFileSfx) -{ - const char* pSfx = strrchr(szFilename, '.'); - return pSfx && 0 == strcmp(pSfx+1, szFileSfx); +tListMeta::tListMeta(const tDesktopInfo& dinfo) { + icon = Elvis((const char*) dinfo.get_icon_path(), "-"); + title = key = Elvis(dinfo.get_name(), ""); } -// for short-living objects describing the information we get from desktop files -class tDesktopInfo { -public: - GDesktopAppInfo *pInfo; - LPCSTR d_file; - tDesktopInfo(LPCSTR szFileName) : d_file(szFileName) { - pInfo = g_desktop_app_info_new_from_filename(szFileName); - if (!pInfo) - return; + #ifdef OLD_IMP - // tear down if not permitted - if (!g_app_info_should_show(*this)) { - g_object_unref(pInfo); - pInfo = nullptr; - } - } - - inline operator GAppInfo*() { - return (GAppInfo*) pInfo; - } - - inline operator GDesktopAppInfo*() { - return pInfo; - } - - ~tDesktopInfo() { } - - LPCSTR get_name() const { - if (!pInfo) - return nullptr; - return g_app_info_get_display_name((GAppInfo*) pInfo); - } - - LPCSTR get_generic() const { - if (!pInfo || !generic_name) - return nullptr; - return g_desktop_app_info_get_generic_name(pInfo); - } - - char * get_icon_path() const { - auto pIcon = g_app_info_get_icon((GAppInfo*) pInfo); - auto_gunref free_icon((GObject*) pIcon); - return pIcon ? g_icon_to_string(pIcon) : nullptr; - } -}; - -tListMeta no_description = {nullptr,nullptr,nullptr,nullptr}; - -t_menu_node root(&no_description); +t_menu_node root(tListMeta::make_dummy()); +#endif // variant with local description data struct t_menu_node_app : t_menu_node { tListMeta description; + t_menu_node_app(const tDesktopInfo& dinfo) : t_menu_node(&description), - description(no_description) { - description.icon = Elvis((const char*) dinfo.get_icon_path(), "-"); + description(dinfo) { LPCSTR cmdraw = g_app_info_get_commandline((GAppInfo*) dinfo.pInfo); if (!cmdraw || !*cmdraw) return; - description.title = description.key = Elvis(dinfo.get_name(), ""); - // if the strings contains the exe and then only file/url tags that we wouldn't // set anyway, THEN create a simplified version and use it later (if bSimpleCmd is true) // OR use the original command through a wrapper (if bSimpleCmd is false) @@ -542,7 +1110,7 @@ struct t_menu_node_app : t_menu_node // not simple command or needs a terminal started via launcher callback, or both progCmd = g_strdup_printf("%s \"%s\"", ApplicationName, dinfo.d_file); if (cmdMod && cmdMod != progCmd) - g_free(cmdMod); + g_free(cmdMod), cmdMod = nullptr; generic = dinfo.get_generic(); } ~t_menu_node_app() { @@ -617,6 +1185,8 @@ void pickup_folder_info(LPCSTR szDesktopFile) { if (!pCat) return; + + #ifdef OLD_IMP if (pCat->load_state_icon < tListMeta::SYSTEM_ICON) { LPCSTR icon_name = g_key_file_get_string (kf, "Desktop Entry", "Icon", nullptr); @@ -636,6 +1206,7 @@ void pickup_folder_info(LPCSTR szDesktopFile) { bool same_trans = 0 == strcmp (cat_title_c, cat_title); if (!same_trans) pCat->load_state_title = tListMeta::SYSTEM_TRANSLATED; + // otherwise: not sure, keep searching for a better translation } // something special, donate the icon to similar items unless they have a better one @@ -652,26 +1223,17 @@ void pickup_folder_info(LPCSTR szDesktopFile) { t->load_state_icon = tListMeta::FALLBACK_ICON; } } + #endif + } void insert_app_info(const char* szDesktopFile) { tDesktopInfo dinfo(szDesktopFile); - if (!dinfo.pInfo) - return; - - LPCSTR pCats = g_desktop_app_info_get_categories(dinfo.pInfo); - if (!pCats) - pCats = "Other"; - if (0 == strncmp(pCats, "X-", 2)) + if (!dinfo) return; - t_menu_node* pNode = new t_menu_node_app(dinfo); - // Pigeonholing roughly by guessed menu structure - - gchar **ppCats = g_strsplit(pCats, ";", -1); - root.add_by_categories(pNode, ppCats); - g_strfreev(ppCats); - + auto& to_where = tMenuAnchor::find_menu_anchor(dinfo); + to_where.translated_apps.insert(std::move(dinfo)); } void proc_dir_rec(LPCSTR syspath, unsigned depth, @@ -758,15 +1320,14 @@ static void init() { //meta_lookup_data = g_hash_table_new(g_str_hash, g_str_equal); //gh_directory_files = g_hash_table_new(g_str_hash, g_str_equal); - for (unsigned i = 0; i < ACOUNT(spec::menuinfo); ++i) { - tListMeta& what = spec::menuinfo[i]; +#ifdef OLD_IMP + + for (auto& what: spec::menuinfo) { if (no_sub_cats && what.parent_sec) continue; - // enforce non-const since we are not destroying that data ever, no key_destroy_func set! -// g_hash_table_insert(meta_lookup_data, (gpointer) what.key, &what); meta_lookup_data[what.key] = &what; } - +#endif const char* terminals[] = { terminal_option, getenv("TERMINAL"), TERM, "urxvt", "alacritty", "roxterm", "xterm", "x-terminal-emulator", "terminator" }; @@ -775,31 +1336,6 @@ static void init() { break; } -static void help(LPCSTR home, LPCSTR dirs, FILE* out, int xit) { - g_fprintf(out, - "USAGE: icewm-menu-fdo [OPTIONS] [FILENAME]\n" - "OPTIONS:\n" - "-g, --generic\tInclude GenericName in parentheses of progs\n" - "-o, --output=FILE\tWrite the output to FILE\n" - "-t, --terminal=NAME\tUse NAME for a terminal that has '-e'\n" - "--seps \tPrint separators before and after contents\n" - "--sep-before\tPrint separator before the contents\n" - "--sep-after\tPrint separator only after contents\n" - "--no-sep-others\tNo separation of the 'Others' menu point\n" - "--no-sub-cats\tNo additional subcategories, just one level of menues\n" - "--flat\tDisplay all apps in one layer with category hints\n" - "--flat-sep STR\tCategory separator string used in flat mode (default: ' / ')\n" - "--match PAT\tDisplay only apps with title containing PAT\n" - "--imatch PAT\tLike --match but ignores the letter case\n" - "--match-sec\tApply --match or --imatch to apps AND sections\n" - "--match-osec\tApply --match or --imatch only to sections\n" - "FILENAME\tAny .desktop file to launch its application Exec command\n" - "This program also listens to environment variables defined by\n" - "the XDG Base Directory Specification:\n" - "XDG_DATA_HOME=%s\n" - "XDG_DATA_DIRS=%s\n", home, dirs); - exit(xit); -} #ifdef DEBUG_xxx void dbgPrint(const gchar *msg) @@ -903,19 +1439,21 @@ int main(int argc, char** argv) { split_folders(sysshare, sys_folders); split_folders(usershare, home_folders); - for(auto& where: sys_home_folders) { - for (auto p = where->data; p < where->data + where->size; ++p) { - proc_dir_rec(*p, 0, pickup_folder_info, "desktop-directories", - "directory"); - } + for(auto& where: home_sys_folders) { + for (auto p: *where) + proc_dir_rec(p, 0, insert_app_info, "applications", "desktop"); } - for(auto& where: sys_home_folders) { - for (auto p = where->data; p < where->data + where->size; ++p) - proc_dir_rec(*p, 0, insert_app_info, "applications", "desktop"); + + for(auto& where: home_sys_folders) { + for (auto p: *where) { + proc_dir_rec(p, 0, pickup_folder_info, "desktop-directories", + "directory"); + } } - root.print(); + //root.print(); + decorate_and_print(); //printf("What? %s\n", gettext("Building")); @@ -925,5 +1463,268 @@ int main(int argc, char** argv) { return EXIT_SUCCESS; } +#else + +#include +#include +#include +#include + + +typedef void (*tFuncInsertInfo)(const string& absPath, intptr_t any); + +class FsScan { + private: + std::set> reclog; + function cb; + string sFileNameExtFilter; + + public: + FsScan(decltype(FsScan::cb) cb, const string &sFileNameExtFilter = "") { + this->cb = cb; + this->sFileNameExtFilter = sFileNameExtFilter; + } + void scan(const string &sStartdir) { + proc_dir_rec(sStartdir); + } +private: +void proc_dir_rec(const string &path) { + auto pdir = opendir(path.c_str()); + if (!pdir) + return; + auto_raii dircloser(pdir); + auto fddir(dirfd(pdir)); + + //const gchar *szFilename(nullptr); + dirent *pent; + struct stat stbuf; + + while (nullptr != (pent = readdir(pdir))) { + if (pent->d_name[0] == '.') + continue; + pent->d_name[255] = 0; + string fname(pent->d_name); + if (!sFileNameExtFilter.empty() && !endsWith(fname, sFileNameExtFilter)) + continue; + if (fstatat(fddir, fname.c_str(), &stbuf, 0)) + continue; + if (S_ISDIR(stbuf.st_mode)) { + // link loop detection + auto prev = make_pair(stbuf.st_ino, stbuf.st_dev); + auto hint = reclog.insert(prev); + if (hint.second) { // we added a new one, otherwise do not descend + proc_dir_rec(path + "/" + fname); + reclog.erase(hint.first); + } + } + + if (!S_ISREG(stbuf.st_mode)) + continue; + + cb(path + "/" + fname); + } +} + +}; + +static void help(bool to_stderr, int xit) { + (to_stderr ? cerr : cout) << + "USAGE: icewm-menu-fdo [OPTIONS] [FILENAME]\n" + "OPTIONS:\n" + "-g, --generic\tInclude GenericName in parentheses of progs\n" + "-o, --output=FILE\tWrite the output to FILE\n" + "-t, --terminal=NAME\tUse NAME for a terminal that has '-e'\n" + "--seps \tPrint separators before and after contents\n" + "--sep-before\tPrint separator before the contents\n" + "--sep-after\tPrint separator only after contents\n" + "--no-sep-others\tNo separation of the 'Others' menu point\n" + "--no-sub-cats\tNo additional subcategories, just one level of menues\n" + "--flat\tDisplay all apps in one layer with category hints\n" + "--flat-sep STR\tCategory separator string used in flat mode (default: ' / ')\n" + "--match PAT\tDisplay only apps with title containing PAT\n" + "--imatch PAT\tLike --match but ignores the letter case\n" + "--match-sec\tApply --match or --imatch to apps AND sections\n" + "--match-osec\tApply --match or --imatch only to sections\n" + "FILENAME\tAny .desktop file to launch its application Exec command\n" + "This program also listens to environment variables defined by\n" + "the XDG Base Directory Specification:\n" + "XDG_DATA_HOME=" << Elvis(getenv("XDG_DATA_HOME"), (char*)"") << "\n" + "XDG_DATA_DIRS=" << Elvis(getenv("XDG_DATA_DIRS"), (char*)"") << endl; + exit(xit); +} + +struct tMenuNode { + void sink_in(lint_ptr df); + + map submenues; + map apps; + unordered_set dont_add_mark; + +}; + +int main(int argc, char** argv) { + + // basic framework and environment initialization + ApplicationName = my_basename(argv[0]); + +#ifdef CONFIG_I18N + setlocale(LC_ALL, ""); + + auto msglang = YLocale::getCheckedExplicitLocale(false); + right_to_left = msglang && std::any_of(rtls, rtls + ACOUNT(rtls), + [&](const char* rtl) { + return rtl[0] == msglang[0] && rtl[1] == msglang[1]; + } + ); + bindtextdomain(PACKAGE, LOCDIR); + textdomain(PACKAGE); +#endif + +#warning FIXME, implement internal launcher which covers the damn %substitutions without glib +#if 0 + if (argc == 2 && ! endsWithSzAr(string(argv[1]), ".desktop")) + && launch(argv[1], argv + 2, argc - 2) { + return EXIT_SUCCESS; + } +#endif + + vector sharedirs; + const char *p; + auto pUserShare = getenv("XDG_DATA_HOME"); + if (pUserShare && *pUserShare) + Tokenize(pUserShare, ":", sharedirs, true); + else if (nullptr != (p = getenv("HOME")) && *p) + sharedirs.push_back(string(p) + "/.local/share"); + + // system dirs, either from environment or from static locations + auto sysshare = getenv("XDG_DATA_DIRS"); + if (sysshare && !*sysshare) + Tokenize(sysshare, ":", sharedirs, true); + else + sharedirs.push_back("/usr/local/share"), sharedirs.push_back("/usr/share"); + + for (auto pArg = argv + 1; pArg < argv + argc; ++pArg) { + if (is_version_switch(*pArg)) { + cout << "icewm-menu-fdo " + VERSION + ", Copyright 2015-2024 Eduard Bloch, 2017-2023 Bert Gijsbers." + < pDf) +{ + auto& df=*pDf; + dont_add_mark.clear(); + bool bFoundCategories = false; + + auto add_sub_menues = [&](const t_menu_path& mp) { + tMenuNode* cur = this; + for (auto it = std::rbegin(mp); it != std::rend(mp); ++it) { + cerr << "adding submenu: " <<*it <submenues[*it]; + } + return cur; + }; + + for(const auto& cat: df.Categories) { + cerr << "where does it fit? " << cat << endl; + t_menu_path refval = {df.Name.c_str()}; + static auto comper = [](const t_menu_path& a, const t_menu_path& b) { + cerr << "left: " << *a.begin() << " vs. right: " << *b.begin() << endl; + return strcmp(*a.begin(), *b.begin()) < 0; + }; + for(const auto& w: valid_paths) { + auto rng = std::equal_range(w.begin(), w.end(), refval, comper); + for(auto it = rng.first; it != rng.second; ++it) { + auto&tgt = * add_sub_menues(*it); + } + + } + + } + +} // vim: set sw=4 ts=4 et: diff --git a/src/fdospecgen.h b/src/fdospecgen.h index 449086d2d..b1b72131f 100644 --- a/src/fdospecgen.h +++ b/src/fdospecgen.h @@ -1,321 +1,236 @@ -// WARNING: this is an autogenerated file. Any change might be overwritten! -LPCSTR ANY[] = { "", "|", nullptr }; -LPCSTR AudioVideo[] = { "AudioVideo", "|", nullptr }; -LPCSTR AudioVideoAudio[] = { "AudioVideo", "Audio", "|", nullptr }; -LPCSTR AudioVideoVideo[] = { "AudioVideo", "Video", "|", nullptr }; -LPCSTR AudioVideoorEducation[] = { "AudioVideo", "|", "Education", "|", nullptr }; -LPCSTR AudioorVideoorAudioVideo[] = { "Audio", "|", "Video", "|", "AudioVideo", "|", nullptr }; -LPCSTR Development[] = { "Development", "|", nullptr }; -LPCSTR EducationComputerScienceorScienceComputerScience[] = { "Education", "ComputerScience", "|", "Science", "ComputerScience", "|", nullptr }; -LPCSTR EducationMathorScienceMath[] = { "Education", "Math", "|", "Science", "Math", "|", nullptr }; -LPCSTR EducationorScience[] = { "Education", "|", "Science", "|", nullptr }; -LPCSTR EducationorScienceorUtility[] = { "Education", "|", "Science", "|", "Utility", "|", nullptr }; -LPCSTR Game[] = { "Game", "|", nullptr }; -LPCSTR Graphics[] = { "Graphics", "|", nullptr }; -LPCSTR Graphics2DGraphics[] = { "Graphics", "2DGraphics", "|", nullptr }; -LPCSTR GraphicsScanning[] = { "Graphics", "Scanning", "|", nullptr }; -LPCSTR GraphicsorOffice[] = { "Graphics", "|", "Office", "|", nullptr }; -LPCSTR Network[] = { "Network", "|", nullptr }; -LPCSTR NetworkorAudio[] = { "Network", "|", "Audio", "|", nullptr }; -LPCSTR NetworkorDevelopment[] = { "Network", "|", "Development", "|", nullptr }; -LPCSTR Office[] = { "Office", "|", nullptr }; -LPCSTR OfficeorDevelopment[] = { "Office", "|", "Development", "|", nullptr }; -LPCSTR OfficeorDevelopmentorAudioVideo[] = { "Office", "|", "Development", "|", "AudioVideo", "|", nullptr }; -LPCSTR OfficeorNetwork[] = { "Office", "|", "Network", "|", nullptr }; -LPCSTR OfficeorTextTools[] = { "Office", "|", "TextTools", "|", nullptr }; -LPCSTR Settings[] = { "Settings", "|", nullptr }; -LPCSTR SettingsHardwareSettings[] = { "Settings", "HardwareSettings", "|", nullptr }; -LPCSTR SettingsorSystem[] = { "Settings", "|", "System", "|", nullptr }; -LPCSTR SettingsorUtility[] = { "Settings", "|", "Utility", "|", nullptr }; -LPCSTR System[] = { "System", "|", nullptr }; -LPCSTR SystemFileTools[] = { "System", "FileTools", "|", nullptr }; -LPCSTR SystemorGame[] = { "System", "|", "Game", "|", nullptr }; -LPCSTR SystemorNetwork[] = { "System", "|", "Network", "|", nullptr }; -LPCSTR Utility[] = { "Utility", "|", nullptr }; -LPCSTR UtilityArchiving[] = { "Utility", "Archiving", "|", nullptr }; -LPCSTR UtilityorSystem[] = { "Utility", "|", "System", "|", nullptr }; +/** + * WARNING: this file is autogenerated! Any change might be overwritten! + * + * Content is created using conv_cat.py with input from + * https://specifications.freedesktop.org/menu-spec/latest/additional-category-registry.html + * (i.e. the table transformed with LibreOffice to CSV format). + */ -namespace spec { +#ifndef FDO_GEN_MENU_STRUCTURE_H +#define FDO_GEN_MENU_STRUCTURE_H -tListMeta menuinfo[] = -{ -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Graphics - { N_("2DGraphics"), "2DGraphics", "folder", (char**) &Graphics, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Graphics - { N_("3DGraphics"), "3DGraphics", "folder", (char**) &Graphics, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Settings or Utility - { N_("Accessibility"), "Accessibility", "folder", (char**) &SettingsorUtility, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Settings or Utility - { N_("Accessibility"), "Accessibility", "folder", (char**) &SettingsorUtility, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("Accessories"), "Accessories", "folder", nullptr, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game - { N_("ActionGame"), "ActionGame", "folder", (char**) &Game, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("Adult"), "Adult", "folder", (char**) &ANY, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game - { N_("AdventureGame"), "AdventureGame", "folder", (char**) &Game, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("Amusement"), "Amusement", "folder", (char**) &ANY, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game - { N_("ArcadeGame"), "ArcadeGame", "folder", (char**) &Game, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Utility - { N_("Archiving"), "Archiving", "folder", (char**) &Utility, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science - { N_("Art"), "Art", "folder", (char**) &EducationorScience, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science - { N_("ArtificialIntelligence"), "ArtificialIntelligence", "folder", (char**) &EducationorScience, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science - { N_("Astronomy"), "Astronomy", "folder", (char**) &EducationorScience, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("Audio"), "Audio", "folder", nullptr, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("AudioVideo"), "AudioVideo", "folder", nullptr, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Audio or Video or AudioVideo - { N_("AudioVideoEditing"), "AudioVideoEditing", "folder", (char**) &AudioorVideoorAudioVideo, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science - { N_("Biology"), "Biology", "folder", (char**) &EducationorScience, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game - { N_("BlocksGame"), "BlocksGame", "folder", (char**) &Game, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game - { N_("BoardGame"), "BoardGame", "folder", (char**) &Game, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Development - { N_("Building"), "Building", "folder", (char**) &Development, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Utility - { N_("Calculator"), "Calculator", "folder", (char**) &Utility, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office - { N_("Calendar"), "Calendar", "folder", (char**) &Office, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game - { N_("CardGame"), "CardGame", "folder", (char**) &Game, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office - { N_("Chart"), "Chart", "folder", (char**) &Office, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network - { N_("Chat"), "Chat", "folder", (char**) &Network, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science - { N_("Chemistry"), "Chemistry", "folder", (char**) &EducationorScience, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Utility - { N_("Clock"), "Clock", "folder", (char**) &Utility, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Utility;Archiving - { N_("Compression"), "Compression", "folder", (char**) &UtilityArchiving, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science - { N_("ComputerScience"), "ComputerScience", "folder", (char**) &EducationorScience, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science - { N_("Construction"), "Construction", "folder", (char**) &EducationorScience, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office - { N_("ContactManagement"), "ContactManagement", "folder", (char**) &Office, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("Core"), "Core", "folder", (char**) &ANY, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science - { N_("DataVisualization"), "DataVisualization", "folder", (char**) &EducationorScience, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office or Development or AudioVideo - { N_("Database"), "Database", "folder", (char**) &OfficeorDevelopmentorAudioVideo, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Development - { N_("Debugger"), "Debugger", "folder", (char**) &Development, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Settings - { N_("DesktopSettings"), "DesktopSettings", "folder", (char**) &Settings, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("Development"), "Development", "folder", nullptr, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network - { N_("Dialup"), "Dialup", "folder", (char**) &Network, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office or TextTools - { N_("Dictionary"), "Dictionary", "folder", (char**) &OfficeorTextTools, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: AudioVideo - { N_("DiscBurning"), "DiscBurning", "folder", (char**) &AudioVideo, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("Documentation"), "Documentation", "folder", (char**) &ANY, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science - { N_("Economy"), "Economy", "folder", (char**) &EducationorScience, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("Editors"), "Editors", "folder", nullptr, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("Education"), "Education", "folder", nullptr, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science - { N_("Electricity"), "Electricity", "folder", (char**) &EducationorScience, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("Electronics"), "Electronics", "folder", (char**) &ANY, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office or Network - { N_("Email"), "Email", "folder", (char**) &OfficeorNetwork, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: System or Game - { N_("Emulator"), "Emulator", "folder", (char**) &SystemorGame, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("Engineering"), "Engineering", "folder", (char**) &ANY, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network - { N_("Feed"), "Feed", "folder", (char**) &Network, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: System;FileTools - { N_("FileManager"), "FileManager", "folder", (char**) &SystemFileTools, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Utility or System - { N_("FileTools"), "FileTools", "folder", (char**) &UtilityorSystem, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network - { N_("FileTransfer"), "FileTransfer", "folder", (char**) &Network, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: System - { N_("Filesystem"), "Filesystem", "folder", (char**) &System, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office - { N_("Finance"), "Finance", "folder", (char**) &Office, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office - { N_("FlowChart"), "FlowChart", "folder", (char**) &Office, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Development - { N_("GUIDesigner"), "GUIDesigner", "folder", (char**) &Development, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("Game"), "Game", "folder", nullptr, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science - { N_("Geography"), "Geography", "folder", (char**) &EducationorScience, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science - { N_("Geology"), "Geology", "folder", (char**) &EducationorScience, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science - { N_("Geoscience"), "Geoscience", "folder", (char**) &EducationorScience, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("Graphics"), "Graphics", "folder", nullptr, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network or Audio - { N_("HamRadio"), "HamRadio", "folder", (char**) &NetworkorAudio, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Settings - { N_("HardwareSettings"), "HardwareSettings", "folder", (char**) &Settings, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science - { N_("History"), "History", "folder", (char**) &EducationorScience, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science - { N_("Humanities"), "Humanities", "folder", (char**) &EducationorScience, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Development - { N_("IDE"), "IDE", "folder", (char**) &Development, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network - { N_("IRCClient"), "IRCClient", "folder", (char**) &Network, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science - { N_("ImageProcessing"), "ImageProcessing", "folder", (char**) &EducationorScience, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network - { N_("InstantMessaging"), "InstantMessaging", "folder", (char**) &Network, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game - { N_("KidsGame"), "KidsGame", "folder", (char**) &Game, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science - { N_("Languages"), "Languages", "folder", (char**) &EducationorScience, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science - { N_("Literature"), "Literature", "folder", (char**) &EducationorScience, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game - { N_("LogicGame"), "LogicGame", "folder", (char**) &Game, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science or Utility - { N_("Maps"), "Maps", "folder", (char**) &EducationorScienceorUtility, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science - { N_("Math"), "Math", "folder", (char**) &EducationorScience, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science - { N_("MedicalSoftware"), "MedicalSoftware", "folder", (char**) &EducationorScience, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: AudioVideo;Audio - { N_("Midi"), "Midi", "folder", (char**) &AudioVideoAudio, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: AudioVideo;Audio - { N_("Mixer"), "Mixer", "folder", (char**) &AudioVideoAudio, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: System or Network - { N_("Monitor"), "Monitor", "folder", (char**) &SystemorNetwork, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("Motif"), "Motif", "folder", (char**) &ANY, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("Multimedia"), "Multimedia", "folder", nullptr, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: AudioVideo or Education - { N_("Music"), "Music", "folder", (char**) &AudioVideoorEducation, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("Network"), "Network", "folder", nullptr, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network - { N_("News"), "News", "folder", (char**) &Network, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education;Math or Science;Math - { N_("NumericalAnalysis"), "NumericalAnalysis", "folder", (char**) &EducationMathorScienceMath, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Graphics;Scanning - { N_("OCR"), "OCR", "folder", (char**) &GraphicsScanning, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("Office"), "Office", "folder", nullptr, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("Other"), "Other", "folder", nullptr, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network - { N_("P2P"), "P2P", "folder", (char**) &Network, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office - { N_("PDA"), "PDA", "folder", (char**) &Office, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Settings - { N_("PackageManager"), "PackageManager", "folder", (char**) &Settings, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education;ComputerScience or Science;ComputerScience - { N_("ParallelComputing"), "ParallelComputing", "folder", (char**) &EducationComputerScienceorScienceComputerScience, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Graphics or Office - { N_("Photography"), "Photography", "folder", (char**) &GraphicsorOffice, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science - { N_("Physics"), "Physics", "folder", (char**) &EducationorScience, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Audio or Video or AudioVideo - { N_("Player"), "Player", "folder", (char**) &AudioorVideoorAudioVideo, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office - { N_("Presentation"), "Presentation", "folder", (char**) &Office, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Settings;HardwareSettings - { N_("Printing"), "Printing", "folder", (char**) &SettingsHardwareSettings, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Development - { N_("Profiling"), "Profiling", "folder", (char**) &Development, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office or Development - { N_("ProjectManagement"), "ProjectManagement", "folder", (char**) &OfficeorDevelopment, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Graphics or Office - { N_("Publishing"), "Publishing", "folder", (char**) &GraphicsorOffice, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Graphics;2DGraphics - { N_("RasterGraphics"), "RasterGraphics", "folder", (char**) &Graphics2DGraphics, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Audio or Video or AudioVideo - { N_("Recorder"), "Recorder", "folder", (char**) &AudioorVideoorAudioVideo, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network - { N_("RemoteAccess"), "RemoteAccess", "folder", (char**) &Network, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Development - { N_("RevisionControl"), "RevisionControl", "folder", (char**) &Development, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science - { N_("Robotics"), "Robotics", "folder", (char**) &EducationorScience, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game - { N_("RolePlaying"), "RolePlaying", "folder", (char**) &Game, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Graphics - { N_("Scanning"), "Scanning", "folder", (char**) &Graphics, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("Science"), "Science", "folder", nullptr, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("Screensavers"), "Screensavers", "folder", nullptr, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Settings or System - { N_("Security"), "Security", "folder", (char**) &SettingsorSystem, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: AudioVideo;Audio - { N_("Sequencer"), "Sequencer", "folder", (char**) &AudioVideoAudio, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("Settings"), "Settings", "folder", nullptr, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game - { N_("Shooter"), "Shooter", "folder", (char**) &Game, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game - { N_("Simulation"), "Simulation", "folder", (char**) &Game, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science or Utility - { N_("Spirituality"), "Spirituality", "folder", (char**) &EducationorScienceorUtility, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science - { N_("Sports"), "Sports", "folder", (char**) &EducationorScience, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game - { N_("SportsGame"), "SportsGame", "folder", (char**) &Game, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office - { N_("Spreadsheet"), "Spreadsheet", "folder", (char**) &Office, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game - { N_("StrategyGame"), "StrategyGame", "folder", (char**) &Game, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("System"), "System", "folder", nullptr, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: AudioVideo;Video - { N_("TV"), "TV", "folder", (char**) &AudioVideoVideo, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network - { N_("Telephony"), "Telephony", "folder", (char**) &Network, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Utility - { N_("TelephonyTools"), "TelephonyTools", "folder", (char**) &Utility, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: System - { N_("TerminalEmulator"), "TerminalEmulator", "folder", (char**) &System, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Utility - { N_("TextEditor"), "TextEditor", "folder", (char**) &Utility, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Utility - { N_("TextTools"), "TextTools", "folder", (char**) &Utility, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Development - { N_("Translation"), "Translation", "folder", (char**) &Development, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: AudioVideo;Audio - { N_("Tuner"), "Tuner", "folder", (char**) &AudioVideoAudio, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("Utility"), "Utility", "folder", nullptr, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Graphics;2DGraphics - { N_("VectorGraphics"), "VectorGraphics", "folder", (char**) &Graphics2DGraphics, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("Video"), "Video", "folder", nullptr, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network - { N_("VideoConference"), "VideoConference", "folder", (char**) &Network, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Graphics or Office - { N_("Viewer"), "Viewer", "folder", (char**) &GraphicsorOffice, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. - { N_("WINE"), "WINE", "folder", nullptr, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network - { N_("WebBrowser"), "WebBrowser", "folder", (char**) &Network, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network or Development - { N_("WebDevelopment"), "WebDevelopment", "folder", (char**) &NetworkorDevelopment, 0, 0}, -// TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office - { N_("WordProcessor"), "WordProcessor", "folder", (char**) &Office} +#include + +using t_menu_path = std::initializer_list; +using t_menu_path_table = std::initializer_list; +using t_menu_path_table_list = std::initializer_list; + +#define MENU_DEPTH_MAX 3 + +constexpr t_menu_path_table_list valid_paths = { + + // menu locations of depth 3 + { + {"Compression", "Archiving", "Utility"}, + {"FileManager", "FileTools", "System"}, + {"Midi", "Audio", "AudioVideo"}, + {"Mixer", "Audio", "AudioVideo"}, + {"NumericalAnalysis", "Math", "Science"}, + {"NumericalAnalysis", "Math", "Education"}, + {"OCR", "Scanning", "Graphics"}, + {"ParallelComputing", "ComputerScience", "Science"}, + {"ParallelComputing", "ComputerScience", "Education"}, + {"Printing", "Settings", "HardwareSettings"}, + {"RasterGraphics", "2DGraphics", "Graphics"}, + {"Sequencer", "Audio", "AudioVideo"}, + {"TV", "Video", "AudioVideo"}, + {"Tuner", "Audio", "AudioVideo"}, + {"VectorGraphics", "2DGraphics", "Graphics"}, + }, + + // menu locations of depth 2 + { + {"2DGraphics", "Graphics"}, + {"3DGraphics", "Graphics"}, + {"Accessibility", "Settings"}, + {"Accessibility", "Utility"}, + {"ActionGame", "Game"}, + {"Additional Category", "Related Categories"}, + {"Adult", ""}, + {"AdventureGame", "Game"}, + {"Amusement", ""}, + {"ArcadeGame", "Game"}, + {"Archiving", "Utility"}, + {"Art", "Science"}, + {"Art", "Education"}, + {"Artificialtelligence", "Science"}, + {"Artificialtelligence", "Education"}, + {"Astronomy", "Science"}, + {"Astronomy", "Education"}, + {"AudioVideoEditing", "Audio"}, + {"AudioVideoEditing", "Video"}, + {"AudioVideoEditing", "AudioVideo"}, + {"Biology", "Science"}, + {"Biology", "Education"}, + {"BlocksGame", "Game"}, + {"BoardGame", "Game"}, + {"Building", "Development"}, + {"COSMIC", ""}, + {"Calculator", "Utility"}, + {"Calendar", "Office"}, + {"CardGame", "Game"}, + {"Chart", "Office"}, + {"Chat", "Network"}, + {"Chemistry", "Science"}, + {"Chemistry", "Education"}, + {"Clock", "Utility"}, + {"ComputerScience", "Science"}, + {"ComputerScience", "Education"}, + {"ConsoleOnly", ""}, + {"Construction", "Science"}, + {"Construction", "Education"}, + {"ContactManagement", "Office"}, + {"Core", ""}, + {"DDE", "Qt"}, + {"DataVisualization", "Science"}, + {"DataVisualization", "Education"}, + {"Database", "AudioVideo"}, + {"Database", "Development"}, + {"Database", "Office"}, + {"Debugger", "Development"}, + {"DesktopSettings", "Settings"}, + {"Dialup", "Network"}, + {"Dictionary", "TextTools"}, + {"Dictionary", "Office"}, + {"DiscBurning", "AudioVideo"}, + {"Documentation", ""}, + {"Economy", "Science"}, + {"Economy", "Education"}, + {"Electricity", "Science"}, + {"Electricity", "Education"}, + {"Electronics", ""}, + {"Email", "Network"}, + {"Email", "Office"}, + {"Emulator", "System"}, + {"Emulator", "Game"}, + {"Engineering", ""}, + {"Feed", "Network"}, + {"FileTools", "System"}, + {"FileTools", "Utility"}, + {"FileTransfer", "Network"}, + {"Filesystem", "System"}, + {"Finance", "Office"}, + {"FlowChart", "Office"}, + {"GNOME", "GTK"}, + {"GTK", ""}, + {"GUIDesigner", "Development"}, + {"Geography", "Science"}, + {"Geography", "Education"}, + {"Geology", "Science"}, + {"Geology", "Education"}, + {"Geoscience", "Science"}, + {"Geoscience", "Education"}, + {"HamRadio", "Audio"}, + {"HamRadio", "Network"}, + {"HardwareSettings", "Settings"}, + {"History", "Science"}, + {"History", "Education"}, + {"Humanities", "Science"}, + {"Humanities", "Education"}, + {"IDE", "Development"}, + {"IRCClient", "Network"}, + {"ImageProcessing", "Science"}, + {"ImageProcessing", "Education"}, + {"InstantMessaging", "Network"}, + {"Java", ""}, + {"KDE", "QT"}, + {"KidsGame", "Game"}, + {"Languages", "Science"}, + {"Languages", "Education"}, + {"Literature", "Science"}, + {"Literature", "Education"}, + {"LogicGame", "Game"}, + {"Maps", "Science"}, + {"Maps", "Education"}, + {"Maps", "Utility"}, + {"Math", "Science"}, + {"Math", "Education"}, + {"MedicalSoftware", "Science"}, + {"MedicalSoftware", "Education"}, + {"Monitor", "System"}, + {"Monitor", "Network"}, + {"Motif", ""}, + {"Music", "AudioVideo"}, + {"Music", "Education"}, + {"News", "Network"}, + {"P2P", "Network"}, + {"PDA", "Office"}, + {"PackageManager", "Settings"}, + {"Photography", "Graphics"}, + {"Photography", "Office"}, + {"Physics", "Science"}, + {"Physics", "Education"}, + {"Player", "Audio"}, + {"Player", "Video"}, + {"Player", "AudioVideo"}, + {"Presentation", "Office"}, + {"Profiling", "Development"}, + {"ProjectManagement", "Development"}, + {"ProjectManagement", "Office"}, + {"Publishing", "Graphics"}, + {"Publishing", "Office"}, + {"Qt", ""}, + {"Recorder", "Audio"}, + {"Recorder", "Video"}, + {"Recorder", "AudioVideo"}, + {"RemoteAccess", "Network"}, + {"RevisionControl", "Development"}, + {"Robotics", "Science"}, + {"Robotics", "Education"}, + {"RolePlaying", "Game"}, + {"Scanning", "Graphics"}, + {"Security", "Settings"}, + {"Security", "System"}, + {"Shooter", "Game"}, + {"Simulation", "Game"}, + {"Spirituality", "Science"}, + {"Spirituality", "Education"}, + {"Spirituality", "Utility"}, + {"Sports", "Science"}, + {"Sports", "Education"}, + {"SportsGame", "Game"}, + {"Spreadsheet", "Office"}, + {"StrategyGame", "Game"}, + {"Telephony", "Network"}, + {"TelephonyTools", "Utility"}, + {"TerminalEmulator", "System"}, + {"TextEditor", "Utility"}, + {"TextTools", "Utility"}, + {"Translation", "Development"}, + {"VideoConference", "Network"}, + {"Viewer", "Graphics"}, + {"Viewer", "Office"}, + {"WebBrowser", "Network"}, + {"WebDevelopment", "Development"}, + {"WebDevelopment", "Network"}, + {"WordProcessor", "Office"}, + {"XFCE", "GTK"}, + }, + + // menu locations of depth 1 + { + {"Accessibility"}, + {"Accessories"}, + {"Audio"}, + {"AudioVideo"}, + {"Development"}, + {"Editors"}, + {"Education"}, + {"Game"}, + {"Graphics"}, + {"Multimedia"}, + {"Network"}, + {"Office"}, + {"Science"}, + {"Screensavers"}, + {"Settings"}, + {"System"}, + {"Utility"}, + {"Video"}, + {"WINE"}, + }, }; -} + +#define SIZE_OF_MENU_TABLE 3 + +#endif // FDO_GEN_MENU_STRUCTURE_H From ab6af3fa8f439345e1f730f51e76be565d367383 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Wed, 25 Sep 2024 16:33:21 +0200 Subject: [PATCH 06/85] First working printing code after rewrite --- .clang-format | 274 +++++++++++++++++ src/fdomenu.cc | 777 +++++++++++++++++++++++++------------------------ 2 files changed, 669 insertions(+), 382 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..82d6780ef --- /dev/null +++ b/.clang-format @@ -0,0 +1,274 @@ +--- +Language: Cpp +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveAssignments: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: true +AlignConsecutiveBitFields: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveDeclarations: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveMacros: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveShortCaseStatements: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCaseArrows: false + AlignCaseColons: false +AlignConsecutiveTableGenBreakingDAGArgColons: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveTableGenCondOperatorColons: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveTableGenDefinitionColons: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: false +AlignEscapedNewlines: Right +AlignOperands: Align +AlignTrailingComments: + Kind: Always + OverEmptyLines: 0 +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowBreakBeforeNoexceptSpecifier: Never +AllowShortBlocksOnASingleLine: Never +AllowShortCaseExpressionOnASingleLine: true +AllowShortCaseLabelsOnASingleLine: false +AllowShortCompoundRequirementOnASingleLine: true +AllowShortEnumsOnASingleLine: true +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: true +BitFieldColonSpacing: Both +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterExternBlock: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakAdjacentStringLiterals: true +BreakAfterAttributes: Leave +BreakAfterJavaFieldAnnotations: false +BreakAfterReturnType: None +BreakArrays: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: Always +BreakBeforeBraces: Attach +BreakBeforeInlineASMColon: OnlyMultiline +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakFunctionDefinitionParameters: false +BreakInheritanceList: BeforeColon +BreakStringLiterals: true +BreakTemplateDeclarations: MultiLine +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: false +IndentExternBlock: AfterExternBlock +IndentGotoLabels: true +IndentPPDirectives: None +IndentRequiresClause: true +IndentWidth: 4 +IndentWrappedFunctionNames: false +InsertBraces: false +InsertNewlineAtEOF: false +InsertTrailingCommas: None +IntegerLiteralSeparator: + Binary: 0 + BinaryMinDigits: 0 + Decimal: 0 + DecimalMinDigits: 0 + Hex: 0 + HexMinDigits: 0 +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLines: + AtEndOfFile: false + AtStartOfBlock: true + AtStartOfFile: true +LambdaBodyIndentation: Signature +LineEnding: DeriveLF +MacroBlockBegin: '' +MacroBlockEnd: '' +MainIncludeChar: Quote +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 4 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PackConstructorInitializers: BinPack +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakScopeResolution: 500 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +PPIndentWidth: -1 +QualifierAlignment: Leave +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +RemoveParentheses: Leave +RemoveSemicolon: false +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SkipMacroDefinitionBody: false +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: LexicographicNumeric +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeJsonColon: false +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + AfterPlacementOperator: true + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInContainerLiterals: true +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParens: Never +SpacesInParensOptions: + ExceptDoubleParentheses: false + InCStyleCasts: false + InConditionalStatements: false + InEmptyParentheses: false + Other: false +SpacesInSquareBrackets: false +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TableGenBreakInsideDAGArg: DontBreak +TabWidth: 8 +UseTab: Never +VerilogBreakBetweenInstancePorts: true +WhitespaceSensitiveMacros: + - BOOST_PP_STRINGIZE + - CF_SWIFT_NAME + - NS_SWIFT_NAME + - PP_STRINGIZE + - STRINGIZE +... + diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 392196191..e603cb7d6 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -12,47 +12,49 @@ * 2015/02/05: Eduard Bloch * - initial version * 2018/08: - * - overhauled program design and menu construction code, added sub-category handling + * - overhauled program design and menu construction code, added sub-category + * handling */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif -#include "config.h" #include "base.h" -//#include "sysdep.h" -#include "intl.h" +#include "config.h" +// #include "sysdep.h" #include "appnames.h" +#include "intl.h" #include "ylocale.h" +#include #include #include -#include // does not matter, string from C++11 is enough -//#include +// #include #include -#include -#include -#include -#include -#include #include -#include -#include #include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include using namespace std; #include "fdospecgen.h" -char const* ApplicationName; +char const *ApplicationName; /* -* Certain parts borrowed from apt-cacher-ng by its autor, either from older branches (C++11 compatible) or development branch. -*/ + * Certain parts borrowed from apt-cacher-ng by its autor, either from older + * branches (C++11 compatible) or development branch. + */ #if 0 constexpr unsigned int str2int(const char* str, int h = 0) { @@ -84,28 +86,29 @@ inline void trimBack(std::string &s, const string_view junk=SPACECHARS) #define LEN_AND_CSTR(sz) sizeof(sz) - 1, sz #endif -#define startsWith(where, what) (0==(where).compare(0, (what).size(), (what))) -#define startsWithSz(where, what) (0==(where).compare(0, sizeof((what))-1, (what))) -#define endsWith(where, what) ((where).size()>=(what).size() && \ - 0==(where).compare((where).size()-(what).size(), (what).size(), (what))) -#define endsWithSzAr(where, what) ((where).size()>=(sizeof((what))-1) && \ - 0==(where).compare((where).size()-(sizeof((what))-1), (sizeof((what))-1), (what))) +#define startsWith(where, what) (0 == (where).compare(0, (what).size(), (what))) +#define startsWithSz(where, what) \ + (0 == (where).compare(0, sizeof((what)) - 1, (what))) +#define endsWith(where, what) \ + ((where).size() >= (what).size() && \ + 0 == (where).compare((where).size() - (what).size(), (what).size(), \ + (what))) +#define endsWithSzAr(where, what) \ + ((where).size() >= (sizeof((what)) - 1) && \ + 0 == (where).compare((where).size() - (sizeof((what)) - 1), \ + (sizeof((what)) - 1), (what))) /** * Basic base implementation of a reference-counted class */ -struct tLintRefcounted -{ -private: - size_t m_nRefCount = 0; -public: - inline void __inc_ref() noexcept - { - m_nRefCount++; - } - inline void __dec_ref() - { - if(--m_nRefCount == 0) +struct tLintRefcounted { + private: + size_t m_nRefCount = 0; + + public: + inline void __inc_ref() noexcept { m_nRefCount++; } + inline void __dec_ref() { + if (--m_nRefCount == 0) delete this; } virtual ~tLintRefcounted() {} @@ -115,156 +118,126 @@ struct tLintRefcounted /** * Lightweight intrusive smart pointer with ordinary reference counting */ -template -class lint_ptr -{ - T * m_ptr = nullptr; -public: - explicit lint_ptr() - { - } - /** - * @brief lint_ptr Captures the pointer and ensures that it's released when the refcount goes to zero, unless initialyTakeRef is set to false. - * If initialyTakeRef is false, the operation is asymmetric, i.e. one extra __dec_ref operation will happen in the end. - * - * @param rawPtr - * @param initialyTakeRef - */ - explicit lint_ptr(T *rawPtr, bool initialyTakeRef = true) : - m_ptr(rawPtr) - { - if(rawPtr && initialyTakeRef) - rawPtr->__inc_ref(); - } - T* construct() - { - reset(new T); - return m_ptr; - } - lint_ptr(const ::lint_ptr & orig) : - m_ptr(orig.m_ptr) - { - if(!m_ptr) return; - m_ptr->__inc_ref(); - } - lint_ptr(::lint_ptr && orig) - { - if (this == &orig) - return; - m_ptr = orig.m_ptr; - orig.m_ptr = nullptr; - } - inline ~lint_ptr() - { - if(!m_ptr) return; - m_ptr->__dec_ref(); - } - T* get() const - { - return m_ptr; - } - bool operator==(const T* raw) const - { - return get() == raw; - } - inline void reset(T *rawPtr) noexcept - { - if(rawPtr == m_ptr) // heh? - return; - reset(); - m_ptr = rawPtr; - if(rawPtr) - rawPtr->__inc_ref(); - } - inline void swap(lint_ptr& other) - { - std::swap(m_ptr, other.m_ptr); - } - inline void reset() noexcept - { - if(m_ptr) - m_ptr->__dec_ref(); - m_ptr = nullptr; - } - lint_ptr& operator=(const lint_ptr &other) - { - if(m_ptr == other.m_ptr) - return *this; - reset(other.m_ptr); - return *this; - } - lint_ptr& operator=(lint_ptr &&other) - { - if(m_ptr == other.m_ptr) - return *this; - - m_ptr = other.m_ptr; - other.m_ptr = nullptr; - return *this; - } - // pointer-like access options - explicit inline operator bool() const noexcept - { - return m_ptr; - } - inline T& operator*() const noexcept - { - return *m_ptr; - } - inline T* operator->() const noexcept - { - return m_ptr; - } - // pointer-like access options - inline bool operator<(const lint_ptr &vs) const noexcept - { - return m_ptr < vs.m_ptr; - } - // pointer-like access options - inline bool operator==(const lint_ptr &vs) const noexcept - { - return m_ptr == vs.m_ptr; - } - /** - * @brief release returns the pointer and makes this invalid while keeping the refcount - * @return Raw pointer - */ - T* release() noexcept - { - auto ret = m_ptr; - m_ptr = nullptr; - return ret; - } -}; +template class lint_ptr { + T *m_ptr = nullptr; + + public: + explicit lint_ptr() {} + /** + * @brief lint_ptr Captures the pointer and ensures that it's released when + * the refcount goes to zero, unless initialyTakeRef is set to false. If + * initialyTakeRef is false, the operation is asymmetric, i.e. one extra + * __dec_ref operation will happen in the end. + * + * @param rawPtr + * @param initialyTakeRef + */ + explicit lint_ptr(T *rawPtr, bool initialyTakeRef = true) : m_ptr(rawPtr) { + if (rawPtr && initialyTakeRef) + rawPtr->__inc_ref(); + } + T *construct() { + reset(new T); + return m_ptr; + } + lint_ptr(const ::lint_ptr &orig) : m_ptr(orig.m_ptr) { + if (!m_ptr) + return; + m_ptr->__inc_ref(); + } + lint_ptr(::lint_ptr &&orig) { + if (this == &orig) + return; + m_ptr = orig.m_ptr; + orig.m_ptr = nullptr; + } + inline ~lint_ptr() { + if (!m_ptr) + return; + m_ptr->__dec_ref(); + } + T *get() const { return m_ptr; } + bool operator==(const T *raw) const { return get() == raw; } + inline void reset(T *rawPtr) noexcept { + if (rawPtr == m_ptr) // heh? + return; + reset(); + m_ptr = rawPtr; + if (rawPtr) + rawPtr->__inc_ref(); + } + inline void swap(lint_ptr &other) { std::swap(m_ptr, other.m_ptr); } + inline void reset() noexcept { + if (m_ptr) + m_ptr->__dec_ref(); + m_ptr = nullptr; + } + lint_ptr &operator=(const lint_ptr &other) { + if (m_ptr == other.m_ptr) + return *this; + reset(other.m_ptr); + return *this; + } + lint_ptr &operator=(lint_ptr &&other) { + if (m_ptr == other.m_ptr) + return *this; + m_ptr = other.m_ptr; + other.m_ptr = nullptr; + return *this; + } + // pointer-like access options + explicit inline operator bool() const noexcept { return m_ptr; } + inline T &operator*() const noexcept { return *m_ptr; } + inline T *operator->() const noexcept { return m_ptr; } + // pointer-like access options + inline bool operator<(const lint_ptr &vs) const noexcept { + return m_ptr < vs.m_ptr; + } + // pointer-like access options + inline bool operator==(const lint_ptr &vs) const noexcept { + return m_ptr == vs.m_ptr; + } + /** + * @brief release returns the pointer and makes this invalid while keeping + * the refcount + * @return Raw pointer + */ + T *release() noexcept { + auto ret = m_ptr; + m_ptr = nullptr; + return ret; + } +}; /*! - * \brief Simple and convenient split function, outputs resulting tokens into a string vector. - * Operates on user-provided vector, with or without purging the previous contents. + * \brief Simple and convenient split function, outputs resulting tokens into a + * string vector. Operates on user-provided vector, with or without purging the + * previous contents. */ -vector & Tokenize(const string & in, const char *sep, - vector & inOutVec, bool bAppend = false, std::string::size_type nStartOffset = 0) -{ - if(!bAppend) - inOutVec.clear(); - - auto pos=nStartOffset, pos2=nStartOffset, oob=in.length(); - while (pos &Tokenize(const string &in, const char *sep, + vector &inOutVec, bool bAppend = false, + std::string::size_type nStartOffset = 0) { + if (!bAppend) + inOutVec.clear(); + + auto pos = nStartOffset, pos2 = nStartOffset, oob = in.length(); + while (pos < oob) { + pos = in.find_first_not_of(sep, pos); + if (pos == string::npos) // no more tokens + break; + pos2 = in.find_first_of(sep, pos); + if (pos2 == string::npos) // no more terminators, EOL + pos2 = oob; + inOutVec.emplace_back(in.substr(pos, pos2 - pos)); + pos = pos2 + 1; + } return inOutVec; } - -auto line_matcher = std::regex("^\\s*(Terminal|Type|Name|Exec|Icon|Categories)(\\[(..)\\])?\\s*=\\s*(.*){0,1}?\\s*$", std::regex_constants::ECMAScript); +auto line_matcher = std::regex("^\\s*(Terminal|Type|Name|Exec|Icon|Categories)(" + "\\[(..)\\])?\\s*=\\s*(.*){0,1}?\\s*$", + std::regex_constants::ECMAScript); struct DesktopFile : public tLintRefcounted { bool Terminal = false, IsApp = true; @@ -272,70 +245,78 @@ struct DesktopFile : public tLintRefcounted { vector Categories; /// Translate with built-in l10n if needed - string& GetTranslatedName() { + string &GetTranslatedName() { if (NameLoc.empty()) { NameLoc = gettext(Name.c_str()); } return NameLoc; } + string GetCommand() { + #warning XXX: Find simple solution for terminal calling and launching with format strings + return Exec; + } DesktopFile(string filePath, const string &lang) { + //cout << "filterlang: " << lang < load(const string& path, const string& lang) { - try - { - auto ret = new DesktopFile(path, lang); - return lint_ptr(ret); - } - catch(const std::exception&) - { - return lint_ptr(); + static lint_ptr load(const string &path, const string &lang) { + try { + auto ret = new DesktopFile(path, lang); + return lint_ptr(ret); + } catch (const std::exception &) { + return lint_ptr(); + } } -} - }; - #if 0 #ifndef LPCSTR // mind the MFC @@ -389,12 +371,12 @@ struct DesktopFile : public tLintRefcounted { typedef const char* LPCSTR; #endif +#include "ycollections.h" +#include #include -#include #include #include -#include -#include "ycollections.h" +#include #endif // program options @@ -411,29 +393,25 @@ bool match_in_section_only = false; auto substr_filter = ""; auto substr_filter_nocase = ""; auto flat_sep = " / "; -char* terminal_command; -char* terminal_option; +char *terminal_command; +char *terminal_option; -template -struct auto_raii { +template struct auto_raii { T m_p; - auto_raii(T xp) : - m_p(xp) { - } + auto_raii(T xp) : m_p(xp) {} ~auto_raii() { if (m_p) TFreeFunc(m_p); } }; - -const char* rtls[] = { - "ar", // arabic - "fa", // farsi - "he", // hebrew - "ps", // pashto - "sd", // sindhi - "ur", // urdu +const char *rtls[] = { + "ar", // arabic + "fa", // farsi + "he", // hebrew + "ps", // pashto + "sd", // sindhi + "ur", // urdu }; #if 0 @@ -558,12 +536,12 @@ class tDesktopInfo { auto use_direct_call = ret.find_first_of(":%") == string::npos; auto bForTerminal = false; - #if GLIB_VERSION_CUR_STABLE >= G_ENCODE_VERSION(2, 36) +#if GLIB_VERSION_CUR_STABLE >= G_ENCODE_VERSION(2, 36) bForTerminal = g_desktop_app_info_get_boolean(pInfo, "Terminal"); - #else +#else // cannot check terminal property, callback is as safe bet use_direct_call = false; - #endif +#endif if (use_direct_call && !bForTerminal) // best case return ret; @@ -745,7 +723,7 @@ class tListMeta { tListMeta* lookup_category(const std::string& key) { - #ifdef OLD_IMP +#ifdef OLD_IMP auto it = meta_lookup_data.find(key); if (it == meta_lookup_data.end()) @@ -758,9 +736,9 @@ tListMeta* lookup_category(const std::string& key) //printf("Got title? %s -> %s\n", ret->key, ret->title); #endif return ret; - #else +#else return nullptr; - #endif +#endif } std::stack flat_pfxes; @@ -1038,7 +1016,7 @@ tListMeta::tListMeta(const tDesktopInfo& dinfo) { title = key = Elvis(dinfo.get_name(), ""); } - #ifdef OLD_IMP +#ifdef OLD_IMP t_menu_node root(tListMeta::make_dummy()); #endif @@ -1095,12 +1073,12 @@ struct t_menu_node_app : t_menu_node } bool bForTerminal = false; - #if GLIB_VERSION_CUR_STABLE >= G_ENCODE_VERSION(2, 36) +#if GLIB_VERSION_CUR_STABLE >= G_ENCODE_VERSION(2, 36) bForTerminal = g_desktop_app_info_get_boolean(dinfo.pInfo, "Terminal"); - #else +#else // cannot check terminal property, callback is as safe bet bUseSimplifiedCmd = false; - #endif +#endif if (bUseSimplifiedCmd && !bForTerminal) // best case progCmd = cmdMod; @@ -1186,7 +1164,7 @@ void pickup_folder_info(LPCSTR szDesktopFile) { if (!pCat) return; - #ifdef OLD_IMP +#ifdef OLD_IMP if (pCat->load_state_icon < tListMeta::SYSTEM_ICON) { LPCSTR icon_name = g_key_file_get_string (kf, "Desktop Entry", "Icon", nullptr); @@ -1223,7 +1201,7 @@ void pickup_folder_info(LPCSTR szDesktopFile) { t->load_state_icon = tListMeta::FALLBACK_ICON; } } - #endif +#endif } @@ -1282,7 +1260,8 @@ bool launch(LPCSTR dfile, char** argv, int argc) { GDesktopAppInfo *pInfo = g_desktop_app_info_new_from_filename(dfile); if (!pInfo) return false; -#if 0 // g_file_get_uri crashes, no idea why, even enforcing file prefix doesn't help +#if 0 // g_file_get_uri crashes, no idea why, even enforcing file prefix doesn't + // help if (argc > 0) { GList* parms = NULL; @@ -1336,7 +1315,6 @@ static void init() { break; } - #ifdef DEBUG_xxx void dbgPrint(const gchar *msg) { @@ -1347,7 +1325,7 @@ void dbgPrint(const gchar *msg) int main(int argc, char** argv) { ApplicationName = my_basename(argv[0]); -#if !GLIB_CHECK_VERSION(2,36,0) +#if !GLIB_CHECK_VERSION(2, 36, 0) g_type_init(); #endif @@ -1465,104 +1443,118 @@ int main(int argc, char** argv) { } #else -#include #include #include #include +#include - -typedef void (*tFuncInsertInfo)(const string& absPath, intptr_t any); +typedef void (*tFuncInsertInfo)(const string &absPath, intptr_t any); class FsScan { - private: + private: std::set> reclog; - function cb; + function cb; string sFileNameExtFilter; - public: + public: FsScan(decltype(FsScan::cb) cb, const string &sFileNameExtFilter = "") { this->cb = cb; this->sFileNameExtFilter = sFileNameExtFilter; } - void scan(const string &sStartdir) { - proc_dir_rec(sStartdir); - } -private: -void proc_dir_rec(const string &path) { - auto pdir = opendir(path.c_str()); - if (!pdir) - return; - auto_raii dircloser(pdir); - auto fddir(dirfd(pdir)); + void scan(const string &sStartdir) { proc_dir_rec(sStartdir); } - //const gchar *szFilename(nullptr); - dirent *pent; - struct stat stbuf; + private: + void proc_dir_rec(const string &path) { + auto pdir = opendir(path.c_str()); + if (!pdir) + return; + auto_raii dircloser(pdir); + auto fddir(dirfd(pdir)); - while (nullptr != (pent = readdir(pdir))) { - if (pent->d_name[0] == '.') - continue; - pent->d_name[255] = 0; - string fname(pent->d_name); - if (!sFileNameExtFilter.empty() && !endsWith(fname, sFileNameExtFilter)) - continue; - if (fstatat(fddir, fname.c_str(), &stbuf, 0)) - continue; - if (S_ISDIR(stbuf.st_mode)) { - // link loop detection - auto prev = make_pair(stbuf.st_ino, stbuf.st_dev); - auto hint = reclog.insert(prev); - if (hint.second) { // we added a new one, otherwise do not descend - proc_dir_rec(path + "/" + fname); - reclog.erase(hint.first); + // const gchar *szFilename(nullptr); + dirent *pent; + struct stat stbuf; + + while (nullptr != (pent = readdir(pdir))) { + if (pent->d_name[0] == '.') + continue; + pent->d_name[255] = 0; + string fname(pent->d_name); + if (!sFileNameExtFilter.empty() && + !endsWith(fname, sFileNameExtFilter)) + continue; + if (fstatat(fddir, fname.c_str(), &stbuf, 0)) + continue; + if (S_ISDIR(stbuf.st_mode)) { + // link loop detection + auto prev = make_pair(stbuf.st_ino, stbuf.st_dev); + auto hint = reclog.insert(prev); + if (hint.second) { // we added a new one, otherwise do not + // descend + proc_dir_rec(path + "/" + fname); + reclog.erase(hint.first); + } } - } - if (!S_ISREG(stbuf.st_mode)) - continue; + if (!S_ISREG(stbuf.st_mode)) + continue; - cb(path + "/" + fname); + cb(path + "/" + fname); + } } -} - }; static void help(bool to_stderr, int xit) { - (to_stderr ? cerr : cout) << - "USAGE: icewm-menu-fdo [OPTIONS] [FILENAME]\n" - "OPTIONS:\n" - "-g, --generic\tInclude GenericName in parentheses of progs\n" - "-o, --output=FILE\tWrite the output to FILE\n" - "-t, --terminal=NAME\tUse NAME for a terminal that has '-e'\n" - "--seps \tPrint separators before and after contents\n" - "--sep-before\tPrint separator before the contents\n" - "--sep-after\tPrint separator only after contents\n" - "--no-sep-others\tNo separation of the 'Others' menu point\n" - "--no-sub-cats\tNo additional subcategories, just one level of menues\n" - "--flat\tDisplay all apps in one layer with category hints\n" - "--flat-sep STR\tCategory separator string used in flat mode (default: ' / ')\n" - "--match PAT\tDisplay only apps with title containing PAT\n" - "--imatch PAT\tLike --match but ignores the letter case\n" - "--match-sec\tApply --match or --imatch to apps AND sections\n" - "--match-osec\tApply --match or --imatch only to sections\n" - "FILENAME\tAny .desktop file to launch its application Exec command\n" - "This program also listens to environment variables defined by\n" - "the XDG Base Directory Specification:\n" - "XDG_DATA_HOME=" << Elvis(getenv("XDG_DATA_HOME"), (char*)"") << "\n" - "XDG_DATA_DIRS=" << Elvis(getenv("XDG_DATA_DIRS"), (char*)"") << endl; + (to_stderr ? cerr : cout) + << "USAGE: icewm-menu-fdo [OPTIONS] [FILENAME]\n" + "OPTIONS:\n" + "-g, --generic\tInclude GenericName in parentheses of progs\n" + "-o, --output=FILE\tWrite the output to FILE\n" + "-t, --terminal=NAME\tUse NAME for a terminal that has '-e'\n" + "--seps \tPrint separators before and after contents\n" + "--sep-before\tPrint separator before the contents\n" + "--sep-after\tPrint separator only after contents\n" + "--no-sep-others\tNo separation of the 'Others' menu point\n" + "--no-sub-cats\tNo additional subcategories, just one level of " + "menues\n" + "--flat\tDisplay all apps in one layer with category hints\n" + "--flat-sep STR\tCategory separator string used in flat mode " + "(default: ' / ')\n" + "--match PAT\tDisplay only apps with title containing PAT\n" + "--imatch PAT\tLike --match but ignores the letter case\n" + "--match-sec\tApply --match or --imatch to apps AND sections\n" + "--match-osec\tApply --match or --imatch only to sections\n" + "FILENAME\tAny .desktop file to launch its application Exec " + "command\n" + "This program also listens to environment variables defined by\n" + "the XDG Base Directory Specification:\n" + "XDG_DATA_HOME=" + << Elvis(getenv("XDG_DATA_HOME"), (char *)"") + << "\n" + "XDG_DATA_DIRS=" + << Elvis(getenv("XDG_DATA_DIRS"), (char *)"") << endl; exit(xit); } +/** + * The own menu deco info is not part of this class. + * It's fetched on-demand with a supplied resolver function. + */ struct tMenuNode { void sink_in(lint_ptr df); - map submenues; - map apps; - unordered_set dont_add_mark; + void print(std::ostream &prt_strm, const function(const string&)> &menuDecoResolver); + void collect_menu_names(const function &callback); + +protected: + map submenues; + // using a map instead of set+logics adds a minor memory overhead but allows simple duplicate detection (adding user's version first) + map apps; + unordered_set dont_add_mark; }; -int main(int argc, char** argv) { +int main(int argc, char **argv) { // basic framework and environment initialization ApplicationName = my_basename(argv[0]); @@ -1571,11 +1563,10 @@ int main(int argc, char** argv) { setlocale(LC_ALL, ""); auto msglang = YLocale::getCheckedExplicitLocale(false); - right_to_left = msglang && std::any_of(rtls, rtls + ACOUNT(rtls), - [&](const char* rtl) { + right_to_left = + msglang && std::any_of(rtls, rtls + ACOUNT(rtls), [&](const char *rtl) { return rtl[0] == msglang[0] && rtl[1] == msglang[1]; - } - ); + }); bindtextdomain(PACKAGE, LOCDIR); textdomain(PACKAGE); #endif @@ -1601,17 +1592,16 @@ int main(int argc, char** argv) { if (sysshare && !*sysshare) Tokenize(sysshare, ":", sharedirs, true); else - sharedirs.push_back("/usr/local/share"), sharedirs.push_back("/usr/share"); + sharedirs.push_back("/usr/local/share"), + sharedirs.push_back("/usr/share"); for (auto pArg = argv + 1; pArg < argv + argc; ++pArg) { if (is_version_switch(*pArg)) { - cout << "icewm-menu-fdo " - VERSION - ", Copyright 2015-2024 Eduard Bloch, 2017-2023 Bert Gijsbers." - <();}); + /* cout << "lang: " << shortLang << endl; int ret = 0; @@ -1693,38 +1685,59 @@ int main(int argc, char** argv) { } #endif -void tMenuNode::sink_in(lint_ptr pDf) -{ - auto& df=*pDf; +void tMenuNode::sink_in(lint_ptr pDf) { + auto &df = *pDf; dont_add_mark.clear(); bool bFoundCategories = false; - auto add_sub_menues = [&](const t_menu_path& mp) { - tMenuNode* cur = this; - for (auto it = std::rbegin(mp); it != std::rend(mp); ++it) { - cerr << "adding submenu: " <<*it <submenues[*it]; } return cur; }; - for(const auto& cat: df.Categories) { + for (const auto &cat : df.Categories) { cerr << "where does it fit? " << cat << endl; - t_menu_path refval = {df.Name.c_str()}; - static auto comper = [](const t_menu_path& a, const t_menu_path& b) { - cerr << "left: " << *a.begin() << " vs. right: " << *b.begin() << endl; - return strcmp(*a.begin(), *b.begin()) < 0; - }; - for(const auto& w: valid_paths) { - auto rng = std::equal_range(w.begin(), w.end(), refval, comper); - for(auto it = rng.first; it != rng.second; ++it) { - auto&tgt = * add_sub_menues(*it); + t_menu_path refval = {cat.c_str()}; + static auto comper = [](const t_menu_path &a, const t_menu_path &b) { + // cerr << "left: " << *a.begin() << " vs. right: " << *b.begin() << + // endl; + return strcmp(*a.begin(), *b.begin()) < 0; + }; + for (const auto &w : valid_paths) { + // cerr << "try paths: " << (uintptr_t)&w << endl; + auto rng = std::equal_range(w.begin(), w.end(), refval, comper); + for (auto it = rng.first; it != rng.second; ++it) { + auto &tgt = *add_sub_menues(*it); + tgt.apps.emplace(df.Name, df); + } } - } +} + +static string ICON_FOLDER("folder"); +string indent_hint(""); +void tMenuNode::print(std::ostream &prt_strm, const function(const string&)> &menuDecoResolver) { + for(auto& m: this->submenues) { + auto& name = m.first; + auto deco = menuDecoResolver(name); + prt_strm << indent_hint << "menu \"" << (deco ? deco->GetTranslatedName() : name) << "\" " << (deco ? deco->Icon : ICON_FOLDER) << " {\n"; + + indent_hint += "\t"; + m.second.print(prt_strm, menuDecoResolver); + indent_hint.erase(indent_hint.size()-1); + + prt_strm << indent_hint << "}\n"; } - + for(auto& p: this->apps) { + auto& pi=p.second; + prt_strm << indent_hint << "prog \"" << pi.GetTranslatedName() << "\" " << pi.Icon << " " << pi.GetCommand() << "\n"; + } + } // vim: set sw=4 ts=4 et: From 89feeb022e6de696eaa96e2c44080e8544f8b490 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Wed, 25 Sep 2024 18:25:47 +0200 Subject: [PATCH 07/85] Fixup some of the expansion patterns in the exec string --- src/fdomenu.cc | 125 ++++++++++++++++++++++--------------------------- 1 file changed, 56 insertions(+), 69 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index e603cb7d6..abf6c9d5a 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -235,13 +235,25 @@ vector &Tokenize(const string &in, const char *sep, return inOutVec; } -auto line_matcher = std::regex("^\\s*(Terminal|Type|Name|Exec|Icon|Categories)(" +void replace_all(std::string& str, const std::string& from, const std::string& to) { + if (from.empty()) { + return; + } + + size_t start_pos = 0; + while ((start_pos = str.find(from, start_pos)) != std::string::npos) { + str.replace(start_pos, from.length(), to); + start_pos += to.length(); + } +} + +auto line_matcher = std::regex("^\\s*(Terminal|Type|Name|Exec|TryExec|Icon|Categories|NoDisplay)(" "\\[(..)\\])?\\s*=\\s*(.*){0,1}?\\s*$", std::regex_constants::ECMAScript); struct DesktopFile : public tLintRefcounted { - bool Terminal = false, IsApp = true; - string Name, NameLoc, Exec, Icon; + bool Terminal = false, IsApp = true, NoDisplay = false; + string Name, NameLoc, Exec, TryExec, Icon; vector Categories; /// Translate with built-in l10n if needed @@ -253,7 +265,15 @@ struct DesktopFile : public tLintRefcounted { } string GetCommand() { - #warning XXX: Find simple solution for terminal calling and launching with format strings + // let's try whether the command line is toxic, expecting stuff from https://specifications.freedesktop.org/desktop-entry-spec/latest/exec-variables.html + if (string::npos == Exec.find('%')) + return Exec; + if (!TryExec.empty()) + return (Exec = TryExec); // copy over so we stick to it in case of later calls + for(const auto& bad: {"%F", "%U", "%f", "%u"}) + replace_all(Exec, bad, ""); + replace_all(Exec, "%c", Name); + replace_all(Exec, "%i", Icon); return Exec; } DesktopFile(string filePath, const string &lang) { @@ -262,6 +282,7 @@ struct DesktopFile : public tLintRefcounted { dfile.open(filePath); string line; std::smatch m; + bool reading = false; while (dfile) { line.clear(); std::getline(dfile, line); @@ -270,6 +291,16 @@ struct DesktopFile : public tLintRefcounted { break; continue; } + if (startsWithSz(line, "[Desktop ")) { + if (startsWithSz(line, "[Desktop Entry")) { + reading = true; + } + else if (reading) // finished with desktop entry contents, exit + break; + } + if (!reading) + continue; + std::regex_search(line, m, line_matcher); if (m.empty()) continue; @@ -280,12 +311,16 @@ struct DesktopFile : public tLintRefcounted { if (m[1] == "Terminal") Terminal = m[4].compare("true") == 0; + else if (m[1] == "NoDisplay") + NoDisplay = m[4].compare("true") == 0; else if (m[1] == "Icon") Icon = m[4]; else if (m[1] == "Categories") { Tokenize(m[4], ";", Categories); } else if (m[1] == "Exec") { Exec = m[4]; + } else if (m[1] == "TryExec") { + TryExec = m[4]; } else if (m[1] == "Type") { if (m[4] == "Application") IsApp = true; @@ -300,67 +335,18 @@ struct DesktopFile : public tLintRefcounted { else Name = m[4]; } - -#if 0 - trimFront(line); - if (line[0] == '#' || line[0] == '[') - continue; - - unsigned matchlen = 0; -#define match(key) \ - { \ - if (startsWithSz(line, key)) { \ - matchlen = sizeof(key) - 1; \ - } \ - } -#define find_val_or_continue() \ - auto p = line.find_first_not_of(KVJUNK, matchlen); \ - if (p == string::npos) \ - continue; - match("Terminal") - if (matchlen) { - find_val_or_continue() - Terminal = line[p] == 't'; - continue; - } - match("Type") - if (matchlen) { - find_val_or_continue() - if (0 == line.compare(p, LEN_AND_CSTR("Application"))) - IsApp = false; - else if (0 == line.compare(p, LEN_AND_CSTR("Directory"))) - IsApp = true; - continue; - } - -#define grab(x, y) \ - match(x); \ - if (matchlen) { \ - find_val_or_continue(); \ - y = line.erase(p); \ - continue; \ - } - grab("Categories", Categories) - grab("Icon", Icon) - grab("Exec", Exec) - - match("Name") - if (matchlen) { - line.erase(matchlen); - trimFront(line); -#error murks - } -#endif } } - static lint_ptr load(const string &path, const string &lang) { + static lint_ptr load_visible(const string &path, const string &lang) { + auto ret = lint_ptr(); try { - auto ret = new DesktopFile(path, lang); - return lint_ptr(ret); + ret.reset(new DesktopFile(path, lang)); + if (ret->NoDisplay) + ret.reset(); } catch (const std::exception &) { - return lint_ptr(); } + return ret; } }; @@ -414,6 +400,15 @@ const char *rtls[] = { "ur", // urdu }; +struct tLessOp4Localized { + std::locale loc; // default locale + const std::collate& coll = std::use_facet >(loc); + bool operator() (const std::string& a, const std::string& b) { + return coll.compare (a.data(), a.data() + a.size(), + b.data(), b.data()+b.size()) < 0; + } +} locStringComper; + #if 0 typedef auto_raii auto_gfree; typedef auto_raii auto_gunref; @@ -439,14 +434,6 @@ struct tLtUtf8 { } } lessThanUtf8; */ -struct tLessOp4Localized { - std::locale loc; // default locale - const std::collate& coll = std::use_facet >(loc); - bool operator() (const std::string& a, const std::string& b) { - return coll.compare (a.data(), a.data() + a.size(), - b.data(), b.data()+b.size()) < 0; - } -} locStringComper; class tDesktopInfo; typedef YVec tCharVec; @@ -1658,7 +1645,7 @@ int main(int argc, char **argv) { #ifdef DEBUG cerr << "reading: " << fPath << endl; #endif - auto df = DesktopFile::load(fPath, shortLang); + auto df = DesktopFile::load_visible(fPath, shortLang); if (df) root.sink_in(df); }, @@ -1729,7 +1716,7 @@ void tMenuNode::print(std::ostream &prt_strm, const function Date: Wed, 25 Sep 2024 19:03:00 +0200 Subject: [PATCH 08/85] Cleanup, fix Other menu population --- src/fdomenu.cc | 1098 +----------------------------------------------- 1 file changed, 23 insertions(+), 1075 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index abf6c9d5a..8955d6479 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -45,6 +45,13 @@ #include #include + +#include +#include +#include +#include + + using namespace std; #include "fdospecgen.h" @@ -55,36 +62,6 @@ char const *ApplicationName; * Certain parts borrowed from apt-cacher-ng by its autor, either from older * branches (C++11 compatible) or development branch. */ -#if 0 -constexpr unsigned int str2int(const char* str, int h = 0) -{ - //return strhash(str); - // same as pure constexpr - return !str[h] ? 5381 : (str2int(str, h+1) * 33) ^ str[h]; -} - -#define SPACECHARS " \f\n\r\t\v" -#define KVJUNK SPACECHARS "[]=" - -inline void trimFront(std::string &s, const char* junk = SPACECHARS, string::size_type start=0) -{ - auto pos = s.find_first_not_of(junk, start); - if(pos == std::string::npos) - s.clear(); - else if(pos>0) - s.erase(0, pos); -} -inline void trimBack(std::string &s, const string_view junk=SPACECHARS) -{ - auto pos = s.find_last_not_of(junk); - if(pos == std::string::npos) - s.clear(); - else if(pos>0) - s.erase(pos+1); -} -#define CSTR_AND_LEN(sz) sz, sizeof(sz) - 1 -#define LEN_AND_CSTR(sz) sizeof(sz) - 1, sz -#endif #define startsWith(where, what) (0 == (where).compare(0, (what).size(), (what))) #define startsWithSz(where, what) \ @@ -409,1032 +386,6 @@ struct tLessOp4Localized { } } locStringComper; -#if 0 -typedef auto_raii auto_gfree; -typedef auto_raii auto_gunref; - -auto cstr_deleter = [](char* ptr) -{ - free((void*) ptr); -}; -using cstr_unique = std::unique_ptr; - -/* -static int cmpUtf8(const void *p1, const void *p2) { - return g_utf8_collate((LPCSTR ) p1, (LPCSTR ) p2); -} -*/ - -/* -struct tLtUtf8 { - bool operator() (const std::string& a, const std::string& b) { - //return g_utf8_collate(a.c_str(), b.c_str()) < 0; - //static auto& f = std::use_facet>(std::locale::classic); - - } -} lessThanUtf8; -*/ - -class tDesktopInfo; -typedef YVec tCharVec; -tCharVec sys_folders, home_folders; -std::array sys_home_folders = { &sys_folders, &home_folders }; -std::array home_sys_folders = { &home_folders, &sys_folders }; - - -char const * const par_sec_dummy[] = { nullptr }; - -void decorate_and_print(); - - -// little adapter class to extract information we get from desktop files using GLib methods -class tDesktopInfo { - GDesktopAppInfo *pInfo = nullptr; - mutable std::string found_name; -public: - tDesktopInfo(LPCSTR szFileName) { - pInfo = g_desktop_app_info_new_from_filename(szFileName); - if (!pInfo) - return; - - // tear down if not permitted - if (!g_app_info_should_show(*this)) { - g_object_unref(pInfo); - pInfo = nullptr; - } - found_name = g_app_info_get_display_name((GAppInfo*) pInfo); - if (found_name.empty()) - found_name = g_desktop_app_info_get_generic_name(pInfo); - } - - inline operator GAppInfo*() { - return (GAppInfo*) pInfo; - } - - inline operator GDesktopAppInfo*() { - return pInfo; - } - - inline operator bool() { - return pInfo; - } - - //~tDesktopInfo() { - // XXX: call g_free on pInfo? free on d_file? - //} - - const std::string& get_name() const { - return found_name; - } - - bool operator<(const tDesktopInfo& other) const { - return locStringComper.operator()(get_name(), other.get_name()); - } - - char * get_icon_path() const { - auto pIcon = g_app_info_get_icon((GAppInfo*) pInfo); - auto_gunref free_icon((GObject*) pIcon); - return pIcon ? g_icon_to_string(pIcon) : nullptr; - } - - // split tokens into a list, to be cleared by g_strfreev - gchar** get_cat_tokens() { - - LPCSTR pCats = g_desktop_app_info_get_categories(pInfo); - if (!pCats) - pCats = "Other"; - if (0 == strncmp(pCats, "X-", 2)) - return (gchar**) malloc(0); - - return g_strsplit(pCats, ";", -1); - } - - std::string get_launch_cmd() { - LPCSTR cmdraw = g_app_info_get_commandline((GAppInfo*) pInfo); - if (!cmdraw || !*cmdraw) - return "-"; - using namespace std; - string ret(cmdraw); - auto p = ret.find_first_not_of(" \f\n\r\t\v"); - if (p != string::npos) - ret = ret.substr(p); - - // detect URLs and expansion patterns which wouldn't work with plain exec - auto use_direct_call = ret.find_first_of(":%") == string::npos; - - auto bForTerminal = false; -#if GLIB_VERSION_CUR_STABLE >= G_ENCODE_VERSION(2, 36) - bForTerminal = g_desktop_app_info_get_boolean(pInfo, "Terminal"); -#else - // cannot check terminal property, callback is as safe bet - use_direct_call = false; -#endif - - if (use_direct_call && !bForTerminal) // best case - return ret; - - if (bForTerminal && nonempty(terminal_command)) - return std::string(terminal_command) + " -e " + ret; - - // not simple command or needs a terminal started via launcher callback, or both - return std::string(ApplicationName) + " \"" + g_desktop_app_info_get_filename(pInfo) + "\""; - } -}; - -struct tMenuAnchor { - // list of application elements, ordered by the translated names - std::set translated_apps; - bool is_localized_builtin = false; - bool is_localized_system = false; - std::string icon_name = "folder"; - - static tMenuAnchor& find_menu_anchor(tDesktopInfo& dinfo); - void add(tDesktopInfo&& app) { translated_apps.emplace(std::move(app)); } -}; - -// helper to collect everything later -//struct tMenuAnchorKey { -// std::array levels = {0, 0, 0, 0}; -//}; - -using tMenuAnchorKey = std::array; - -// all pointer ordered which is okay, we operate on static entries -std::unordered_map all_content; -std::unordered_set seen_cats; -tMenuAnchor garbage_bin; - -tMenuAnchor& setup_anchor(tMenuAnchorKey key) { - for(auto x: key) if(x) seen_cats.emplace(x); - return all_content[key]; -} -/* -tMenuAnchor& setup_anchor(LPCSTR main_cat, LPCSTR sub_cat = nullptr, - LPCSTR sub_sub_cat = nullptr, - LPCSTR sub_sub_sub_cat = nullptr) { -return setup_anchor({main_cat, sub_cat, sub_sub_cat, sub_sub_sub_cat}); -} -*/ -LPCSTR dig_key(tMenuAnchorKey& key, LPCSTR prev_key, unsigned depth) { - - - - spec::mapping wanted(scat, nullptr, nullptr); - auto from_to = equal_range(spec::subcat_to_maincat, spec::subcat_to_maincat + ACOUNT(spec::subcat_to_maincat), - wanted, - [](const spec::mapping &a, const spec::mapping &b) { return strcmp(get<0>(a), get<0>(b)) < 0; } ); - - - depth++; - if(depth >= key.size()) - return; - key[depth] = dig_key(key, depth); -} - -tMenuAnchor& tMenuAnchor::find_menu_anchor(tDesktopInfo& dinfo) { - - LPCSTR pCats = g_desktop_app_info_get_categories(dinfo); - - if (!pCats) - pCats = "Other"; - if (0 == strncmp(pCats, "X-", 2)) - return garbage_bin; - - auto ppCats = dinfo.get_cat_tokens(); - if (!ppCats) - return garbage_bin; - - // Pigeonholing roughly by guessed menu structure - using namespace std; - static vector mcats, scats; - mcats.clear(); - scats.clear(); - - for(auto p = *ppCats; *p; p++) { - auto endex = spec::mcat::sall + ACOUNT(spec::mcat::sall); - auto is_mcat = binary_search(spec::mcat::sall, endex, - [](LPCSTR a, LPCSTR b) { return strcmp(a, b) < 0; } ); - (is_mcat ? mcats : scats).push_back(p); - } - - auto endex = spec::subcat_to_maincat + ACOUNT(spec::subcat_to_maincat); - bool found_subcat = false; - for(auto &mcat: mcats) { - for (auto &scat: scats) { - spec::mapping wanted(scat, nullptr, nullptr); - auto from_to = equal_range(spec::subcat_to_maincat, endex, wanted, - [](const spec::mapping &a, const spec::mapping &b) { return strcmp(get<0>(a), get<0>(b)) < 0; } ); - if (from_to.first == endex) - continue; - found_subcat = true; - - for(auto it = from_to.first; it != from_to.second; ++it) { - auto mc = get<0>(*it); - auto sc = get<1>(*it); - auto altsc = get<2>(*it); - if (mc) { - // perfect match, fast path - setup_anchor({mc, sc, 0, 0}).add(move(dinfo)); - } - else { - tMenuAnchorKey key = {} - for(unsigned i = 0; i < 4; ++i) { - - } - } - } - } - } - - - g_strfreev(ppCats); -} - - -struct tStaticMenuDescription { - LPCSTR key, icon; - const char ** parent_sec; -}; - -// shim class which describes the Menu related attributes, which can be fetched from static data or adjusted with localized or additional things from filesystem -class tListMeta { - LPCSTR title = nullptr, icon = nullptr, key = nullptr; - tStaticMenuDescription *builtin_data = nullptr; - tListMeta() {} - /* - enum eLoadFlags :char { - NONE = 0, - DEFAULT_TRANSLATED = 1, - SYSTEM_TRANSLATED = 2, - DEFAULT_ICON = 4, - FALLBACK_ICON = 8, - SYSTEM_ICON = 16, - }; - short load_state_icon, load_state_title; -*/ - - std::unordered_map meta_lookup_data; - std::unordered_map known_directory_files; - -public: - tListMeta(const tDesktopInfo&); - static tListMeta make_dummy() { return tListMeta();} - LPCSTR get_key() const { - if (key) - return key; - if (builtin_data && builtin_data->key) - return builtin_data->key; - return ""; - } - LPCSTR get_icon() const { - if (icon) - return icon; - if (builtin_data && builtin_data->icon) - return builtin_data->icon; - return "-"; - } - LPCSTR get_title() const { - if (title) - return title; - if (builtin_data && builtin_data->key) - return builtin_data->key; - return ""; - } - decltype(tStaticMenuDescription::parent_sec) get_parent_secs() const { - if (builtin_data) - return builtin_data->parent_sec; - return (const char**) &par_sec_dummy; - } -}; - - -tListMeta* lookup_category(const std::string& key) -{ -#ifdef OLD_IMP - - auto it = meta_lookup_data.find(key); - if (it == meta_lookup_data.end()) - return nullptr; - auto* ret = (tListMeta*) it->second; -#ifdef CONFIG_I18N - // auto-translate the default title for the user's language - //if (ret && !ret->title) - // ret->title = gettext(ret->key); - //printf("Got title? %s -> %s\n", ret->key, ret->title); -#endif - return ret; -#else -return nullptr; -#endif -} - -std::stack flat_pfxes; - -const char* flat_pfx() -{ - if (!flat_output || flat_pfxes.empty()) - return ""; - return flat_pfxes.top().c_str(); -} - -void flat_add_level(const char *name) -{ - if (!flat_output) - return; - if (flat_pfxes.empty()) - flat_pfxes.push(std::string(name) + flat_sep); - else - flat_pfxes.push(flat_pfxes.top() + name + flat_sep); -} - -void flat_drop_level() -{ - flat_pfxes.pop(); -} - -bool filter_matched(const char* title, const char* section_prefix) -{ - if (!match_in_section) - section_prefix = nullptr; - if (match_in_section_only) - title = nullptr; - - bool hasFilter(substr_filter && *substr_filter), - hasIfilter (substr_filter_nocase && *substr_filter_nocase); - - if (hasFilter) { - if(title && strstr(title, substr_filter)) - return true; - if(section_prefix && strstr(section_prefix, substr_filter)) - return true; - } -#ifdef __GNU_LIBRARY__ - if (hasIfilter) { - if(title && strcasestr(title, substr_filter_nocase)) - return true; - if(section_prefix && strcasestr(section_prefix, substr_filter_nocase)) - return true; - } -#endif - return ! (hasFilter || hasIfilter); -} - -struct t_menu_node; -extern t_menu_node root; - -// very basic, avoid vtables! -struct t_menu_node { -protected: - // for leafs -> NULL, otherwise sub-menu contents - std::map store; - char* progCmd; - const char* generic; -public: - const tListMeta *meta; - t_menu_node(const tListMeta* desc): - progCmd(nullptr), generic(nullptr), meta(desc) {} - - struct t_print_visitor { - int count, level; - t_menu_node* print_separated; - }; - - void print(t_print_visitor *ctx) { - if (!meta) - return; - auto title = meta->get_title(); - - if (store.empty()) - { - if (title && progCmd && - filter_matched(title, flat_pfxes.empty() - ? nullptr : flat_pfxes.top().c_str())) - { - if (ctx->count == 0 && add_sep_before) - puts("separator"); - if (nonempty(generic) && !strcasestr(title, generic)) { - if (right_to_left) { - printf("prog \"(%s) %s%s\" %s %s\n", - generic, flat_pfx(), title, meta->get_icon(), progCmd); - } else { - printf("prog \"%s%s (%s)\" %s %s\n", - flat_pfx(), title, generic, meta->get_icon(), progCmd); - } - } - else - printf("prog \"%s%s\" %s %s\n", flat_pfx(), title, meta->get_icon(), progCmd); - } - ctx->count++; - return; - } - - // else: render as menu - - if (ctx->level == 1 && !no_sep_others - && 0 == strcmp(meta->get_key(), "Other")) { - - ctx->print_separated = this; - return; - } - - // root level does not have a name, for others open category menu - if (ctx->level > 0) { - if (ctx->count == 0 && add_sep_before) - puts("separator"); - ctx->count++; - if (flat_output) - flat_add_level(title); - else - printf("menu \"%s\" %s {\n", title, meta->get_icon()); - } - ctx->level++; - - for(auto& it: this->store) { - ((t_menu_node*) it.second)->print(ctx); - } - - if (ctx->level == 1 && ctx->print_separated) - { - fflush(stdout); - puts("separator"); - no_sep_others = true; - ctx->print_separated->print(ctx); - } - ctx->level--; - if (ctx->level > 0) { - if (flat_output) - flat_drop_level(); - else { -#ifndef DEBUG - puts("}"); -#else - printf("# end of menu \"%s\"\n}\n", title); -#endif - } - } - if (add_sep_after && ctx->level == 0 && ctx->count > 0) - puts("separator"); - - } - - /** - * Usual print method for the root node - */ - void print() { - t_print_visitor ctx = {0,0,nullptr}; - print(&ctx); - } - - t_menu_node* add(t_menu_node* node) { - auto nam = node->meta->get_title(); - if (nam) - store[nam] = node; - return node; - } - - /** - * Returns a sub-menu which is named by the title (or key) of the provided information. - * Creates one as needed or finds existing one. - */ - t_menu_node* get_subtree(const tListMeta* info) { - auto title = info->get_title(); - auto it = store.find(title); - return (it != store.end()) ? (t_menu_node*) it->second - : add(new t_menu_node(info)); - } - - /** - * Find and examine the possible subcategory, try to assign it to the particular main category with the proper structure. - * When succeeded, blank out the main category pointer in matched_main_cats. - */ - void try_add_to_subcat(t_menu_node* pNode, const tListMeta* subCatCandidate, YVec &matched_main_cats) - { - t_menu_node *pTree = &root; - // skip the rest of the further nesting (cannot fit into any) - bool skipping = false; - - tListMeta* pNewCatInfo = nullptr; - tListMeta** ppLastMainCat = nullptr; - - for (auto pSubCatName = subCatCandidate->get_parent_secs(); - *pSubCatName; ++pSubCatName) { - // stop nesting, add to the last visited/created submenu - bool store_here = **pSubCatName == '|'; - if (skipping && store_here) { - skipping = false; - pTree = &root; - continue; - } - if (store_here) { - pTree->get_subtree(subCatCandidate)->add(pNode); - // main menu was served, don't come here again - if (ppLastMainCat) - *ppLastMainCat = nullptr; - } - - skipping = true; - // check main category filter, enter from root for main categories - - for (tListMeta** ppMainCat = matched_main_cats.data; - ppMainCat < matched_main_cats.data + matched_main_cats.size; - ++ppMainCat) { - - if (!*ppMainCat) - continue; - - // empty filter means ANY - if (**pSubCatName == '\0' - || 0 == strcmp(*pSubCatName, (**ppMainCat).get_key())) { - // the category is enabled! - skipping = false; - pTree = &root; - pNewCatInfo = *ppMainCat; - ppLastMainCat = ppMainCat; - break; - } - } - if (skipping) - continue; - // if not on first node, make or find submenues for the comming tokens - if (!pNewCatInfo) - pNewCatInfo = lookup_category(*pSubCatName); - if (!pNewCatInfo) - return; // heh? fantasy category? Let caller handle it - pTree = pTree->get_subtree(pNewCatInfo); - } - } - void add_by_categories(t_menu_node* pNode, gchar **ppCats) { - static YVec matched_main_cats, matched_sub_cats; - matched_main_cats.size = matched_sub_cats.size = 0; - - for (gchar **pCatKey = ppCats; pCatKey && *pCatKey; ++pCatKey) { - if (!**pCatKey) - continue; // empty? - tListMeta *pResolved = lookup_category(*pCatKey); - if (!pResolved) - continue; - if (!pResolved->get_parent_secs()) - matched_main_cats.add(pResolved); - else - matched_sub_cats.add(pResolved); - } - if (matched_main_cats.size == 0) - matched_main_cats.add(lookup_category("Other")); - if (!no_sub_cats) { - for (tListMeta** p = matched_sub_cats.data; - p < matched_sub_cats.data + matched_sub_cats.size; ++p) { - try_add_to_subcat(pNode, *p, matched_main_cats); - } - } - for (tListMeta** p = matched_main_cats.data; - p < matched_main_cats.data + matched_main_cats.size; ++p) { - - if (*p == nullptr) - continue; - get_subtree(*p)->add(pNode); - } - } -}; - - - -tListMeta::tListMeta(const tDesktopInfo& dinfo) { - icon = Elvis((const char*) dinfo.get_icon_path(), "-"); - title = key = Elvis(dinfo.get_name(), ""); -} - -#ifdef OLD_IMP - -t_menu_node root(tListMeta::make_dummy()); -#endif - -// variant with local description data -struct t_menu_node_app : t_menu_node -{ - tListMeta description; - - t_menu_node_app(const tDesktopInfo& dinfo) : t_menu_node(&description), - description(dinfo) { - - LPCSTR cmdraw = g_app_info_get_commandline((GAppInfo*) dinfo.pInfo); - if (!cmdraw || !*cmdraw) - return; - - // if the strings contains the exe and then only file/url tags that we wouldn't - // set anyway, THEN create a simplified version and use it later (if bSimpleCmd is true) - // OR use the original command through a wrapper (if bSimpleCmd is false) - bool bUseSimplifiedCmd = true; - gchar * cmdMod = g_strdup(cmdraw); - gchar *pcut = strpbrk(cmdMod, " \f\n\r\t\v"); - - if (pcut) { - bool bExpectXchar = false; - for (gchar *p = pcut; *p && bUseSimplifiedCmd; ++p) { - int c = (unsigned) *p; - if (bExpectXchar) { - if (strchr("FfuU", c)) - bExpectXchar = false; - else - bUseSimplifiedCmd = false; - continue; - } else if (c == '%') { - bExpectXchar = true; - continue; - } else { - if (isspace(unsigned(c))) - continue; - else { - if (!strchr(p, '%')) - goto cmdMod_is_good_as_is; - else - bUseSimplifiedCmd = false; - } - } - } - - if (bExpectXchar) - bUseSimplifiedCmd = false; - if (bUseSimplifiedCmd) - *pcut = '\0'; - cmdMod_is_good_as_is: ; - } - - bool bForTerminal = false; -#if GLIB_VERSION_CUR_STABLE >= G_ENCODE_VERSION(2, 36) - bForTerminal = g_desktop_app_info_get_boolean(dinfo.pInfo, "Terminal"); -#else - // cannot check terminal property, callback is as safe bet - bUseSimplifiedCmd = false; -#endif - - if (bUseSimplifiedCmd && !bForTerminal) // best case - progCmd = cmdMod; - else if (bForTerminal && nonempty(terminal_command)) - progCmd = g_strjoin(" ", terminal_command, "-e", cmdMod, NULL); - else - // not simple command or needs a terminal started via launcher callback, or both - progCmd = g_strdup_printf("%s \"%s\"", ApplicationName, dinfo.d_file); - if (cmdMod && cmdMod != progCmd) - g_free(cmdMod), cmdMod = nullptr; - generic = dinfo.get_generic(); - } - ~t_menu_node_app() { - g_free(progCmd); - } -}; - -std::string get_stem(const std::string& full_path) { - LPCSTR dot(nullptr), start(full_path.c_str()); - for(auto p = start; ; ++p) - { - if ('/' == *p) - start = p + 1; - else if ('.' == *p) { - dot = p; - } - else if (!*p) { - if (!dot) - dot = p; - else if (dot < start) - dot = p; - - break; - } - } - return std::string(start, dot-start); -} - -struct tFromTo { LPCSTR from; LPCSTR to;}; -// match transformations applied by some DEs -const tFromTo SameCatMap[] = { - {"Utilities", "Utility"}, - {"Sound & Video", "AudioVideo"}, - {"Sound", "Audio"}, - {"File", "FileTools"}, - {"Terminal Applications", "TerminalEmulator"}, - {"Mathematics", "Math"}, - {"Arcade", "ArcadeGame"}, - {"Card Games", "CardGame"} -}; -const tFromTo SameIconMap[] = { - { "AudioVideo", "Audio" }, - { "AudioVideo", "Video" } -}; - -typedef void (*tFuncInsertInfo)(LPCSTR szDesktopFile); -void pickup_folder_info(LPCSTR szDesktopFile) { - GKeyFile *kf = g_key_file_new(); - auto_raii free_kf(kf); - - if (!g_key_file_load_from_file(kf, szDesktopFile, G_KEY_FILE_NONE, nullptr)) - return; - LPCSTR cat_name = g_key_file_get_string(kf, "Desktop Entry", "Name", nullptr); - // looks like bad data - if (!cat_name || !*cat_name) - return; - // try a perfect match by path or file name - auto pCat = lookup_category(cat_name); - if (!pCat) - { - auto bn = get_stem(szDesktopFile); - if (!bn.empty()) - pCat = lookup_category(bn); - } - for (const tFromTo* p = SameCatMap; - !pCat && p < SameCatMap+ACOUNT(SameCatMap); - ++p) { - - if (0 == strcmp(cat_name, p->from)) - pCat = lookup_category(p->to); - } - - if (!pCat) - return; - -#ifdef OLD_IMP - if (pCat->load_state_icon < tListMeta::SYSTEM_ICON) { - LPCSTR icon_name = g_key_file_get_string (kf, "Desktop Entry", - "Icon", nullptr); - if (icon_name && *icon_name) { - pCat->icon = icon_name; - pCat->load_state_icon = tListMeta::SYSTEM_ICON; - } - } - if (pCat->load_state_title < tListMeta::SYSTEM_TRANSLATED) { - char* cat_title = g_key_file_get_locale_string(kf, "Desktop Entry", - "Name", nullptr, nullptr); - if (!cat_title) - return; - pCat->title = cat_title; - char* cat_title_c = g_key_file_get_string(kf, "Desktop Entry", - "Name", nullptr); - bool same_trans = 0 == strcmp (cat_title_c, cat_title); - if (!same_trans) - pCat->load_state_title = tListMeta::SYSTEM_TRANSLATED; - - // otherwise: not sure, keep searching for a better translation - } - // something special, donate the icon to similar items unless they have a better one - - for (auto p = SameIconMap; p < SameIconMap + ACOUNT(SameIconMap); ++p) { - - if (strcmp (pCat->key, p->from)) - continue; - - tListMeta *t = lookup_category (p->to); - // give them at least some icon for now - if (t && t->load_state_icon < tListMeta::FALLBACK_ICON) { - t->icon = pCat->icon; - t->load_state_icon = tListMeta::FALLBACK_ICON; - } - } -#endif - -} - -void insert_app_info(const char* szDesktopFile) { - tDesktopInfo dinfo(szDesktopFile); - if (!dinfo) - return; - - auto& to_where = tMenuAnchor::find_menu_anchor(dinfo); - to_where.translated_apps.insert(std::move(dinfo)); -} - -void proc_dir_rec(LPCSTR syspath, unsigned depth, - tFuncInsertInfo cb, LPCSTR szSubfolder, - LPCSTR szFileSfx) { - gchar *path = g_strjoin("/", syspath, szSubfolder, NULL); - auto_gfree relmem_path(path); - GDir *pdir = g_dir_open(path, 0, nullptr); - if (!pdir) - return; - auto_raii dircloser(pdir); - - const gchar *szFilename(nullptr); - while (nullptr != (szFilename = g_dir_read_name(pdir))) { - if (!szFilename || !checkSuffix(szFilename, szFileSfx)) - continue; - - gchar *szFullName = g_strjoin("/", path, szFilename, NULL); - auto_gfree xxfree(szFullName); - static GStatBuf buf; - if (0 != g_stat(szFullName, &buf)) - continue; - if (S_ISDIR(buf.st_mode)) { - static ino_t reclog[6]; - for (unsigned i = 0; i < depth; ++i) { - if (reclog[i] == buf.st_ino) - goto dir_visited_before; - } - if (depth < ACOUNT(reclog)) { - reclog[++depth] = buf.st_ino; - proc_dir_rec(szFullName, depth, cb, szSubfolder, - szFileSfx); - --depth; - } - dir_visited_before: ; - } - - if (!S_ISREG(buf.st_mode)) - continue; - - cb(szFullName); - } -} - -bool launch(LPCSTR dfile, char** argv, int argc) { - GDesktopAppInfo *pInfo = g_desktop_app_info_new_from_filename(dfile); - if (!pInfo) - return false; -#if 0 // g_file_get_uri crashes, no idea why, even enforcing file prefix doesn't - // help - if (argc > 0) - { - GList* parms = NULL; - for (int i = 0; i < argc; ++i) - parms = g_list_append(parms, - g_strdup_printf("%s%s", strstr(argv[i], "://") ? "" : "file://", - argv[i])); - return g_app_info_launch ((GAppInfo *)pInfo, - parms, NULL, NULL); - } - else -#else - (void) argv; - (void) argc; -#endif - return g_app_info_launch((GAppInfo *) pInfo, nullptr, nullptr, nullptr); -} - -static void init() { -#ifdef CONFIG_I18N - setlocale(LC_ALL, ""); - - auto loc = YLocale::getCheckedExplicitLocale(false); - right_to_left = loc && std::any_of(rtls, rtls + ACOUNT(rtls), - [&](const char* rtl) { - return rtl[0] == loc[0] && rtl[1] == loc[1]; - } - ); - - bindtextdomain(PACKAGE, LOCDIR); - textdomain(PACKAGE); - -#endif - - //meta_lookup_data = g_hash_table_new(g_str_hash, g_str_equal); - //gh_directory_files = g_hash_table_new(g_str_hash, g_str_equal); - -#ifdef OLD_IMP - - for (auto& what: spec::menuinfo) { - if (no_sub_cats && what.parent_sec) - continue; - meta_lookup_data[what.key] = &what; - } -#endif - const char* terminals[] = { terminal_option, getenv("TERMINAL"), TERM, - "urxvt", "alacritty", "roxterm", "xterm", - "x-terminal-emulator", "terminator" }; - for (auto term : terminals) - if (term && (terminal_command = path_lookup(term)) != nullptr) - break; -} - -#ifdef DEBUG_xxx -void dbgPrint(const gchar *msg) -{ - tlog("%s", msg); -} -#endif - -int main(int argc, char** argv) { - ApplicationName = my_basename(argv[0]); - -#if !GLIB_CHECK_VERSION(2, 36, 0) - g_type_init(); -#endif - -#ifdef DEBUG_xxx - // XXX: if enabled, one probably also need to enable debug facilities in its code, like - // what --debug option does - g_set_printerr_handler(dbgPrint); - g_set_print_handler(dbgPrint); -#endif - - char* usershare = getenv("XDG_DATA_HOME"); - if (!usershare || !*usershare) - usershare = g_strjoin(nullptr, getenv("HOME"), "/.local/share", NULL); - - // system dirs, either from environment or from static locations - LPCSTR sysshare = getenv("XDG_DATA_DIRS"); - if (!sysshare || !*sysshare) - sysshare = "/usr/local/share:/usr/share"; - - if (argc == 2 && checkSuffix(argv[1], "desktop") - && launch(argv[1], argv + 2, argc - 2)) { - return EXIT_SUCCESS; - } - - for (auto pArg = argv + 1; pArg < argv + argc; ++pArg) { - if (is_version_switch(*pArg)) { - g_fprintf(stdout, - "icewm-menu-fdo " - VERSION - ", Copyright 2015-2024 Eduard Bloch, 2017-2023 Bert Gijsbers.\n"); - exit(0); - } - else if (is_copying_switch(*pArg)) - print_copying_exit(); - else if (is_help_switch(*pArg)) - help(usershare, sysshare, stdout, EXIT_SUCCESS); - else if (is_long_switch(*pArg, "seps")) - add_sep_before = add_sep_after = true; - else if (is_long_switch(*pArg, "sep-before")) - add_sep_before = true; - else if (is_long_switch(*pArg, "sep-after")) - add_sep_after = true; - else if (is_long_switch(*pArg, "no-sep-others")) - no_sep_others = true; - else if (is_long_switch(*pArg, "no-sub-cats")) - no_sub_cats = true; - else if (is_long_switch(*pArg, "flat")) - flat_output = no_sep_others = true; - else if (is_long_switch(*pArg, "match-sec")) - match_in_section = true; - else if (is_long_switch(*pArg, "match-osec")) - match_in_section = match_in_section_only = true; - else if (is_switch(*pArg, "g", "generic-name")) - generic_name = true; - else { - char *value = nullptr, *expand = nullptr; - if (GetArgument(value, "o", "output", pArg, argv + argc)) { - if (*value == '~') - value = expand = tilde_expansion(value); - else if (*value == '$') - value = expand = dollar_expansion(value); - if (nonempty(value)) { - if (freopen(value, "w", stdout) == nullptr) { - fflush(stdout); - } - } - if (expand) - delete[] expand; - } - else if (GetArgument(value, "m", "match", pArg, argv + argc)) - substr_filter = value; - else if (GetArgument(value, "M", "imatch", pArg, argv + argc)) - substr_filter_nocase = value; - else if (GetArgument(value, "F", "flat-sep", pArg, argv + argc)) - flat_sep = value; - else if (GetArgument(value, "t", "terminal", pArg, argv + argc)) - terminal_option = value; - else // unknown option - help(usershare, sysshare, stderr, EXIT_FAILURE); - } - } - - init(); - - auto split_folders = [](const char* path_string, tCharVec& where) { - for (auto p = g_strsplit(path_string, ":", -1); *p; ++p) - where.add(*p); - }; - split_folders(sysshare, sys_folders); - split_folders(usershare, home_folders); - - for(auto& where: home_sys_folders) { - for (auto p: *where) - proc_dir_rec(p, 0, insert_app_info, "applications", "desktop"); - } - - - for(auto& where: home_sys_folders) { - for (auto p: *where) { - proc_dir_rec(p, 0, pickup_folder_info, "desktop-directories", - "directory"); - } - } - - //root.print(); - decorate_and_print(); - - //printf("What? %s\n", gettext("Building")); - - if (nonempty(usershare) && usershare != getenv("XDG_DATA_HOME")) - g_free(usershare); - delete[] terminal_command; - - return EXIT_SUCCESS; -} -#else - -#include -#include -#include -#include - typedef void (*tFuncInsertInfo)(const string &absPath, intptr_t any); class FsScan { @@ -1527,15 +478,17 @@ static void help(bool to_stderr, int xit) { * The own menu deco info is not part of this class. * It's fetched on-demand with a supplied resolver function. */ -struct tMenuNode { +struct MenuNode { void sink_in(lint_ptr df); void print(std::ostream &prt_strm, const function(const string&)> &menuDecoResolver); void collect_menu_names(const function &callback); + void fixup(); + protected: - map submenues; + map submenues; // using a map instead of set+logics adds a minor memory overhead but allows simple duplicate detection (adding user's version first) map apps; unordered_set dont_add_mark; @@ -1638,7 +591,7 @@ int main(int argc, char **argv) { auto shortLang = string(msglang ? msglang : "").substr(0, 2); - tMenuNode root; + MenuNode root; auto desktop_loader = FsScan( [&](const string &fPath) { @@ -1659,35 +612,26 @@ int main(int argc, char **argv) { root.print(cout, [](const string&) {return lint_ptr();}); - /* - cout << "lang: " << shortLang << endl; - int ret = 0; - for(int i=1; i < argc; ++i) { - DesktopFile x(argv[i], shortLang); - ret += x.IsApp; - - } - */ return EXIT_SUCCESS; } -#endif -void tMenuNode::sink_in(lint_ptr pDf) { +void MenuNode::sink_in(lint_ptr pDf) { auto &df = *pDf; dont_add_mark.clear(); bool bFoundCategories = false; auto add_sub_menues = [&](const t_menu_path &mp) { - tMenuNode *cur = this; + MenuNode *cur = this; for (auto it = std::rbegin(mp); it != std::rend(mp); ++it) { - cerr << "adding submenu: " << *it << endl; - cur = &cur->submenues[*it]; + auto key = (*it && **it) ? *it : "Other"; + //cerr << "adding submenu: " << key << endl; + cur = &cur->submenues[key]; } return cur; }; for (const auto &cat : df.Categories) { - cerr << "where does it fit? " << cat << endl; + //cerr << "where does it fit? " << cat << endl; t_menu_path refval = {cat.c_str()}; static auto comper = [](const t_menu_path &a, const t_menu_path &b) { // cerr << "left: " << *a.begin() << " vs. right: " << *b.begin() << @@ -1708,7 +652,7 @@ void tMenuNode::sink_in(lint_ptr pDf) { static string ICON_FOLDER("folder"); string indent_hint(""); -void tMenuNode::print(std::ostream &prt_strm, const function(const string&)> &menuDecoResolver) { +void MenuNode::print(std::ostream &prt_strm, const function(const string&)> &menuDecoResolver) { for(auto& m: this->submenues) { auto& name = m.first; auto deco = menuDecoResolver(name); @@ -1727,4 +671,8 @@ void tMenuNode::print(std::ostream &prt_strm, const function Date: Wed, 25 Sep 2024 19:48:48 +0200 Subject: [PATCH 09/85] Localized sorting --- src/fdomenu.cc | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 8955d6479..880a271ed 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -327,6 +327,8 @@ struct DesktopFile : public tLintRefcounted { } }; +using DesktopFilePtr = lint_ptr; + #if 0 #ifndef LPCSTR // mind the MFC @@ -479,9 +481,9 @@ static void help(bool to_stderr, int xit) { * It's fetched on-demand with a supplied resolver function. */ struct MenuNode { - void sink_in(lint_ptr df); + void sink_in(DesktopFilePtr df); - void print(std::ostream &prt_strm, const function(const string&)> &menuDecoResolver); + void print(std::ostream &prt_strm, const function &menuDecoResolver); void collect_menu_names(const function &callback); @@ -490,7 +492,7 @@ struct MenuNode { protected: map submenues; // using a map instead of set+logics adds a minor memory overhead but allows simple duplicate detection (adding user's version first) - map apps; + map apps; unordered_set dont_add_mark; }; @@ -610,13 +612,12 @@ int main(int argc, char **argv) { desktop_loader.scan(sdir + "/applications"); } - root.print(cout, [](const string&) {return lint_ptr();}); + root.print(cout, [](const string&) {return DesktopFilePtr();}); return EXIT_SUCCESS; } -void MenuNode::sink_in(lint_ptr pDf) { - auto &df = *pDf; +void MenuNode::sink_in(DesktopFilePtr pDf) { dont_add_mark.clear(); bool bFoundCategories = false; @@ -630,7 +631,7 @@ void MenuNode::sink_in(lint_ptr pDf) { return cur; }; - for (const auto &cat : df.Categories) { + for (const auto &cat : pDf->Categories) { //cerr << "where does it fit? " << cat << endl; t_menu_path refval = {cat.c_str()}; static auto comper = [](const t_menu_path &a, const t_menu_path &b) { @@ -643,7 +644,7 @@ void MenuNode::sink_in(lint_ptr pDf) { auto rng = std::equal_range(w.begin(), w.end(), refval, comper); for (auto it = rng.first; it != rng.second; ++it) { auto &tgt = *add_sub_menues(*it); - tgt.apps.emplace(df.Name, df); + tgt.apps.emplace(pDf->Name, pDf); } } } @@ -652,23 +653,32 @@ void MenuNode::sink_in(lint_ptr pDf) { static string ICON_FOLDER("folder"); string indent_hint(""); -void MenuNode::print(std::ostream &prt_strm, const function(const string&)> &menuDecoResolver) { +void MenuNode::print(std::ostream &prt_strm, const function &menuDecoResolver) { + // translated name to icon and submenu (sorted by translated) + map, tLessOp4Localized> sorted; for(auto& m: this->submenues) { auto& name = m.first; auto deco = menuDecoResolver(name); - prt_strm << indent_hint << "menu \"" << (deco ? deco->GetTranslatedName() : name) << "\" " << (deco ? deco->Icon : ICON_FOLDER) << " {\n"; + sorted[deco ? deco->GetTranslatedName() : name] = make_pair(deco ? deco->Icon : ICON_FOLDER, &m.second); + } + for(auto& m: sorted) { + auto& name = m.first; + prt_strm << indent_hint << "menu \"" << name << "\" " << m.second.first << " {\n"; indent_hint += "\t"; - m.second.print(prt_strm, menuDecoResolver); + m.second.second->print(prt_strm, menuDecoResolver); indent_hint.pop_back(); prt_strm << indent_hint << "}\n"; } - for(auto& p: this->apps) { + map sortedApps; + for(auto& p: this->apps) + sortedApps[p.second->GetTranslatedName()]=p.second; + + for(auto &p: sortedApps) { auto& pi=p.second; - prt_strm << indent_hint << "prog \"" << pi.GetTranslatedName() << "\" " << pi.Icon << " " << pi.GetCommand() << "\n"; + prt_strm << indent_hint << "prog \"" << pi->GetTranslatedName() << "\" " << pi->Icon << " " << pi->GetCommand() << "\n"; } - } void MenuNode::fixup() { From 984970a52b98c194739841be5bbe1245dbe6305e Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Thu, 26 Sep 2024 10:32:56 +0200 Subject: [PATCH 10/85] Map unknown subcats to Other main cat --- contrib/conv_cat.py | 51 ++++++++++++++++++++--------------- src/fdospecgen.h | 66 ++++++++++++++++++++++++--------------------- 2 files changed, 65 insertions(+), 52 deletions(-) diff --git a/contrib/conv_cat.py b/contrib/conv_cat.py index d9fbfe4eb..8b05df9ec 100644 --- a/contrib/conv_cat.py +++ b/contrib/conv_cat.py @@ -11,6 +11,29 @@ edges = collections.defaultdict(lambda: set()) paths = collections.defaultdict(lambda: list()) +main_cats = ( + "Accessibility", + "Settings", + "Screensavers", + "Accessories", + "Development", + "Education", + "Game", + "Graphics", + "Multimedia", + "Audio", + "Video", + "AudioVideo", + "Network", + "Office", + "Science", + "System", + "WINE", + "Editors", + "Utility", + "Other" +) + def add_edges(key :str, multicand :list): global edges print(f"{key} -> {multicand}", file=sys.stderr) @@ -22,6 +45,8 @@ def add_edges(key :str, multicand :list): for row in rdr: #print(row) assert(len(row) == 3) + if " " in row[0]: # the header + continue multicand = list(map(lambda s: s.strip(), re.split(r'\sor\s', row[2]))) add_edges(row[0], multicand) @@ -58,30 +83,14 @@ def xxx(): for vv in v: #print(f"XX: {vv}") xp = [k] + list(reversed(vv.strip().split(';'))) + if not xp[-1]: + xp[-1] = "Other" + if xp[-1] not in main_cats: + xp = ["Other"] + xp if debug: print(f"{len(xp)} -> {xp}", file=sys.stderr) paths[len(xp)].append(xp) -paths[1] = list(map(lambda x: [x], [ - "Accessibility", -"Settings", -"Screensavers", -"Accessories", -"Development", -"Education", -"Game", -"Graphics", -"Multimedia", -"Audio", -"Video", -"AudioVideo", -"Network", -"Office", -"Science", -"System", -"WINE", -"Editors", -"Utility"] - )) +paths[1] = list(map(lambda x: [x], main_cats)) if debug: print(paths, file=sys.stderr) diff --git a/src/fdospecgen.h b/src/fdospecgen.h index b1b72131f..b2776b8cb 100644 --- a/src/fdospecgen.h +++ b/src/fdospecgen.h @@ -15,22 +15,31 @@ using t_menu_path = std::initializer_list; using t_menu_path_table = std::initializer_list; using t_menu_path_table_list = std::initializer_list; -#define MENU_DEPTH_MAX 3 +#define MENU_DEPTH_MAX 4 constexpr t_menu_path_table_list valid_paths = { + // menu locations of depth 4 + { + {"Other", "Printing", "Settings", "HardwareSettings"}, + }, + // menu locations of depth 3 { {"Compression", "Archiving", "Utility"}, {"FileManager", "FileTools", "System"}, {"Midi", "Audio", "AudioVideo"}, {"Mixer", "Audio", "AudioVideo"}, - {"NumericalAnalysis", "Math", "Science"}, {"NumericalAnalysis", "Math", "Education"}, + {"NumericalAnalysis", "Math", "Science"}, {"OCR", "Scanning", "Graphics"}, - {"ParallelComputing", "ComputerScience", "Science"}, + {"Other", "Dictionary", "TextTools"}, + {"Other", "KDE", "QT"}, + {"Other", "GNOME", "GTK"}, + {"Other", "XFCE", "GTK"}, + {"Other", "DDE", "Qt"}, {"ParallelComputing", "ComputerScience", "Education"}, - {"Printing", "Settings", "HardwareSettings"}, + {"ParallelComputing", "ComputerScience", "Science"}, {"RasterGraphics", "2DGraphics", "Graphics"}, {"Sequencer", "Audio", "AudioVideo"}, {"TV", "Video", "AudioVideo"}, @@ -42,13 +51,12 @@ constexpr t_menu_path_table_list valid_paths = { { {"2DGraphics", "Graphics"}, {"3DGraphics", "Graphics"}, - {"Accessibility", "Settings"}, {"Accessibility", "Utility"}, + {"Accessibility", "Settings"}, {"ActionGame", "Game"}, - {"Additional Category", "Related Categories"}, - {"Adult", ""}, + {"Adult", "Other"}, {"AdventureGame", "Game"}, - {"Amusement", ""}, + {"Amusement", "Other"}, {"ArcadeGame", "Game"}, {"Archiving", "Utility"}, {"Art", "Science"}, @@ -58,14 +66,14 @@ constexpr t_menu_path_table_list valid_paths = { {"Astronomy", "Science"}, {"Astronomy", "Education"}, {"AudioVideoEditing", "Audio"}, - {"AudioVideoEditing", "Video"}, {"AudioVideoEditing", "AudioVideo"}, + {"AudioVideoEditing", "Video"}, {"Biology", "Science"}, {"Biology", "Education"}, {"BlocksGame", "Game"}, {"BoardGame", "Game"}, {"Building", "Development"}, - {"COSMIC", ""}, + {"COSMIC", "Other"}, {"Calculator", "Utility"}, {"Calendar", "Office"}, {"CardGame", "Game"}, @@ -76,12 +84,11 @@ constexpr t_menu_path_table_list valid_paths = { {"Clock", "Utility"}, {"ComputerScience", "Science"}, {"ComputerScience", "Education"}, - {"ConsoleOnly", ""}, + {"ConsoleOnly", "Other"}, {"Construction", "Science"}, {"Construction", "Education"}, {"ContactManagement", "Office"}, - {"Core", ""}, - {"DDE", "Qt"}, + {"Core", "Other"}, {"DataVisualization", "Science"}, {"DataVisualization", "Education"}, {"Database", "AudioVideo"}, @@ -90,20 +97,19 @@ constexpr t_menu_path_table_list valid_paths = { {"Debugger", "Development"}, {"DesktopSettings", "Settings"}, {"Dialup", "Network"}, - {"Dictionary", "TextTools"}, {"Dictionary", "Office"}, {"DiscBurning", "AudioVideo"}, - {"Documentation", ""}, + {"Documentation", "Other"}, {"Economy", "Science"}, {"Economy", "Education"}, {"Electricity", "Science"}, {"Electricity", "Education"}, - {"Electronics", ""}, - {"Email", "Network"}, + {"Electronics", "Other"}, {"Email", "Office"}, - {"Emulator", "System"}, + {"Email", "Network"}, {"Emulator", "Game"}, - {"Engineering", ""}, + {"Emulator", "System"}, + {"Engineering", "Other"}, {"Feed", "Network"}, {"FileTools", "System"}, {"FileTools", "Utility"}, @@ -111,8 +117,7 @@ constexpr t_menu_path_table_list valid_paths = { {"Filesystem", "System"}, {"Finance", "Office"}, {"FlowChart", "Office"}, - {"GNOME", "GTK"}, - {"GTK", ""}, + {"GTK", "Other"}, {"GUIDesigner", "Development"}, {"Geography", "Science"}, {"Geography", "Education"}, @@ -132,8 +137,7 @@ constexpr t_menu_path_table_list valid_paths = { {"ImageProcessing", "Science"}, {"ImageProcessing", "Education"}, {"InstantMessaging", "Network"}, - {"Java", ""}, - {"KDE", "QT"}, + {"Java", "Other"}, {"KidsGame", "Game"}, {"Languages", "Science"}, {"Languages", "Education"}, @@ -147,9 +151,9 @@ constexpr t_menu_path_table_list valid_paths = { {"Math", "Education"}, {"MedicalSoftware", "Science"}, {"MedicalSoftware", "Education"}, - {"Monitor", "System"}, {"Monitor", "Network"}, - {"Motif", ""}, + {"Monitor", "System"}, + {"Motif", "Other"}, {"Music", "AudioVideo"}, {"Music", "Education"}, {"News", "Network"}, @@ -161,26 +165,26 @@ constexpr t_menu_path_table_list valid_paths = { {"Physics", "Science"}, {"Physics", "Education"}, {"Player", "Audio"}, - {"Player", "Video"}, {"Player", "AudioVideo"}, + {"Player", "Video"}, {"Presentation", "Office"}, {"Profiling", "Development"}, {"ProjectManagement", "Development"}, {"ProjectManagement", "Office"}, {"Publishing", "Graphics"}, {"Publishing", "Office"}, - {"Qt", ""}, + {"Qt", "Other"}, {"Recorder", "Audio"}, - {"Recorder", "Video"}, {"Recorder", "AudioVideo"}, + {"Recorder", "Video"}, {"RemoteAccess", "Network"}, {"RevisionControl", "Development"}, {"Robotics", "Science"}, {"Robotics", "Education"}, {"RolePlaying", "Game"}, {"Scanning", "Graphics"}, - {"Security", "Settings"}, {"Security", "System"}, + {"Security", "Settings"}, {"Shooter", "Game"}, {"Simulation", "Game"}, {"Spirituality", "Science"}, @@ -204,7 +208,6 @@ constexpr t_menu_path_table_list valid_paths = { {"WebDevelopment", "Development"}, {"WebDevelopment", "Network"}, {"WordProcessor", "Office"}, - {"XFCE", "GTK"}, }, // menu locations of depth 1 @@ -221,6 +224,7 @@ constexpr t_menu_path_table_list valid_paths = { {"Multimedia"}, {"Network"}, {"Office"}, + {"Other"}, {"Science"}, {"Screensavers"}, {"Settings"}, @@ -231,6 +235,6 @@ constexpr t_menu_path_table_list valid_paths = { }, }; -#define SIZE_OF_MENU_TABLE 3 +#define SIZE_OF_MENU_TABLE 4 #endif // FDO_GEN_MENU_STRUCTURE_H From 7e5e19dd9c766e3f3a43298cb05152a13abc22ff Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Thu, 26 Sep 2024 11:00:40 +0200 Subject: [PATCH 11/85] Simple attempt to get duplicated items in parent nodes --- src/fdomenu.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 880a271ed..bce4e5a6e 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -379,6 +379,8 @@ const char *rtls[] = { "ur", // urdu }; + + struct tLessOp4Localized { std::locale loc; // default locale const std::collate& coll = std::use_facet >(loc); @@ -489,10 +491,9 @@ struct MenuNode { void fixup(); -protected: map submenues; // using a map instead of set+logics adds a minor memory overhead but allows simple duplicate detection (adding user's version first) - map apps; + unordered_map apps; unordered_set dont_add_mark; }; @@ -624,6 +625,13 @@ void MenuNode::sink_in(DesktopFilePtr pDf) { auto add_sub_menues = [&](const t_menu_path &mp) { MenuNode *cur = this; for (auto it = std::rbegin(mp); it != std::rend(mp); ++it) { + +#warning Insufficient, works only when the keywords have the "friendly" order + auto wrong_one = cur->apps.find(pDf->Name); + if (wrong_one != cur->apps.end() && wrong_one->second == pDf) { + cur->apps.erase(wrong_one); + } + auto key = (*it && **it) ? *it : "Other"; //cerr << "adding submenu: " << key << endl; cur = &cur->submenues[key]; From 8b75dde4cc5650489022413b08bb1b2cf6cdb5d3 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Thu, 26 Sep 2024 16:56:41 +0200 Subject: [PATCH 12/85] Attaching menu description, incomplete --- src/fdomenu.cc | 69 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 9 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index bce4e5a6e..71573da16 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -253,7 +253,7 @@ struct DesktopFile : public tLintRefcounted { replace_all(Exec, "%i", Icon); return Exec; } - DesktopFile(string filePath, const string &lang) { + DesktopFile(string filePath, const string &lang, const unordered_set& allowed_names) { //cout << "filterlang: " << lang < load_visible(const string &path, const string &lang) { + static lint_ptr load_visible(const string &path, const string &lang, const unordered_set &wanted_names = unordered_set()) { auto ret = lint_ptr(); try { - ret.reset(new DesktopFile(path, lang)); + ret.reset(new DesktopFile(path, lang, wanted_names)); if (ret->NoDisplay) ret.reset(); } catch (const std::exception &) { @@ -487,16 +493,22 @@ struct MenuNode { void print(std::ostream &prt_strm, const function &menuDecoResolver); - void collect_menu_names(const function &callback); + //void collect_menu_names(const function &callback); void fixup(); map submenues; + // using a map instead of set+logics adds a minor memory overhead but allows simple duplicate detection (adding user's version first) unordered_map apps; - unordered_set dont_add_mark; + //unordered_set dont_add_mark; + + static unordered_multimap menu_nodes_by_name; + DesktopFilePtr deco; }; +decltype(MenuNode::menu_nodes_by_name) MenuNode::menu_nodes_by_name; + int main(int argc, char **argv) { // basic framework and environment initialization @@ -606,6 +618,7 @@ int main(int argc, char **argv) { root.sink_in(df); }, ".desktop"); + for (const auto &sdir : sharedirs) { #ifdef DEBUG cerr << "checkdir: " << sdir << endl; @@ -613,28 +626,61 @@ int main(int argc, char **argv) { desktop_loader.scan(sdir + "/applications"); } + root.fixup(); + + unordered_set filter; + for(const auto& kv: root.menu_nodes_by_name) + filter.insert(kv.first); + + auto dir_loader = FsScan([&](const string &fPath) { + #warning Filter apparently broken + auto df = DesktopFile::load_visible(fPath, shortLang /*, filter*/); + if (df) { + auto rng = root.menu_nodes_by_name.equal_range(df->Name); + for (auto it=rng.first; it != rng.second; ++it) + it->second->second.deco = df; + } + }, ".directory"); + + for (const auto &sdir : sharedirs) { + dir_loader.scan(sdir + "/desktop-directories"); + } + + root.print(cout, [](const string&) {return DesktopFilePtr();}); return EXIT_SUCCESS; } void MenuNode::sink_in(DesktopFilePtr pDf) { - dont_add_mark.clear(); - bool bFoundCategories = false; auto add_sub_menues = [&](const t_menu_path &mp) { MenuNode *cur = this; for (auto it = std::rbegin(mp); it != std::rend(mp); ++it) { #warning Insufficient, works only when the keywords have the "friendly" order + /* auto wrong_one = cur->apps.find(pDf->Name); if (wrong_one != cur->apps.end() && wrong_one->second == pDf) { cur->apps.erase(wrong_one); } + This gets overcomplicated. Could be solved by getting the menu paths for each keyword first, sorting them by length (descending), + then adding the deepest first and marking parent nodes as "visited" (another hashset or similar) to not add there again later. + + But then again, it's probably easier to just add them wherever they appear and use fixup() later. + + */ + auto key = (*it && **it) ? *it : "Other"; + auto added = cur->submenues.emplace(key, MenuNode()); + if (added.second) { + menu_nodes_by_name.insert({key, added.first}); + } + cur = & added.first->second; + //cerr << "adding submenu: " << key << endl; - cur = &cur->submenues[key]; + //cur = &cur->submenues[key]; } return cur; }; @@ -671,7 +717,12 @@ void MenuNode::print(std::ostream &prt_strm, const functiondeco ? + m.second.second->deco->GetTranslatedName() : name) << "\" " << + + ((m.second.second->deco && !m.second.second->deco->Icon.empty()) ? + m.second.second->deco->Icon : ICON_FOLDER) + << " {\n"; indent_hint += "\t"; m.second.second->print(prt_strm, menuDecoResolver); From 443084f08fcec4c66a361a6334480a44eb30a1ae Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Thu, 26 Sep 2024 17:19:21 +0200 Subject: [PATCH 13/85] Fix main cat fallback --- contrib/conv_cat.py | 2 +- src/fdospecgen.h | 84 ++++++++++++++++++++++----------------------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/contrib/conv_cat.py b/contrib/conv_cat.py index 8b05df9ec..f9dd39900 100644 --- a/contrib/conv_cat.py +++ b/contrib/conv_cat.py @@ -86,7 +86,7 @@ def xxx(): if not xp[-1]: xp[-1] = "Other" if xp[-1] not in main_cats: - xp = ["Other"] + xp + xp = xp + ["Other"] if debug: print(f"{len(xp)} -> {xp}", file=sys.stderr) paths[len(xp)].append(xp) diff --git a/src/fdospecgen.h b/src/fdospecgen.h index b2776b8cb..a39abed0b 100644 --- a/src/fdospecgen.h +++ b/src/fdospecgen.h @@ -21,55 +21,55 @@ constexpr t_menu_path_table_list valid_paths = { // menu locations of depth 4 { - {"Other", "Printing", "Settings", "HardwareSettings"}, + {"Printing", "Settings", "HardwareSettings", "Other"}, }, // menu locations of depth 3 { {"Compression", "Archiving", "Utility"}, + {"DDE", "Qt", "Other"}, + {"Dictionary", "TextTools", "Other"}, {"FileManager", "FileTools", "System"}, + {"GNOME", "GTK", "Other"}, + {"KDE", "QT", "Other"}, {"Midi", "Audio", "AudioVideo"}, {"Mixer", "Audio", "AudioVideo"}, {"NumericalAnalysis", "Math", "Education"}, {"NumericalAnalysis", "Math", "Science"}, {"OCR", "Scanning", "Graphics"}, - {"Other", "Dictionary", "TextTools"}, - {"Other", "KDE", "QT"}, - {"Other", "GNOME", "GTK"}, - {"Other", "XFCE", "GTK"}, - {"Other", "DDE", "Qt"}, - {"ParallelComputing", "ComputerScience", "Education"}, {"ParallelComputing", "ComputerScience", "Science"}, + {"ParallelComputing", "ComputerScience", "Education"}, {"RasterGraphics", "2DGraphics", "Graphics"}, {"Sequencer", "Audio", "AudioVideo"}, {"TV", "Video", "AudioVideo"}, {"Tuner", "Audio", "AudioVideo"}, {"VectorGraphics", "2DGraphics", "Graphics"}, + {"XFCE", "GTK", "Other"}, }, // menu locations of depth 2 { {"2DGraphics", "Graphics"}, {"3DGraphics", "Graphics"}, - {"Accessibility", "Utility"}, {"Accessibility", "Settings"}, + {"Accessibility", "Utility"}, {"ActionGame", "Game"}, {"Adult", "Other"}, {"AdventureGame", "Game"}, {"Amusement", "Other"}, {"ArcadeGame", "Game"}, {"Archiving", "Utility"}, - {"Art", "Science"}, {"Art", "Education"}, - {"Artificialtelligence", "Science"}, + {"Art", "Science"}, {"Artificialtelligence", "Education"}, - {"Astronomy", "Science"}, + {"Artificialtelligence", "Science"}, {"Astronomy", "Education"}, + {"Astronomy", "Science"}, {"AudioVideoEditing", "Audio"}, - {"AudioVideoEditing", "AudioVideo"}, {"AudioVideoEditing", "Video"}, - {"Biology", "Science"}, + {"AudioVideoEditing", "AudioVideo"}, {"Biology", "Education"}, + {"Biology", "Science"}, {"BlocksGame", "Game"}, {"BoardGame", "Game"}, {"Building", "Development"}, @@ -79,31 +79,31 @@ constexpr t_menu_path_table_list valid_paths = { {"CardGame", "Game"}, {"Chart", "Office"}, {"Chat", "Network"}, - {"Chemistry", "Science"}, {"Chemistry", "Education"}, + {"Chemistry", "Science"}, {"Clock", "Utility"}, - {"ComputerScience", "Science"}, {"ComputerScience", "Education"}, + {"ComputerScience", "Science"}, {"ConsoleOnly", "Other"}, - {"Construction", "Science"}, {"Construction", "Education"}, + {"Construction", "Science"}, {"ContactManagement", "Office"}, {"Core", "Other"}, - {"DataVisualization", "Science"}, {"DataVisualization", "Education"}, - {"Database", "AudioVideo"}, - {"Database", "Development"}, + {"DataVisualization", "Science"}, {"Database", "Office"}, + {"Database", "Development"}, + {"Database", "AudioVideo"}, {"Debugger", "Development"}, {"DesktopSettings", "Settings"}, {"Dialup", "Network"}, {"Dictionary", "Office"}, {"DiscBurning", "AudioVideo"}, {"Documentation", "Other"}, - {"Economy", "Science"}, {"Economy", "Education"}, - {"Electricity", "Science"}, + {"Economy", "Science"}, {"Electricity", "Education"}, + {"Electricity", "Science"}, {"Electronics", "Other"}, {"Email", "Office"}, {"Email", "Network"}, @@ -119,79 +119,79 @@ constexpr t_menu_path_table_list valid_paths = { {"FlowChart", "Office"}, {"GTK", "Other"}, {"GUIDesigner", "Development"}, - {"Geography", "Science"}, {"Geography", "Education"}, - {"Geology", "Science"}, + {"Geography", "Science"}, {"Geology", "Education"}, - {"Geoscience", "Science"}, + {"Geology", "Science"}, {"Geoscience", "Education"}, + {"Geoscience", "Science"}, {"HamRadio", "Audio"}, {"HamRadio", "Network"}, {"HardwareSettings", "Settings"}, - {"History", "Science"}, {"History", "Education"}, - {"Humanities", "Science"}, + {"History", "Science"}, {"Humanities", "Education"}, + {"Humanities", "Science"}, {"IDE", "Development"}, {"IRCClient", "Network"}, - {"ImageProcessing", "Science"}, {"ImageProcessing", "Education"}, + {"ImageProcessing", "Science"}, {"InstantMessaging", "Network"}, {"Java", "Other"}, {"KidsGame", "Game"}, - {"Languages", "Science"}, {"Languages", "Education"}, - {"Literature", "Science"}, + {"Languages", "Science"}, {"Literature", "Education"}, + {"Literature", "Science"}, {"LogicGame", "Game"}, - {"Maps", "Science"}, {"Maps", "Education"}, + {"Maps", "Science"}, {"Maps", "Utility"}, - {"Math", "Science"}, {"Math", "Education"}, - {"MedicalSoftware", "Science"}, + {"Math", "Science"}, {"MedicalSoftware", "Education"}, - {"Monitor", "Network"}, + {"MedicalSoftware", "Science"}, {"Monitor", "System"}, + {"Monitor", "Network"}, {"Motif", "Other"}, - {"Music", "AudioVideo"}, {"Music", "Education"}, + {"Music", "AudioVideo"}, {"News", "Network"}, {"P2P", "Network"}, {"PDA", "Office"}, {"PackageManager", "Settings"}, {"Photography", "Graphics"}, {"Photography", "Office"}, - {"Physics", "Science"}, {"Physics", "Education"}, + {"Physics", "Science"}, {"Player", "Audio"}, - {"Player", "AudioVideo"}, {"Player", "Video"}, + {"Player", "AudioVideo"}, {"Presentation", "Office"}, {"Profiling", "Development"}, - {"ProjectManagement", "Development"}, {"ProjectManagement", "Office"}, + {"ProjectManagement", "Development"}, {"Publishing", "Graphics"}, {"Publishing", "Office"}, {"Qt", "Other"}, {"Recorder", "Audio"}, - {"Recorder", "AudioVideo"}, {"Recorder", "Video"}, + {"Recorder", "AudioVideo"}, {"RemoteAccess", "Network"}, {"RevisionControl", "Development"}, - {"Robotics", "Science"}, {"Robotics", "Education"}, + {"Robotics", "Science"}, {"RolePlaying", "Game"}, {"Scanning", "Graphics"}, - {"Security", "System"}, {"Security", "Settings"}, + {"Security", "System"}, {"Shooter", "Game"}, {"Simulation", "Game"}, - {"Spirituality", "Science"}, {"Spirituality", "Education"}, + {"Spirituality", "Science"}, {"Spirituality", "Utility"}, - {"Sports", "Science"}, {"Sports", "Education"}, + {"Sports", "Science"}, {"SportsGame", "Game"}, {"Spreadsheet", "Office"}, {"StrategyGame", "Game"}, From 1c0961021a32b3c182ccc25b99ac35636fdf4bf0 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Thu, 26 Sep 2024 17:31:32 +0200 Subject: [PATCH 14/85] Work around missing reverse iterator, can be plain C++11 again --- src/CMakeLists.txt | 2 +- src/fdomenu.cc | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0eb933bfe..bd8e509f8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.13) PROJECT(ICEWM CXX) -set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED on) INCLUDE(CheckIncludeFiles) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 71573da16..d2cf21e64 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -656,7 +656,11 @@ void MenuNode::sink_in(DesktopFilePtr pDf) { auto add_sub_menues = [&](const t_menu_path &mp) { MenuNode *cur = this; - for (auto it = std::rbegin(mp); it != std::rend(mp); ++it) { + + // work around the lack of reverse iterator, can fixed in C++14 with std::rbegin() conversion + if(!mp.size()) + return cur; + for (auto it = mp.end()-1; ; --it) { #warning Insufficient, works only when the keywords have the "friendly" order /* @@ -681,6 +685,8 @@ void MenuNode::sink_in(DesktopFilePtr pDf) { //cerr << "adding submenu: " << key << endl; //cur = &cur->submenues[key]; + if (mp.begin() == it) + break; } return cur; }; From 63ca37fb01d55bcea4cdc0a28001c9700bc01db2 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Thu, 26 Sep 2024 19:56:47 +0200 Subject: [PATCH 15/85] Fallback to directory file base name matching the category name --- src/CMakeLists.txt | 3 +++ src/fdomenu.cc | 32 +++++++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bd8e509f8..c232973d0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -92,6 +92,9 @@ else() endif() endif() +#list(APPEND CXXFLAGS_COMMON -fsanitize=address -fsanitize=undefined) +#list(APPEND EXTRA_LINKER_FLAGS -fsanitize=address -fsanitize=undefined) + option(CONFIG_IMLIB2 "Imlib2 image loader" on) option(CONFIG_LIBPNG "PNGLIB image loader" off) option(CONFIG_LIBJPEG "JPEGLIB image loader" off) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index d2cf21e64..2b7184bce 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -322,6 +322,7 @@ struct DesktopFile : public tLintRefcounted { } static lint_ptr load_visible(const string &path, const string &lang, const unordered_set &wanted_names = unordered_set()) { + //cerr << "load_visiblie: " << path << endl; auto ret = lint_ptr(); try { ret.reset(new DesktopFile(path, lang, wanted_names)); @@ -413,6 +414,9 @@ class FsScan { private: void proc_dir_rec(const string &path) { + + cerr << "enter: " << path <d_name[0] == '.') continue; - pent->d_name[255] = 0; + // XXX: this triggers a problem, don't do it for now + //cerr << "before: " << pent->d_name << endl; + //pent->d_name[0xff] = '\0'; + //cerr << "after: " << pent->d_name << endl; + string fname(pent->d_name); - if (!sFileNameExtFilter.empty() && - !endsWith(fname, sFileNameExtFilter)) - continue; - if (fstatat(fddir, fname.c_str(), &stbuf, 0)) + + if (fstatat(fddir, pent->d_name, &stbuf, 0)) continue; + if (S_ISDIR(stbuf.st_mode)) { // link loop detection auto prev = make_pair(stbuf.st_ino, stbuf.st_dev); @@ -447,6 +454,12 @@ class FsScan { if (!S_ISREG(stbuf.st_mode)) continue; + if (!sFileNameExtFilter.empty() && + !endsWith(fname, sFileNameExtFilter)) { + + continue; + } + cb(path + "/" + fname); } } @@ -639,6 +652,15 @@ int main(int argc, char **argv) { auto rng = root.menu_nodes_by_name.equal_range(df->Name); for (auto it=rng.first; it != rng.second; ++it) it->second->second.deco = df; + if (rng.first == rng.second) // empty? Try using the plain filename, some menus descriptors use the category as file name but a differing Name attribute + { + auto cpos = fPath.find_last_of("/"); + auto mcatName = fPath.substr(cpos + 1, fPath.length()-cpos-11); + rng = root.menu_nodes_by_name.equal_range(mcatName); + cerr << "altname: " << mcatName <second->second.deco = df; + } } }, ".directory"); From d98ce079d7665942817b005461ead04ec90f3567 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Thu, 26 Sep 2024 20:29:55 +0200 Subject: [PATCH 16/85] Mark submenu labels translateable --- contrib/Main_Categories.csv | 14 + contrib/conv_cat.py | 44 +- src/fdospecgen.h | 1383 ++++++++++++++++++++++++++++++----- 3 files changed, 1219 insertions(+), 222 deletions(-) create mode 100644 contrib/Main_Categories.csv diff --git a/contrib/Main_Categories.csv b/contrib/Main_Categories.csv new file mode 100644 index 000000000..a52a6a10d --- /dev/null +++ b/contrib/Main_Categories.csv @@ -0,0 +1,14 @@ +Main Category,Description,Notes +AudioVideo,"Application for presenting, creating, or processing multimedia (audio/video)",  +Audio,An audio application,Desktop entry must include AudioVideo as well +Video,A video application,Desktop entry must include AudioVideo as well +Development,An application for development,  +Education,Educational software,  +Game,A game,  +Graphics,"Application for viewing, creating, or processing graphics",  +Network,Network application such as a web browser,  +Office,An office type application,  +Science,Scientific software,  +Settings,Settings applications,"Entries may appear in a separate menu or as part of a ""Control Center""" +System,"System application, ""System Tools"" such as say a log viewer or network monitor",  +Utility,"Small utility application, ""Accessories""",  diff --git a/contrib/conv_cat.py b/contrib/conv_cat.py index f9dd39900..732619393 100644 --- a/contrib/conv_cat.py +++ b/contrib/conv_cat.py @@ -10,29 +10,11 @@ edges = collections.defaultdict(lambda: set()) paths = collections.defaultdict(lambda: list()) +hints = dict() + +# a few special ones, those from the spec are added from table input +main_cats = {"Accessibility", "Screensavers", "WINE", "Other"} -main_cats = ( - "Accessibility", - "Settings", - "Screensavers", - "Accessories", - "Development", - "Education", - "Game", - "Graphics", - "Multimedia", - "Audio", - "Video", - "AudioVideo", - "Network", - "Office", - "Science", - "System", - "WINE", - "Editors", - "Utility", - "Other" -) def add_edges(key :str, multicand :list): global edges @@ -40,6 +22,17 @@ def add_edges(key :str, multicand :list): edges[key] |= set(multicand) +with open('Main_Categories.csv', newline='') as csvfile: + rdr = csv.reader(csvfile, dialect='unix') + for row in rdr: + #print(row) + assert(len(row) == 3) + if " " in row[0]: # the header + continue + main_cats.add(row[0].strip()) + hints[row[0]] = row[1] + + with open('Additional_Categories.csv', newline='') as csvfile: rdr = csv.reader(csvfile, dialect='unix') for row in rdr: @@ -49,6 +42,7 @@ def add_edges(key :str, multicand :list): continue multicand = list(map(lambda s: s.strip(), re.split(r'\sor\s', row[2]))) add_edges(row[0], multicand) + hints[row[0]] = row[1] #print(edges, file=sys.stderr) @@ -121,7 +115,11 @@ def xxx(): print(f"\n\t// menu locations of depth {k}\n\t{{") byFirst = sorted(paths[k], key=lambda l: l[0]) for v in byFirst: - print("\t\t" + str(v).replace("'", '"').replace('[','{').replace(']','}') + ",") + print("\t\t{") + for t in v: + print("// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: " + hints.get(t, t)) + print("\t\t\tN_(\"" + t + "\"),") + print("\t\t},") print("\t},") print(f"""}}; diff --git a/src/fdospecgen.h b/src/fdospecgen.h index a39abed0b..9f8df034a 100644 --- a/src/fdospecgen.h +++ b/src/fdospecgen.h @@ -21,217 +21,1202 @@ constexpr t_menu_path_table_list valid_paths = { // menu locations of depth 4 { - {"Printing", "Settings", "HardwareSettings", "Other"}, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tool to manage printers + N_("Printing"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Settings applications + N_("Settings"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tool to manage hardware components, like sound cards, video cards or printers + N_("HardwareSettings"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other + N_("Other"), + }, }, // menu locations of depth 3 { - {"Compression", "Archiving", "Utility"}, - {"DDE", "Qt", "Other"}, - {"Dictionary", "TextTools", "Other"}, - {"FileManager", "FileTools", "System"}, - {"GNOME", "GTK", "Other"}, - {"KDE", "QT", "Other"}, - {"Midi", "Audio", "AudioVideo"}, - {"Mixer", "Audio", "AudioVideo"}, - {"NumericalAnalysis", "Math", "Education"}, - {"NumericalAnalysis", "Math", "Science"}, - {"OCR", "Scanning", "Graphics"}, - {"ParallelComputing", "ComputerScience", "Science"}, - {"ParallelComputing", "ComputerScience", "Education"}, - {"RasterGraphics", "2DGraphics", "Graphics"}, - {"Sequencer", "Audio", "AudioVideo"}, - {"TV", "Video", "AudioVideo"}, - {"Tuner", "Audio", "AudioVideo"}, - {"VectorGraphics", "2DGraphics", "Graphics"}, - {"XFCE", "GTK", "Other"}, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tool to manage compressed data/archives + N_("Compression"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tool to archive/backup data + N_("Archiving"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Small utility application, "Accessories" + N_("Utility"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on DDE libraries + N_("DDE"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on Qt libraries + N_("Qt"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other + N_("Other"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A dictionary + N_("Dictionary"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A text tool utility + N_("TextTools"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other + N_("Other"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A file manager + N_("FileManager"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A file tool utility + N_("FileTools"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: System application, "System Tools" such as say a log viewer or network monitor + N_("System"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on GNOME libraries + N_("GNOME"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on GTK+ libraries + N_("GTK"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other + N_("Other"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on KDE libraries + N_("KDE"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: QT + N_("QT"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other + N_("Other"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An app related to MIDI + N_("Midi"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An audio application + N_("Audio"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for presenting, creating, or processing multimedia (audio/video) + N_("AudioVideo"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Just a mixer + N_("Mixer"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An audio application + N_("Audio"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for presenting, creating, or processing multimedia (audio/video) + N_("AudioVideo"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Numerical analysis software + N_("NumericalAnalysis"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Math software + N_("Math"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Numerical analysis software + N_("NumericalAnalysis"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Math software + N_("Math"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Optical character recognition application + N_("OCR"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Tool to scan a file/text + N_("Scanning"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for viewing, creating, or processing graphics + N_("Graphics"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Parallel computing software + N_("ParallelComputing"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Computer Science software + N_("ComputerScience"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Parallel computing software + N_("ParallelComputing"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Computer Science software + N_("ComputerScience"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for viewing, creating, or processing raster (bitmap) graphics + N_("RasterGraphics"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: 2D based graphical application + N_("2DGraphics"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for viewing, creating, or processing graphics + N_("Graphics"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A sequencer + N_("Sequencer"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An audio application + N_("Audio"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for presenting, creating, or processing multimedia (audio/video) + N_("AudioVideo"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A TV application + N_("TV"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A video application + N_("Video"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for presenting, creating, or processing multimedia (audio/video) + N_("AudioVideo"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tuner + N_("Tuner"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An audio application + N_("Audio"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for presenting, creating, or processing multimedia (audio/video) + N_("AudioVideo"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for viewing, creating, or processing vector graphics + N_("VectorGraphics"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: 2D based graphical application + N_("2DGraphics"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for viewing, creating, or processing graphics + N_("Graphics"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on XFCE libraries + N_("XFCE"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on GTK+ libraries + N_("GTK"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other + N_("Other"), + }, }, // menu locations of depth 2 { - {"2DGraphics", "Graphics"}, - {"3DGraphics", "Graphics"}, - {"Accessibility", "Settings"}, - {"Accessibility", "Utility"}, - {"ActionGame", "Game"}, - {"Adult", "Other"}, - {"AdventureGame", "Game"}, - {"Amusement", "Other"}, - {"ArcadeGame", "Game"}, - {"Archiving", "Utility"}, - {"Art", "Education"}, - {"Art", "Science"}, - {"Artificialtelligence", "Education"}, - {"Artificialtelligence", "Science"}, - {"Astronomy", "Education"}, - {"Astronomy", "Science"}, - {"AudioVideoEditing", "Audio"}, - {"AudioVideoEditing", "Video"}, - {"AudioVideoEditing", "AudioVideo"}, - {"Biology", "Education"}, - {"Biology", "Science"}, - {"BlocksGame", "Game"}, - {"BoardGame", "Game"}, - {"Building", "Development"}, - {"COSMIC", "Other"}, - {"Calculator", "Utility"}, - {"Calendar", "Office"}, - {"CardGame", "Game"}, - {"Chart", "Office"}, - {"Chat", "Network"}, - {"Chemistry", "Education"}, - {"Chemistry", "Science"}, - {"Clock", "Utility"}, - {"ComputerScience", "Education"}, - {"ComputerScience", "Science"}, - {"ConsoleOnly", "Other"}, - {"Construction", "Education"}, - {"Construction", "Science"}, - {"ContactManagement", "Office"}, - {"Core", "Other"}, - {"DataVisualization", "Education"}, - {"DataVisualization", "Science"}, - {"Database", "Office"}, - {"Database", "Development"}, - {"Database", "AudioVideo"}, - {"Debugger", "Development"}, - {"DesktopSettings", "Settings"}, - {"Dialup", "Network"}, - {"Dictionary", "Office"}, - {"DiscBurning", "AudioVideo"}, - {"Documentation", "Other"}, - {"Economy", "Education"}, - {"Economy", "Science"}, - {"Electricity", "Education"}, - {"Electricity", "Science"}, - {"Electronics", "Other"}, - {"Email", "Office"}, - {"Email", "Network"}, - {"Emulator", "Game"}, - {"Emulator", "System"}, - {"Engineering", "Other"}, - {"Feed", "Network"}, - {"FileTools", "System"}, - {"FileTools", "Utility"}, - {"FileTransfer", "Network"}, - {"Filesystem", "System"}, - {"Finance", "Office"}, - {"FlowChart", "Office"}, - {"GTK", "Other"}, - {"GUIDesigner", "Development"}, - {"Geography", "Education"}, - {"Geography", "Science"}, - {"Geology", "Education"}, - {"Geology", "Science"}, - {"Geoscience", "Education"}, - {"Geoscience", "Science"}, - {"HamRadio", "Audio"}, - {"HamRadio", "Network"}, - {"HardwareSettings", "Settings"}, - {"History", "Education"}, - {"History", "Science"}, - {"Humanities", "Education"}, - {"Humanities", "Science"}, - {"IDE", "Development"}, - {"IRCClient", "Network"}, - {"ImageProcessing", "Education"}, - {"ImageProcessing", "Science"}, - {"InstantMessaging", "Network"}, - {"Java", "Other"}, - {"KidsGame", "Game"}, - {"Languages", "Education"}, - {"Languages", "Science"}, - {"Literature", "Education"}, - {"Literature", "Science"}, - {"LogicGame", "Game"}, - {"Maps", "Education"}, - {"Maps", "Science"}, - {"Maps", "Utility"}, - {"Math", "Education"}, - {"Math", "Science"}, - {"MedicalSoftware", "Education"}, - {"MedicalSoftware", "Science"}, - {"Monitor", "System"}, - {"Monitor", "Network"}, - {"Motif", "Other"}, - {"Music", "Education"}, - {"Music", "AudioVideo"}, - {"News", "Network"}, - {"P2P", "Network"}, - {"PDA", "Office"}, - {"PackageManager", "Settings"}, - {"Photography", "Graphics"}, - {"Photography", "Office"}, - {"Physics", "Education"}, - {"Physics", "Science"}, - {"Player", "Audio"}, - {"Player", "Video"}, - {"Player", "AudioVideo"}, - {"Presentation", "Office"}, - {"Profiling", "Development"}, - {"ProjectManagement", "Office"}, - {"ProjectManagement", "Development"}, - {"Publishing", "Graphics"}, - {"Publishing", "Office"}, - {"Qt", "Other"}, - {"Recorder", "Audio"}, - {"Recorder", "Video"}, - {"Recorder", "AudioVideo"}, - {"RemoteAccess", "Network"}, - {"RevisionControl", "Development"}, - {"Robotics", "Education"}, - {"Robotics", "Science"}, - {"RolePlaying", "Game"}, - {"Scanning", "Graphics"}, - {"Security", "Settings"}, - {"Security", "System"}, - {"Shooter", "Game"}, - {"Simulation", "Game"}, - {"Spirituality", "Education"}, - {"Spirituality", "Science"}, - {"Spirituality", "Utility"}, - {"Sports", "Education"}, - {"Sports", "Science"}, - {"SportsGame", "Game"}, - {"Spreadsheet", "Office"}, - {"StrategyGame", "Game"}, - {"Telephony", "Network"}, - {"TelephonyTools", "Utility"}, - {"TerminalEmulator", "System"}, - {"TextEditor", "Utility"}, - {"TextTools", "Utility"}, - {"Translation", "Development"}, - {"VideoConference", "Network"}, - {"Viewer", "Graphics"}, - {"Viewer", "Office"}, - {"WebBrowser", "Network"}, - {"WebDevelopment", "Development"}, - {"WebDevelopment", "Network"}, - {"WordProcessor", "Office"}, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: 2D based graphical application + N_("2DGraphics"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for viewing, creating, or processing graphics + N_("Graphics"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for viewing, creating, or processing 3-D graphics + N_("3DGraphics"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for viewing, creating, or processing graphics + N_("Graphics"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Accessibility + N_("Accessibility"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Settings applications + N_("Settings"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Accessibility + N_("Accessibility"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Small utility application, "Accessories" + N_("Utility"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An action game + N_("ActionGame"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A game + N_("Game"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application handles adult or explicit material + N_("Adult"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other + N_("Other"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Adventure style game + N_("AdventureGame"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A game + N_("Game"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A simple amusement + N_("Amusement"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other + N_("Other"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Arcade style game + N_("ArcadeGame"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A game + N_("Game"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tool to archive/backup data + N_("Archiving"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Small utility application, "Accessories" + N_("Utility"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Software to teach arts + N_("Art"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Software to teach arts + N_("Art"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Artificial Intelligence software + N_("Artificialtelligence"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Artificial Intelligence software + N_("Artificialtelligence"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Astronomy software + N_("Astronomy"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Astronomy software + N_("Astronomy"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to edit audio/video files + N_("AudioVideoEditing"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A video application + N_("Video"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to edit audio/video files + N_("AudioVideoEditing"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An audio application + N_("Audio"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to edit audio/video files + N_("AudioVideoEditing"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for presenting, creating, or processing multimedia (audio/video) + N_("AudioVideo"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Biology software + N_("Biology"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Biology software + N_("Biology"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Falling blocks game + N_("BlocksGame"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A game + N_("Game"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A board game + N_("BoardGame"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A game + N_("Game"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tool to build applications + N_("Building"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An application for development + N_("Development"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on COSMIC libraries + N_("COSMIC"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other + N_("Other"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A calculator + N_("Calculator"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Small utility application, "Accessories" + N_("Utility"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Calendar application + N_("Calendar"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An office type application + N_("Office"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A card game + N_("CardGame"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A game + N_("Game"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Chart application + N_("Chart"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An office type application + N_("Office"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A chat client + N_("Chat"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Network application such as a web browser + N_("Network"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Chemistry software + N_("Chemistry"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Chemistry software + N_("Chemistry"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A clock application/applet + N_("Clock"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Small utility application, "Accessories" + N_("Utility"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Computer Science software + N_("ComputerScience"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Computer Science software + N_("ComputerScience"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application that only works inside a terminal (text-based or command line application) + N_("ConsoleOnly"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other + N_("Other"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside:   + N_("Construction"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside:   + N_("Construction"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: E.g. an address book + N_("ContactManagement"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An office type application + N_("Office"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Important application, core to the desktop such as a file manager or a help browser + N_("Core"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other + N_("Other"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Data visualization software + N_("DataVisualization"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Data visualization software + N_("DataVisualization"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to manage a database + N_("Database"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for presenting, creating, or processing multimedia (audio/video) + N_("AudioVideo"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to manage a database + N_("Database"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An application for development + N_("Development"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to manage a database + N_("Database"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An office type application + N_("Office"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tool to debug applications + N_("Debugger"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An application for development + N_("Development"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Configuration tool for the GUI + N_("DesktopSettings"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Settings applications + N_("Settings"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A dial-up program + N_("Dialup"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Network application such as a web browser + N_("Network"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A dictionary + N_("Dictionary"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An office type application + N_("Office"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to burn a disc + N_("DiscBurning"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for presenting, creating, or processing multimedia (audio/video) + N_("AudioVideo"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Help or documentation + N_("Documentation"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other + N_("Other"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Economy software + N_("Economy"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Economy software + N_("Economy"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Electricity software + N_("Electricity"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Electricity software + N_("Electricity"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Electronics software, e.g. a circuit designer + N_("Electronics"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other + N_("Other"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Email application + N_("Email"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Network application such as a web browser + N_("Network"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Email application + N_("Email"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An office type application + N_("Office"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Emulator of another platform, such as a DOS emulator + N_("Emulator"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: System application, "System Tools" such as say a log viewer or network monitor + N_("System"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Emulator of another platform, such as a DOS emulator + N_("Emulator"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A game + N_("Game"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Engineering software, e.g. CAD programs + N_("Engineering"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other + N_("Other"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: RSS, podcast and other subscription based contents + N_("Feed"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Network application such as a web browser + N_("Network"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A file tool utility + N_("FileTools"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: System application, "System Tools" such as say a log viewer or network monitor + N_("System"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A file tool utility + N_("FileTools"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Small utility application, "Accessories" + N_("Utility"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Tools like FTP or P2P programs + N_("FileTransfer"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Network application such as a web browser + N_("Network"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A file system tool + N_("Filesystem"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: System application, "System Tools" such as say a log viewer or network monitor + N_("System"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to manage your finance + N_("Finance"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An office type application + N_("Office"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A flowchart application + N_("FlowChart"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An office type application + N_("Office"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on GTK+ libraries + N_("GTK"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other + N_("Other"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A GUI designer application + N_("GUIDesigner"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An application for development + N_("Development"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Geography software + N_("Geography"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Geography software + N_("Geography"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Geology software + N_("Geology"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Geology software + N_("Geology"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Geoscience software, GIS + N_("Geoscience"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Geoscience software, GIS + N_("Geoscience"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: HAM radio software + N_("HamRadio"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An audio application + N_("Audio"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: HAM radio software + N_("HamRadio"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Network application such as a web browser + N_("Network"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tool to manage hardware components, like sound cards, video cards or printers + N_("HardwareSettings"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Settings applications + N_("Settings"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: History software + N_("History"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: History software + N_("History"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Software for philosophy, psychology and other humanities + N_("Humanities"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Software for philosophy, psychology and other humanities + N_("Humanities"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: IDE application + N_("IDE"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An application for development + N_("Development"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An IRC client + N_("IRCClient"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Network application such as a web browser + N_("Network"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Image Processing software + N_("ImageProcessing"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Image Processing software + N_("ImageProcessing"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An instant messaging client + N_("InstantMessaging"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Network application such as a web browser + N_("Network"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on Java GUI libraries, such as AWT or Swing + N_("Java"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other + N_("Other"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A game for kids + N_("KidsGame"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A game + N_("Game"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Software to learn foreign languages + N_("Languages"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Software to learn foreign languages + N_("Languages"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Literature software + N_("Literature"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Literature software + N_("Literature"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Logic games like puzzles, etc + N_("LogicGame"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A game + N_("Game"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Software for viewing maps, navigation, mapping, GPS + N_("Maps"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Software for viewing maps, navigation, mapping, GPS + N_("Maps"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Software for viewing maps, navigation, mapping, GPS + N_("Maps"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Small utility application, "Accessories" + N_("Utility"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Math software + N_("Math"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Math software + N_("Math"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Medical software + N_("MedicalSoftware"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Medical software + N_("MedicalSoftware"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Monitor application/applet that monitors some resource or activity + N_("Monitor"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: System application, "System Tools" such as say a log viewer or network monitor + N_("System"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Monitor application/applet that monitors some resource or activity + N_("Monitor"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Network application such as a web browser + N_("Network"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on Motif libraries + N_("Motif"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other + N_("Other"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Musical software + N_("Music"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for presenting, creating, or processing multimedia (audio/video) + N_("AudioVideo"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Musical software + N_("Music"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A news reader or a news ticker + N_("News"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Network application such as a web browser + N_("Network"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A P2P program + N_("P2P"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Network application such as a web browser + N_("Network"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Tool to manage your PDA + N_("PDA"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An office type application + N_("Office"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A package manager application + N_("PackageManager"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Settings applications + N_("Settings"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Camera tools, etc. + N_("Photography"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for viewing, creating, or processing graphics + N_("Graphics"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Camera tools, etc. + N_("Photography"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An office type application + N_("Office"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Physics software + N_("Physics"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Physics software + N_("Physics"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to play audio/video files + N_("Player"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A video application + N_("Video"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to play audio/video files + N_("Player"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An audio application + N_("Audio"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to play audio/video files + N_("Player"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for presenting, creating, or processing multimedia (audio/video) + N_("AudioVideo"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Presentation software + N_("Presentation"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An office type application + N_("Office"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A profiling tool + N_("Profiling"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An application for development + N_("Development"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Project management application + N_("ProjectManagement"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An application for development + N_("Development"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Project management application + N_("ProjectManagement"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An office type application + N_("Office"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Desktop Publishing applications and Color Management tools + N_("Publishing"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for viewing, creating, or processing graphics + N_("Graphics"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Desktop Publishing applications and Color Management tools + N_("Publishing"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An office type application + N_("Office"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on Qt libraries + N_("Qt"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other + N_("Other"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to record audio/video files + N_("Recorder"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A video application + N_("Video"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to record audio/video files + N_("Recorder"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An audio application + N_("Audio"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to record audio/video files + N_("Recorder"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for presenting, creating, or processing multimedia (audio/video) + N_("AudioVideo"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tool to remotely manage your PC + N_("RemoteAccess"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Network application such as a web browser + N_("Network"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Applications like cvs or subversion + N_("RevisionControl"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An application for development + N_("Development"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Robotics software + N_("Robotics"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Robotics software + N_("Robotics"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A role playing game + N_("RolePlaying"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A game + N_("Game"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Tool to scan a file/text + N_("Scanning"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for viewing, creating, or processing graphics + N_("Graphics"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A security tool + N_("Security"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Settings applications + N_("Settings"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A security tool + N_("Security"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: System application, "System Tools" such as say a log viewer or network monitor + N_("System"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A shooter game + N_("Shooter"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A game + N_("Game"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A simulation game + N_("Simulation"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A game + N_("Game"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Religious and spiritual software, theology + N_("Spirituality"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Religious and spiritual software, theology + N_("Spirituality"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Religious and spiritual software, theology + N_("Spirituality"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Small utility application, "Accessories" + N_("Utility"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Sports software + N_("Sports"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Sports software + N_("Sports"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A sports game + N_("SportsGame"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A game + N_("Game"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A spreadsheet + N_("Spreadsheet"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An office type application + N_("Office"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A strategy game + N_("StrategyGame"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A game + N_("Game"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Telephony via PC + N_("Telephony"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Network application such as a web browser + N_("Network"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Telephony tools, to dial a number, manage PBX, ... + N_("TelephonyTools"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Small utility application, "Accessories" + N_("Utility"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A terminal emulator application + N_("TerminalEmulator"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: System application, "System Tools" such as say a log viewer or network monitor + N_("System"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A text editor + N_("TextEditor"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Small utility application, "Accessories" + N_("Utility"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A text tool utility + N_("TextTools"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Small utility application, "Accessories" + N_("Utility"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A translation tool + N_("Translation"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An application for development + N_("Development"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Video Conference software + N_("VideoConference"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Network application such as a web browser + N_("Network"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Tool to view e.g. a graphic or pdf file + N_("Viewer"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for viewing, creating, or processing graphics + N_("Graphics"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Tool to view e.g. a graphic or pdf file + N_("Viewer"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An office type application + N_("Office"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A web browser + N_("WebBrowser"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Network application such as a web browser + N_("Network"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tool for web developers + N_("WebDevelopment"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An application for development + N_("Development"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tool for web developers + N_("WebDevelopment"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Network application such as a web browser + N_("Network"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A word processor + N_("WordProcessor"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An office type application + N_("Office"), + }, }, // menu locations of depth 1 { - {"Accessibility"}, - {"Accessories"}, - {"Audio"}, - {"AudioVideo"}, - {"Development"}, - {"Editors"}, - {"Education"}, - {"Game"}, - {"Graphics"}, - {"Multimedia"}, - {"Network"}, - {"Office"}, - {"Other"}, - {"Science"}, - {"Screensavers"}, - {"Settings"}, - {"System"}, - {"Utility"}, - {"Video"}, - {"WINE"}, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Accessibility + N_("Accessibility"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An audio application + N_("Audio"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for presenting, creating, or processing multimedia (audio/video) + N_("AudioVideo"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An application for development + N_("Development"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software + N_("Education"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A game + N_("Game"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for viewing, creating, or processing graphics + N_("Graphics"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Network application such as a web browser + N_("Network"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An office type application + N_("Office"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other + N_("Other"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software + N_("Science"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Screensavers + N_("Screensavers"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Settings applications + N_("Settings"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: System application, "System Tools" such as say a log viewer or network monitor + N_("System"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Small utility application, "Accessories" + N_("Utility"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A video application + N_("Video"), + }, + { +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: WINE + N_("WINE"), + }, }, }; From 53e911f40a0accefb86671f6fc915e1b0f192756 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Thu, 26 Sep 2024 21:00:55 +0200 Subject: [PATCH 17/85] Drop menu info getter Was not the best idea. --- src/fdomenu.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 2b7184bce..886cc3943 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -504,7 +504,7 @@ static void help(bool to_stderr, int xit) { struct MenuNode { void sink_in(DesktopFilePtr df); - void print(std::ostream &prt_strm, const function &menuDecoResolver); + void print(std::ostream &prt_strm); //void collect_menu_names(const function &callback); @@ -669,7 +669,7 @@ int main(int argc, char **argv) { } - root.print(cout, [](const string&) {return DesktopFilePtr();}); + root.print(cout); return EXIT_SUCCESS; } @@ -735,12 +735,12 @@ void MenuNode::sink_in(DesktopFilePtr pDf) { static string ICON_FOLDER("folder"); string indent_hint(""); -void MenuNode::print(std::ostream &prt_strm, const function &menuDecoResolver) { +void MenuNode::print(std::ostream &prt_strm) { // translated name to icon and submenu (sorted by translated) map, tLessOp4Localized> sorted; for(auto& m: this->submenues) { auto& name = m.first; - auto deco = menuDecoResolver(name); + auto& deco = m.second.deco; sorted[deco ? deco->GetTranslatedName() : name] = make_pair(deco ? deco->Icon : ICON_FOLDER, &m.second); } for(auto& m: sorted) { @@ -753,7 +753,7 @@ void MenuNode::print(std::ostream &prt_strm, const functionprint(prt_strm, menuDecoResolver); + m.second.second->print(prt_strm); indent_hint.pop_back(); prt_strm << indent_hint << "}\n"; From 8f33dbe74a3e6c22da30ad028430383bb6dbc061 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Thu, 26 Sep 2024 21:19:12 +0200 Subject: [PATCH 18/85] Don't recurse for .directory fetching Legacy applications used to dump some unmaintained descriptions into such folders in local home. TBD. --- src/fdomenu.cc | 50 +++++++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 886cc3943..78cf7a707 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -397,25 +397,24 @@ struct tLessOp4Localized { } } locStringComper; -typedef void (*tFuncInsertInfo)(const string &absPath, intptr_t any); - class FsScan { private: std::set> reclog; function cb; string sFileNameExtFilter; + bool recursive; public: - FsScan(decltype(FsScan::cb) cb, const string &sFileNameExtFilter = "") { - this->cb = cb; - this->sFileNameExtFilter = sFileNameExtFilter; + FsScan(decltype(FsScan::cb) cb, const string &sFileNameExtFilter = "", + bool recursive = true) + : cb(cb), sFileNameExtFilter(sFileNameExtFilter), recursive(recursive) { } void scan(const string &sStartdir) { proc_dir_rec(sStartdir); } private: void proc_dir_rec(const string &path) { - cerr << "enter: " << path <d_name, &stbuf, 0)) continue; - if (S_ISDIR(stbuf.st_mode)) { + if (recursive && S_ISDIR(stbuf.st_mode)) { // link loop detection auto prev = make_pair(stbuf.st_ino, stbuf.st_dev); auto hint = reclog.insert(prev); @@ -641,28 +640,41 @@ int main(int argc, char **argv) { root.fixup(); +/* unordered_set filter; for(const auto& kv: root.menu_nodes_by_name) filter.insert(kv.first); +*/ auto dir_loader = FsScan([&](const string &fPath) { #warning Filter apparently broken auto df = DesktopFile::load_visible(fPath, shortLang /*, filter*/); - if (df) { - auto rng = root.menu_nodes_by_name.equal_range(df->Name); + if (!df) + return; + + // get all menu nodes of that name + auto rng = root.menu_nodes_by_name.equal_range(df->Name); + for (auto it=rng.first; it != rng.second; ++it) + { + if (!it->second->second.deco) + it->second->second.deco = df; + } + // No menus of that name? Try using the plain filename, some .directory files use the category as file name stem but differing in the Name attribute + if (rng.first == rng.second) + { + auto cpos = fPath.find_last_of("/"); + auto mcatName = fPath.substr(cpos + 1, fPath.length()-cpos-11); + rng = root.menu_nodes_by_name.equal_range(mcatName); + cerr << "altname: " << mcatName <second->second.deco = df; - if (rng.first == rng.second) // empty? Try using the plain filename, some menus descriptors use the category as file name but a differing Name attribute { - auto cpos = fPath.find_last_of("/"); - auto mcatName = fPath.substr(cpos + 1, fPath.length()-cpos-11); - rng = root.menu_nodes_by_name.equal_range(mcatName); - cerr << "altname: " << mcatName <second->second.deco = df; - } + if (!it->second->second.deco) + it->second->second.deco = df; + } } - }, ".directory"); + + }, ".directory", false); for (const auto &sdir : sharedirs) { dir_loader.scan(sdir + "/desktop-directories"); From a350749fe832130808cbec28d8a2949833c0222c Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Thu, 26 Sep 2024 21:23:01 +0200 Subject: [PATCH 19/85] clang-reformat fdomenu.cc --- src/fdomenu.cc | 223 ++++++++++++++++++++++++++----------------------- 1 file changed, 119 insertions(+), 104 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 78cf7a707..6a5e19c2e 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -45,13 +45,11 @@ #include #include - #include #include #include #include - using namespace std; #include "fdospecgen.h" @@ -212,7 +210,8 @@ vector &Tokenize(const string &in, const char *sep, return inOutVec; } -void replace_all(std::string& str, const std::string& from, const std::string& to) { +void replace_all(std::string &str, const std::string &from, + const std::string &to) { if (from.empty()) { return; } @@ -224,9 +223,10 @@ void replace_all(std::string& str, const std::string& from, const std::string& t } } -auto line_matcher = std::regex("^\\s*(Terminal|Type|Name|Exec|TryExec|Icon|Categories|NoDisplay)(" - "\\[(..)\\])?\\s*=\\s*(.*){0,1}?\\s*$", - std::regex_constants::ECMAScript); +auto line_matcher = std::regex( + "^\\s*(Terminal|Type|Name|Exec|TryExec|Icon|Categories|NoDisplay)(" + "\\[(..)\\])?\\s*=\\s*(.*){0,1}?\\s*$", + std::regex_constants::ECMAScript); struct DesktopFile : public tLintRefcounted { bool Terminal = false, IsApp = true, NoDisplay = false; @@ -242,19 +242,22 @@ struct DesktopFile : public tLintRefcounted { } string GetCommand() { - // let's try whether the command line is toxic, expecting stuff from https://specifications.freedesktop.org/desktop-entry-spec/latest/exec-variables.html + // let's try whether the command line is toxic, expecting stuff from + // https://specifications.freedesktop.org/desktop-entry-spec/latest/exec-variables.html if (string::npos == Exec.find('%')) return Exec; if (!TryExec.empty()) - return (Exec = TryExec); // copy over so we stick to it in case of later calls - for(const auto& bad: {"%F", "%U", "%f", "%u"}) + return (Exec = TryExec); // copy over so we stick to it in case of + // later calls + for (const auto &bad : {"%F", "%U", "%f", "%u"}) replace_all(Exec, bad, ""); replace_all(Exec, "%c", Name); replace_all(Exec, "%i", Icon); return Exec; } - DesktopFile(string filePath, const string &lang, const unordered_set& allowed_names) { - //cout << "filterlang: " << lang < &allowed_names) { + // cout << "filterlang: " << lang < load_visible(const string &path, const string &lang, const unordered_set &wanted_names = unordered_set()) { - //cerr << "load_visiblie: " << path << endl; + static lint_ptr load_visible( + const string &path, const string &lang, + const unordered_set &wanted_names = unordered_set()) { + // cerr << "load_visiblie: " << path << endl; auto ret = lint_ptr(); try { ret.reset(new DesktopFile(path, lang, wanted_names)); @@ -386,14 +391,12 @@ const char *rtls[] = { "ur", // urdu }; - - struct tLessOp4Localized { std::locale loc; // default locale - const std::collate& coll = std::use_facet >(loc); - bool operator() (const std::string& a, const std::string& b) { - return coll.compare (a.data(), a.data() + a.size(), - b.data(), b.data()+b.size()) < 0; + const std::collate &coll = std::use_facet>(loc); + bool operator()(const std::string &a, const std::string &b) { + return coll.compare(a.data(), a.data() + a.size(), b.data(), + b.data() + b.size()) < 0; } } locStringComper; @@ -430,9 +433,9 @@ class FsScan { if (pent->d_name[0] == '.') continue; // XXX: this triggers a problem, don't do it for now - //cerr << "before: " << pent->d_name << endl; - //pent->d_name[0xff] = '\0'; - //cerr << "after: " << pent->d_name << endl; + // cerr << "before: " << pent->d_name << endl; + // pent->d_name[0xff] = '\0'; + // cerr << "after: " << pent->d_name << endl; string fname(pent->d_name); @@ -455,7 +458,7 @@ class FsScan { if (!sFileNameExtFilter.empty() && !endsWith(fname, sFileNameExtFilter)) { - + continue; } @@ -505,17 +508,19 @@ struct MenuNode { void print(std::ostream &prt_strm); - //void collect_menu_names(const function &callback); + // void collect_menu_names(const function &callback); void fixup(); map submenues; - // using a map instead of set+logics adds a minor memory overhead but allows simple duplicate detection (adding user's version first) + // using a map instead of set+logics adds a minor memory overhead but allows + // simple duplicate detection (adding user's version first) unordered_map apps; - //unordered_set dont_add_mark; + // unordered_set dont_add_mark; - static unordered_multimap menu_nodes_by_name; + static unordered_multimap + menu_nodes_by_name; DesktopFilePtr deco; }; @@ -565,7 +570,7 @@ int main(int argc, char **argv) { for (auto pArg = argv + 1; pArg < argv + argc; ++pArg) { if (is_version_switch(*pArg)) { cout << "icewm-menu-fdo " VERSION ", Copyright 2015-2024 Eduard " - "Bloch, 2017-2023 Bert Gijsbers." + "Bloch, 2017-2023 Bert Gijsbers." << endl; exit(0); } else if (is_copying_switch(*pArg)) @@ -640,47 +645,47 @@ int main(int argc, char **argv) { root.fixup(); -/* - unordered_set filter; - for(const auto& kv: root.menu_nodes_by_name) - filter.insert(kv.first); -*/ - - auto dir_loader = FsScan([&](const string &fPath) { - #warning Filter apparently broken - auto df = DesktopFile::load_visible(fPath, shortLang /*, filter*/); - if (!df) - return; - - // get all menu nodes of that name - auto rng = root.menu_nodes_by_name.equal_range(df->Name); - for (auto it=rng.first; it != rng.second; ++it) - { - if (!it->second->second.deco) - it->second->second.deco = df; - } - // No menus of that name? Try using the plain filename, some .directory files use the category as file name stem but differing in the Name attribute - if (rng.first == rng.second) - { - auto cpos = fPath.find_last_of("/"); - auto mcatName = fPath.substr(cpos + 1, fPath.length()-cpos-11); - rng = root.menu_nodes_by_name.equal_range(mcatName); - cerr << "altname: " << mcatName < filter; + for(const auto& kv: root.menu_nodes_by_name) + filter.insert(kv.first); + */ + + auto dir_loader = FsScan( + [&](const string &fPath) { +#warning Filter apparently broken + auto df = DesktopFile::load_visible(fPath, shortLang /*, filter*/); + if (!df) + return; + + // get all menu nodes of that name + auto rng = root.menu_nodes_by_name.equal_range(df->Name); + for (auto it = rng.first; it != rng.second; ++it) { if (!it->second->second.deco) - it->second->second.deco = df; + it->second->second.deco = df; } - } - - }, ".directory", false); - + // No menus of that name? Try using the plain filename, some + // .directory files use the category as file name stem but differing + // in the Name attribute + if (rng.first == rng.second) { + auto cpos = fPath.find_last_of("/"); + auto mcatName = + fPath.substr(cpos + 1, fPath.length() - cpos - 11); + rng = root.menu_nodes_by_name.equal_range(mcatName); + cerr << "altname: " << mcatName << endl; + + for (auto it = rng.first; it != rng.second; ++it) { + if (!it->second->second.deco) + it->second->second.deco = df; + } + } + }, + ".directory", false); + for (const auto &sdir : sharedirs) { dir_loader.scan(sdir + "/desktop-directories"); } - root.print(cout); return EXIT_SUCCESS; @@ -691,10 +696,11 @@ void MenuNode::sink_in(DesktopFilePtr pDf) { auto add_sub_menues = [&](const t_menu_path &mp) { MenuNode *cur = this; - // work around the lack of reverse iterator, can fixed in C++14 with std::rbegin() conversion - if(!mp.size()) + // work around the lack of reverse iterator, can fixed in C++14 with + // std::rbegin() conversion + if (!mp.size()) return cur; - for (auto it = mp.end()-1; ; --it) { + for (auto it = mp.end() - 1;; --it) { #warning Insufficient, works only when the keywords have the "friendly" order /* @@ -703,10 +709,13 @@ void MenuNode::sink_in(DesktopFilePtr pDf) { cur->apps.erase(wrong_one); } - This gets overcomplicated. Could be solved by getting the menu paths for each keyword first, sorting them by length (descending), - then adding the deepest first and marking parent nodes as "visited" (another hashset or similar) to not add there again later. + This gets overcomplicated. Could be solved by getting the menu paths + for each keyword first, sorting them by length (descending), then + adding the deepest first and marking parent nodes as "visited" + (another hashset or similar) to not add there again later. - But then again, it's probably easier to just add them wherever they appear and use fixup() later. + But then again, it's probably easier to just add them wherever they + appear and use fixup() later. */ @@ -715,10 +724,10 @@ void MenuNode::sink_in(DesktopFilePtr pDf) { if (added.second) { menu_nodes_by_name.insert({key, added.first}); } - cur = & added.first->second; + cur = &added.first->second; - //cerr << "adding submenu: " << key << endl; - //cur = &cur->submenues[key]; + // cerr << "adding submenu: " << key << endl; + // cur = &cur->submenues[key]; if (mp.begin() == it) break; } @@ -726,7 +735,7 @@ void MenuNode::sink_in(DesktopFilePtr pDf) { }; for (const auto &cat : pDf->Categories) { - //cerr << "where does it fit? " << cat << endl; + // cerr << "where does it fit? " << cat << endl; t_menu_path refval = {cat.c_str()}; static auto comper = [](const t_menu_path &a, const t_menu_path &b) { // cerr << "left: " << *a.begin() << " vs. right: " << *b.begin() << @@ -749,21 +758,26 @@ string indent_hint(""); void MenuNode::print(std::ostream &prt_strm) { // translated name to icon and submenu (sorted by translated) - map, tLessOp4Localized> sorted; - for(auto& m: this->submenues) { - auto& name = m.first; - auto& deco = m.second.deco; - sorted[deco ? deco->GetTranslatedName() : name] = make_pair(deco ? deco->Icon : ICON_FOLDER, &m.second); - } - for(auto& m: sorted) { - auto& name = m.first; - prt_strm << indent_hint << "menu \"" << (m.second.second->deco ? - m.second.second->deco->GetTranslatedName() : name) << "\" " << - - ((m.second.second->deco && !m.second.second->deco->Icon.empty()) ? - m.second.second->deco->Icon : ICON_FOLDER) - << " {\n"; - + map, tLessOp4Localized> sorted; + for (auto &m : this->submenues) { + auto &name = m.first; + auto &deco = m.second.deco; + sorted[deco ? deco->GetTranslatedName() : name] = + make_pair(deco ? deco->Icon : ICON_FOLDER, &m.second); + } + for (auto &m : sorted) { + auto &name = m.first; + prt_strm << indent_hint << "menu \"" + << (m.second.second->deco + ? m.second.second->deco->GetTranslatedName() + : name) + << "\" " << + + ((m.second.second->deco && !m.second.second->deco->Icon.empty()) + ? m.second.second->deco->Icon + : ICON_FOLDER) + << " {\n"; + indent_hint += "\t"; m.second.second->print(prt_strm); indent_hint.pop_back(); @@ -771,17 +785,18 @@ void MenuNode::print(std::ostream &prt_strm) { prt_strm << indent_hint << "}\n"; } map sortedApps; - for(auto& p: this->apps) - sortedApps[p.second->GetTranslatedName()]=p.second; - - for(auto &p: sortedApps) { - auto& pi=p.second; - prt_strm << indent_hint << "prog \"" << pi->GetTranslatedName() << "\" " << pi->Icon << " " << pi->GetCommand() << "\n"; + for (auto &p : this->apps) + sortedApps[p.second->GetTranslatedName()] = p.second; + + for (auto &p : sortedApps) { + auto &pi = p.second; + prt_strm << indent_hint << "prog \"" << pi->GetTranslatedName() << "\" " + << pi->Icon << " " << pi->GetCommand() << "\n"; } } void MenuNode::fixup() { - //if (submenues.find("") != submenues.end()) {} + // if (submenues.find("") != submenues.end()) {} } // vim: set sw=4 ts=4 et: From c3260fc6bf645ec528d5160c8bcecc81ed2bcab9 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Thu, 26 Sep 2024 21:25:00 +0200 Subject: [PATCH 20/85] Stop requiring glib in CMake build --- src/CMakeLists.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c232973d0..f928273fd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -380,11 +380,6 @@ if(CONFIG_FRIBIDI) endif() endif() option(CONFIG_FDO_MENUS "Define to support freedesktop.org style menus" on) -if(CONFIG_FDO_MENUS) - set(hint "Freedesktop style menus enabled (-DCONFIG_FDO_MENUS=on) but libglib2.0-dev or similar package not found") - pkg_check_or_fail(gio gio-2.0 gio-unix-2.0 ${hint}) - pkg_check_or_fail(gio_unix gio-unix-2.0 ${hint}) -endif() option(DEBUG "Define if you want to debug IceWM" off) option(PRECON "Define to enable assertions in IceWM" off) From 8d3382ba44e4585c3b2f59583694bdc54816f703 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Thu, 26 Sep 2024 21:28:32 +0200 Subject: [PATCH 21/85] Common DBG macro to turn on/off debug notes --- src/fdomenu.cc | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 6a5e19c2e..fac4f1157 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -56,6 +56,12 @@ using namespace std; char const *ApplicationName; +#ifdef DEBUG +#define DBG(x) cerr << x << endl; +#else +#define DBG(x) +#endif + /* * Certain parts borrowed from apt-cacher-ng by its autor, either from older * branches (C++11 compatible) or development branch. @@ -310,7 +316,6 @@ struct DesktopFile : public tLintRefcounted { else continue; } else { // must be name - // cerr << "wtf? " << m[3].matched << "," << m[4] << endl; if (m[3].matched) NameLoc = m[4]; else { @@ -327,7 +332,6 @@ struct DesktopFile : public tLintRefcounted { static lint_ptr load_visible( const string &path, const string &lang, const unordered_set &wanted_names = unordered_set()) { - // cerr << "load_visiblie: " << path << endl; auto ret = lint_ptr(); try { ret.reset(new DesktopFile(path, lang, wanted_names)); @@ -417,7 +421,7 @@ class FsScan { private: void proc_dir_rec(const string &path) { - cerr << "enter: " << path << endl; + DBG("enter: " << path); auto pdir = opendir(path.c_str()); if (!pdir) @@ -432,10 +436,6 @@ class FsScan { while (nullptr != (pent = readdir(pdir))) { if (pent->d_name[0] == '.') continue; - // XXX: this triggers a problem, don't do it for now - // cerr << "before: " << pent->d_name << endl; - // pent->d_name[0xff] = '\0'; - // cerr << "after: " << pent->d_name << endl; string fname(pent->d_name); @@ -627,9 +627,7 @@ int main(int argc, char **argv) { auto desktop_loader = FsScan( [&](const string &fPath) { -#ifdef DEBUG - cerr << "reading: " << fPath << endl; -#endif + DBG("reading: " << fPath); auto df = DesktopFile::load_visible(fPath, shortLang); if (df) root.sink_in(df); @@ -637,9 +635,7 @@ int main(int argc, char **argv) { ".desktop"); for (const auto &sdir : sharedirs) { -#ifdef DEBUG - cerr << "checkdir: " << sdir << endl; -#endif + DBG("checkdir: " << sdir); desktop_loader.scan(sdir + "/applications"); } @@ -672,7 +668,7 @@ int main(int argc, char **argv) { auto mcatName = fPath.substr(cpos + 1, fPath.length() - cpos - 11); rng = root.menu_nodes_by_name.equal_range(mcatName); - cerr << "altname: " << mcatName << endl; + DBG("altname: " << mcatName); for (auto it = rng.first; it != rng.second; ++it) { if (!it->second->second.deco) From 1c85f93b2cbc8d9a8f7aacfe1d4a477ce31d9198 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Thu, 26 Sep 2024 21:56:16 +0200 Subject: [PATCH 22/85] Filter out duplicates where apps declare some intermediate categories as well --- src/fdomenu.cc | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index fac4f1157..a88b81b8b 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -543,14 +543,6 @@ int main(int argc, char **argv) { textdomain(PACKAGE); #endif -#warning FIXME, implement internal launcher which covers the damn %substitutions without glib -#if 0 - if (argc == 2 && ! endsWithSzAr(string(argv[1]), ".desktop")) - && launch(argv[1], argv + 2, argc - 2) { - return EXIT_SUCCESS; - } -#endif - vector sharedirs; const char *p; auto pUserShare = getenv("XDG_DATA_HOME"); @@ -698,8 +690,9 @@ void MenuNode::sink_in(DesktopFilePtr pDf) { return cur; for (auto it = mp.end() - 1;; --it) { -#warning Insufficient, works only when the keywords have the "friendly" order /* + #warning Insufficient, works only when the keywords have the "friendly" order + auto wrong_one = cur->apps.find(pDf->Name); if (wrong_one != cur->apps.end() && wrong_one->second == pDf) { cur->apps.erase(wrong_one); @@ -792,7 +785,31 @@ void MenuNode::print(std::ostream &prt_strm) { } void MenuNode::fixup() { - // if (submenues.find("") != submenues.end()) {} + + // descend deep and then check whether the same app has been added somewhere + // in the parent nodes, then remove it there + vector checkStack; + std::function go_deeper; + go_deeper = [&](MenuNode *cur) { + checkStack.push_back(cur); + + for (auto &sub : cur->submenues) + go_deeper(&sub.second); + + for (auto &appIt : cur->apps) { + for (auto ancestorIt = checkStack.begin(); + ancestorIt != checkStack.end() - 1; ++ancestorIt) { + auto otherIt = (*ancestorIt)->apps.find(appIt.second->Name); + if (otherIt != (*ancestorIt)->apps.end() && + otherIt->second == appIt.second) { + (*ancestorIt)->apps.erase(otherIt); + } + } + } + + checkStack.pop_back(); + }; + go_deeper(this); } // vim: set sw=4 ts=4 et: From 5b802bdc3d802ef8226a032a192acc27c83c8a43 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Thu, 26 Sep 2024 22:04:38 +0200 Subject: [PATCH 23/85] Add extra separator handling --- src/fdomenu.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index a88b81b8b..7eef04493 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -477,7 +477,7 @@ static void help(bool to_stderr, int xit) { "--seps \tPrint separators before and after contents\n" "--sep-before\tPrint separator before the contents\n" "--sep-after\tPrint separator only after contents\n" - "--no-sep-others\tNo separation of the 'Others' menu point\n" + "--no-sep-others\tLegacy, has no meaning\n" "--no-sub-cats\tNo additional subcategories, just one level of " "menues\n" "--flat\tDisplay all apps in one layer with category hints\n" @@ -674,8 +674,14 @@ int main(int argc, char **argv) { dir_loader.scan(sdir + "/desktop-directories"); } + if (add_sep_before) + cout << "separator" << endl; + root.print(cout); + if (add_sep_after) + cout << "separator" << endl; + return EXIT_SUCCESS; } From a306426793ae7c81db7ba2f62e9db161a30e273e Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Thu, 26 Sep 2024 22:30:59 +0200 Subject: [PATCH 24/85] Implemented execution in Terminal Restored terminal lookup code --- src/fdomenu.cc | 60 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 7eef04493..1ce839f76 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -62,6 +62,23 @@ char const *ApplicationName; #define DBG(x) #endif +// program options +bool add_sep_before = false; +bool add_sep_after = false; +bool no_sep_others = false; +bool no_sub_cats = false; +bool generic_name = false; +bool right_to_left = false; +bool flat_output = false; +bool match_in_section = false; +bool match_in_section_only = false; + +auto substr_filter = ""; +auto substr_filter_nocase = ""; +auto flat_sep = " / "; +char *terminal_command; +char *terminal_option; + /* * Certain parts borrowed from apt-cacher-ng by its autor, either from older * branches (C++11 compatible) or development branch. @@ -235,7 +252,7 @@ auto line_matcher = std::regex( std::regex_constants::ECMAScript); struct DesktopFile : public tLintRefcounted { - bool Terminal = false, IsApp = true, NoDisplay = false; + bool Terminal = false, IsApp = true, NoDisplay = false, CommandMassaged = false; string Name, NameLoc, Exec, TryExec, Icon; vector Categories; @@ -247,7 +264,17 @@ struct DesktopFile : public tLintRefcounted { return NameLoc; } - string GetCommand() { + const string& GetCommand() { + + if (CommandMassaged) + return Exec; + + CommandMassaged = true; + + if (Terminal && terminal_command) { + Exec = string(terminal_command) + " -e " + Exec; + } + // let's try whether the command line is toxic, expecting stuff from // https://specifications.freedesktop.org/desktop-entry-spec/latest/exec-variables.html if (string::npos == Exec.find('%')) @@ -255,12 +282,15 @@ struct DesktopFile : public tLintRefcounted { if (!TryExec.empty()) return (Exec = TryExec); // copy over so we stick to it in case of // later calls + for (const auto &bad : {"%F", "%U", "%f", "%u"}) replace_all(Exec, bad, ""); replace_all(Exec, "%c", Name); replace_all(Exec, "%i", Icon); + return Exec; } + DesktopFile(string filePath, const string &lang, const unordered_set &allowed_names) { // cout << "filterlang: " << lang < #endif -// program options -bool add_sep_before = false; -bool add_sep_after = false; -bool no_sep_others = false; -bool no_sub_cats = false; -bool generic_name = false; -bool right_to_left = false; -bool flat_output = false; -bool match_in_section = false; -bool match_in_section_only = false; - -auto substr_filter = ""; -auto substr_filter_nocase = ""; -auto flat_sep = " / "; -char *terminal_command; -char *terminal_option; - template struct auto_raii { T m_p; auto_raii(T xp) : m_p(xp) {} @@ -600,7 +613,8 @@ int main(int argc, char **argv) { } if (expand) delete[] expand; - } else if (GetArgument(value, "m", "match", pArg, argv + argc)) + } + else if (GetArgument(value, "m", "match", pArg, argv + argc)) substr_filter = value; else if (GetArgument(value, "M", "imatch", pArg, argv + argc)) substr_filter_nocase = value; @@ -615,6 +629,12 @@ int main(int argc, char **argv) { auto shortLang = string(msglang ? msglang : "").substr(0, 2); + const char* terminals[] = { terminal_option, getenv("TERMINAL"), TERM, + "urxvt", "alacritty", "roxterm", "xterm" }; + for (auto term : terminals) + if (term && (terminal_command = path_lookup(term)) != nullptr) + break; + MenuNode root; auto desktop_loader = FsScan( From 2d9f316a95ac2127610b5af22a6c0412920cc8cf Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Thu, 26 Sep 2024 22:39:31 +0200 Subject: [PATCH 25/85] Rename local DBG macro --- src/fdomenu.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 1ce839f76..cd5fc4001 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -57,9 +57,9 @@ using namespace std; char const *ApplicationName; #ifdef DEBUG -#define DBG(x) cerr << x << endl; +#define DBGMSG(x) cerr << x << endl; #else -#define DBG(x) +#define DBGMSG(x) #endif // program options @@ -434,7 +434,7 @@ class FsScan { private: void proc_dir_rec(const string &path) { - DBG("enter: " << path); + DBGMSG("enter: " << path); auto pdir = opendir(path.c_str()); if (!pdir) @@ -639,7 +639,7 @@ int main(int argc, char **argv) { auto desktop_loader = FsScan( [&](const string &fPath) { - DBG("reading: " << fPath); + DBGMSG("reading: " << fPath); auto df = DesktopFile::load_visible(fPath, shortLang); if (df) root.sink_in(df); @@ -647,7 +647,7 @@ int main(int argc, char **argv) { ".desktop"); for (const auto &sdir : sharedirs) { - DBG("checkdir: " << sdir); + DBGMSG("checkdir: " << sdir); desktop_loader.scan(sdir + "/applications"); } @@ -661,7 +661,7 @@ int main(int argc, char **argv) { auto dir_loader = FsScan( [&](const string &fPath) { -#warning Filter apparently broken + // XXX: Filter not working as intended, and probably pointless anyway because of the alternative checks, see below auto df = DesktopFile::load_visible(fPath, shortLang /*, filter*/); if (!df) return; @@ -680,7 +680,7 @@ int main(int argc, char **argv) { auto mcatName = fPath.substr(cpos + 1, fPath.length() - cpos - 11); rng = root.menu_nodes_by_name.equal_range(mcatName); - DBG("altname: " << mcatName); + DBGMSG("altname: " << mcatName); for (auto it = rng.first; it != rng.second; ++it) { if (!it->second->second.deco) From 5dc130693572386c7176303f4bcbcb207342d9f4 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Fri, 27 Sep 2024 00:38:28 +0200 Subject: [PATCH 26/85] Cleaning --- src/fdomenu.cc | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index cd5fc4001..48054606f 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -375,20 +375,6 @@ struct DesktopFile : public tLintRefcounted { using DesktopFilePtr = lint_ptr; -#if 0 - -#ifndef LPCSTR // mind the MFC -// easier to read... -typedef const char* LPCSTR; -#endif - -#include "ycollections.h" -#include -#include -#include -#include -#include -#endif template struct auto_raii { T m_p; From e3e326a84626d9902c2cb382635d2c807066627f Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Fri, 27 Sep 2024 00:50:37 +0200 Subject: [PATCH 27/85] Support --no-sub-cats --- src/fdomenu.cc | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 48054606f..fc29603e6 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -252,7 +252,8 @@ auto line_matcher = std::regex( std::regex_constants::ECMAScript); struct DesktopFile : public tLintRefcounted { - bool Terminal = false, IsApp = true, NoDisplay = false, CommandMassaged = false; + bool Terminal = false, IsApp = true, NoDisplay = false, + CommandMassaged = false; string Name, NameLoc, Exec, TryExec, Icon; vector Categories; @@ -264,7 +265,7 @@ struct DesktopFile : public tLintRefcounted { return NameLoc; } - const string& GetCommand() { + const string &GetCommand() { if (CommandMassaged) return Exec; @@ -274,7 +275,7 @@ struct DesktopFile : public tLintRefcounted { if (Terminal && terminal_command) { Exec = string(terminal_command) + " -e " + Exec; } - + // let's try whether the command line is toxic, expecting stuff from // https://specifications.freedesktop.org/desktop-entry-spec/latest/exec-variables.html if (string::npos == Exec.find('%')) @@ -282,7 +283,7 @@ struct DesktopFile : public tLintRefcounted { if (!TryExec.empty()) return (Exec = TryExec); // copy over so we stick to it in case of // later calls - + for (const auto &bad : {"%F", "%U", "%f", "%u"}) replace_all(Exec, bad, ""); replace_all(Exec, "%c", Name); @@ -375,7 +376,6 @@ struct DesktopFile : public tLintRefcounted { using DesktopFilePtr = lint_ptr; - template struct auto_raii { T m_p; auto_raii(T xp) : m_p(xp) {} @@ -599,8 +599,7 @@ int main(int argc, char **argv) { } if (expand) delete[] expand; - } - else if (GetArgument(value, "m", "match", pArg, argv + argc)) + } else if (GetArgument(value, "m", "match", pArg, argv + argc)) substr_filter = value; else if (GetArgument(value, "M", "imatch", pArg, argv + argc)) substr_filter_nocase = value; @@ -615,12 +614,13 @@ int main(int argc, char **argv) { auto shortLang = string(msglang ? msglang : "").substr(0, 2); - const char* terminals[] = { terminal_option, getenv("TERMINAL"), TERM, - "urxvt", "alacritty", "roxterm", "xterm" }; + const char *terminals[] = {terminal_option, getenv("TERMINAL"), TERM, + "urxvt", "alacritty", "roxterm", + "xterm"}; for (auto term : terminals) if (term && (terminal_command = path_lookup(term)) != nullptr) break; - + MenuNode root; auto desktop_loader = FsScan( @@ -647,7 +647,8 @@ int main(int argc, char **argv) { auto dir_loader = FsScan( [&](const string &fPath) { - // XXX: Filter not working as intended, and probably pointless anyway because of the alternative checks, see below + // XXX: Filter not working as intended, and probably pointless + // anyway because of the alternative checks, see below auto df = DesktopFile::load_visible(fPath, shortLang /*, filter*/); if (!df) return; @@ -703,7 +704,8 @@ void MenuNode::sink_in(DesktopFilePtr pDf) { for (auto it = mp.end() - 1;; --it) { /* - #warning Insufficient, works only when the keywords have the "friendly" order + #warning Insufficient, works only when the keywords have the + "friendly" order auto wrong_one = cur->apps.find(pDf->Name); if (wrong_one != cur->apps.end() && wrong_one->second == pDf) { @@ -745,6 +747,11 @@ void MenuNode::sink_in(DesktopFilePtr pDf) { }; for (const auto &w : valid_paths) { // cerr << "try paths: " << (uintptr_t)&w << endl; + + // ignore deeper paths, fallback to the main cats only + if (no_sub_cats && w.begin()->size() > 1) + continue; + auto rng = std::equal_range(w.begin(), w.end(), refval, comper); for (auto it = rng.first; it != rng.second; ++it) { auto &tgt = *add_sub_menues(*it); From ce23ebaf6c2827e704a2ac5196a9538707afefd2 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Fri, 27 Sep 2024 08:22:10 +0200 Subject: [PATCH 28/85] Stop storing lookup helper in global member Parts can be temporary, and collecting the data when constructing adds more complexity then doing this later when each menu is visited anyway. --- src/fdomenu.cc | 80 +++++++++++++++++--------------------------------- 1 file changed, 27 insertions(+), 53 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index fc29603e6..8009d3bb8 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -503,28 +503,19 @@ static void help(bool to_stderr, int xit) { * It's fetched on-demand with a supplied resolver function. */ struct MenuNode { - void sink_in(DesktopFilePtr df); - - void print(std::ostream &prt_strm); - - // void collect_menu_names(const function &callback); - - void fixup(); map submenues; - - // using a map instead of set+logics adds a minor memory overhead but allows - // simple duplicate detection (adding user's version first) + DesktopFilePtr deco; unordered_map apps; - // unordered_set dont_add_mark; - static unordered_multimap - menu_nodes_by_name; - DesktopFilePtr deco; + void sink_in(DesktopFilePtr df); + void print(std::ostream &prt_strm); + /** + * Returns a temporary list of visited node references. + */ + unordered_multimap fixup(); }; -decltype(MenuNode::menu_nodes_by_name) MenuNode::menu_nodes_by_name; - int main(int argc, char **argv) { // basic framework and environment initialization @@ -637,7 +628,7 @@ int main(int argc, char **argv) { desktop_loader.scan(sdir + "/applications"); } - root.fixup(); + auto menu_lookup = root.fixup(); /* unordered_set filter; @@ -654,10 +645,10 @@ int main(int argc, char **argv) { return; // get all menu nodes of that name - auto rng = root.menu_nodes_by_name.equal_range(df->Name); + auto rng = menu_lookup.equal_range(df->Name); for (auto it = rng.first; it != rng.second; ++it) { - if (!it->second->second.deco) - it->second->second.deco = df; + if (!it->second->deco) + it->second->deco = df; } // No menus of that name? Try using the plain filename, some // .directory files use the category as file name stem but differing @@ -666,12 +657,12 @@ int main(int argc, char **argv) { auto cpos = fPath.find_last_of("/"); auto mcatName = fPath.substr(cpos + 1, fPath.length() - cpos - 11); - rng = root.menu_nodes_by_name.equal_range(mcatName); + rng = menu_lookup.equal_range(mcatName); DBGMSG("altname: " << mcatName); for (auto it = rng.first; it != rng.second; ++it) { - if (!it->second->second.deco) - it->second->second.deco = df; + if (!it->second->deco) + it->second->deco = df; } } }, @@ -697,37 +688,14 @@ void MenuNode::sink_in(DesktopFilePtr pDf) { auto add_sub_menues = [&](const t_menu_path &mp) { MenuNode *cur = this; - // work around the lack of reverse iterator, can fixed in C++14 with - // std::rbegin() conversion + // work around the lack of reverse iterator, can be made easier in C++14 + // with std::rbegin() conversion + if (!mp.size()) return cur; for (auto it = mp.end() - 1;; --it) { - - /* - #warning Insufficient, works only when the keywords have the - "friendly" order - - auto wrong_one = cur->apps.find(pDf->Name); - if (wrong_one != cur->apps.end() && wrong_one->second == pDf) { - cur->apps.erase(wrong_one); - } - - This gets overcomplicated. Could be solved by getting the menu paths - for each keyword first, sorting them by length (descending), then - adding the deepest first and marking parent nodes as "visited" - (another hashset or similar) to not add there again later. - - But then again, it's probably easier to just add them wherever they - appear and use fixup() later. - - */ - auto key = (*it && **it) ? *it : "Other"; - auto added = cur->submenues.emplace(key, MenuNode()); - if (added.second) { - menu_nodes_by_name.insert({key, added.first}); - } - cur = &added.first->second; + cur = &cur->submenues[key]; // cerr << "adding submenu: " << key << endl; // cur = &cur->submenues[key]; @@ -803,7 +771,9 @@ void MenuNode::print(std::ostream &prt_strm) { } } -void MenuNode::fixup() { +unordered_multimap MenuNode::fixup() { + + unordered_multimap ret; // descend deep and then check whether the same app has been added somewhere // in the parent nodes, then remove it there @@ -812,8 +782,11 @@ void MenuNode::fixup() { go_deeper = [&](MenuNode *cur) { checkStack.push_back(cur); - for (auto &sub : cur->submenues) - go_deeper(&sub.second); + for (auto it = cur->submenues.begin(); it != cur->submenues.end(); + ++it) { + ret.insert(make_pair(it->first, &it->second)); + go_deeper(&it->second); + } for (auto &appIt : cur->apps) { for (auto ancestorIt = checkStack.begin(); @@ -829,6 +802,7 @@ void MenuNode::fixup() { checkStack.pop_back(); }; go_deeper(this); + return ret; } // vim: set sw=4 ts=4 et: From 57c03f6d79f89eae2b0346387248f46733f0bb30 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Fri, 27 Sep 2024 08:44:30 +0200 Subject: [PATCH 29/85] Fewer stat operations using readdir hints --- src/fdomenu.cc | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 8009d3bb8..d86758627 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -438,10 +438,23 @@ class FsScan { string fname(pent->d_name); + // Take the shortcuts where possible, no need to analyze directory + // properties for descending if that's known to be a plain file + // already. + if (pent->d_type == DT_REG) + goto process_reg_file; + + if (recursive && pent->d_type == DT_DIR) + goto process_dir; + if (fstatat(fddir, pent->d_name, &stbuf, 0)) continue; + if (S_ISREG(stbuf.st_mode)) + goto process_reg_file; + if (recursive && S_ISDIR(stbuf.st_mode)) { + process_dir: // link loop detection auto prev = make_pair(stbuf.st_ino, stbuf.st_dev); auto hint = reclog.insert(prev); @@ -452,9 +465,7 @@ class FsScan { } } - if (!S_ISREG(stbuf.st_mode)) - continue; - + process_reg_file: if (!sFileNameExtFilter.empty() && !endsWith(fname, sFileNameExtFilter)) { From b3e2db22bf439dad64a646614d4a3d8294175edc Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Fri, 27 Sep 2024 10:11:17 +0200 Subject: [PATCH 30/85] Match country-specific languages correctly --- src/fdomenu.cc | 101 +++++++++++++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 42 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index d86758627..f6125d021 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -247,14 +247,14 @@ void replace_all(std::string &str, const std::string &from, } auto line_matcher = std::regex( - "^\\s*(Terminal|Type|Name|Exec|TryExec|Icon|Categories|NoDisplay)(" - "\\[(..)\\])?\\s*=\\s*(.*){0,1}?\\s*$", + "^\\s*(Terminal|Type|Name|Exec|TryExec|Icon|Categories|NoDisplay)" + "(\\[((\\w\\w)(_\\w\\w)?)\\])?\\s*=\\s*(.*){0,1}?\\s*$", std::regex_constants::ECMAScript); struct DesktopFile : public tLintRefcounted { bool Terminal = false, IsApp = true, NoDisplay = false, CommandMassaged = false; - string Name, NameLoc, Exec, TryExec, Icon; + string Name, NameLoc, Exec, TryExec, Icon, GenericName, GenericNameLoc; vector Categories; /// Translate with built-in l10n if needed @@ -292,14 +292,36 @@ struct DesktopFile : public tLintRefcounted { return Exec; } - DesktopFile(string filePath, const string &lang, - const unordered_set &allowed_names) { + DesktopFile(string filePath, const string &langWanted) { // cout << "filterlang: " << lang <= 2) + langWantShort[0] = langWanted[0], langWantShort[1] = langWanted[1]; + std::ifstream dfile; dfile.open(filePath); string line; std::smatch m; bool reading = false; + + auto take_loc_best = [&langWanted, + &langWantShort](decltype(m[0]) &value, + decltype(m[0]) &langLong, + decltype(m[0]) &langShort, + string &out, string &outLoc) { + if (langWanted.size() > 3 && langLong == langWanted) { + // perfect hit always takes preference + outLoc = value; + } else if (langShort.matched && langShort == langWantShort) { + if (outLoc.empty()) + outLoc = value; + } else if (!langLong.matched) { + out = value; + } + }; + while (dfile) { line.clear(); std::getline(dfile, line); @@ -321,51 +343,45 @@ struct DesktopFile : public tLintRefcounted { std::regex_search(line, m, line_matcher); if (m.empty()) continue; - if (m[3].matched && m[3].compare(lang)) - continue; // for(auto x: m) cout << x << " - "; cout << " = " << m.size() << // endl; - if (m[1] == "Terminal") - Terminal = m[4].compare("true") == 0; - else if (m[1] == "NoDisplay") - NoDisplay = m[4].compare("true") == 0; - else if (m[1] == "Icon") - Icon = m[4]; - else if (m[1] == "Categories") { - Tokenize(m[4], ";", Categories); - } else if (m[1] == "Exec") { - Exec = m[4]; - } else if (m[1] == "TryExec") { - TryExec = m[4]; - } else if (m[1] == "Type") { - if (m[4] == "Application") + const auto &value = m[6], key = m[1], langLong = m[3], + langShort = m[4]; + // cerr << "val: " << value << ", key: " << key << ", langLong: " << + // langLong << ", langShort: " << langShort << endl; + + if (key == "Terminal") + Terminal = value.compare("true") == 0; + else if (key == "NoDisplay") + NoDisplay = value.compare("true") == 0; + else if (key == "Icon") + Icon = value; + else if (key == "Categories") + Tokenize(value, ";", Categories); + else if (key == "Exec") + Exec = value; + else if (key == "TryExec") + TryExec = value; + else if (key == "Type") { + if (value == "Application") IsApp = true; - else if (m[4] == "Directory") + else if (value == "Directory") IsApp = false; - else - continue; - } else { // must be name - if (m[3].matched) - NameLoc = m[4]; - else { - Name = m[4]; - // detect reading of a worthless desktop item ASAP - if (!allowed_names.empty() && - allowed_names.find(Name) != allowed_names.end()) - break; - } - } + } else if (key == "Name") + take_loc_best(value, langLong, langShort, Name, NameLoc); + else if (key == "GenericName") + take_loc_best(value, langLong, langShort, GenericName, + GenericNameLoc); } } - static lint_ptr load_visible( - const string &path, const string &lang, - const unordered_set &wanted_names = unordered_set()) { + static lint_ptr load_visible(const string &path, + const string &lang) { auto ret = lint_ptr(); try { - ret.reset(new DesktopFile(path, lang, wanted_names)); + ret.reset(new DesktopFile(path, lang)); if (ret->NoDisplay) ret.reset(); } catch (const std::exception &) { @@ -614,7 +630,8 @@ int main(int argc, char **argv) { } } - auto shortLang = string(msglang ? msglang : "").substr(0, 2); + auto justLang = string(msglang ? msglang : ""); + justLang = justLang.substr(0, justLang.find('.')); const char *terminals[] = {terminal_option, getenv("TERMINAL"), TERM, "urxvt", "alacritty", "roxterm", @@ -628,7 +645,7 @@ int main(int argc, char **argv) { auto desktop_loader = FsScan( [&](const string &fPath) { DBGMSG("reading: " << fPath); - auto df = DesktopFile::load_visible(fPath, shortLang); + auto df = DesktopFile::load_visible(fPath, justLang); if (df) root.sink_in(df); }, @@ -651,7 +668,7 @@ int main(int argc, char **argv) { [&](const string &fPath) { // XXX: Filter not working as intended, and probably pointless // anyway because of the alternative checks, see below - auto df = DesktopFile::load_visible(fPath, shortLang /*, filter*/); + auto df = DesktopFile::load_visible(fPath, justLang /*, filter*/); if (!df) return; From d688c1ff7f05430e77ca6d34983d90032e357837 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Fri, 27 Sep 2024 10:25:30 +0200 Subject: [PATCH 31/85] Printing of GenericName --- src/fdomenu.cc | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index f6125d021..edd0a86bd 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -247,7 +247,7 @@ void replace_all(std::string &str, const std::string &from, } auto line_matcher = std::regex( - "^\\s*(Terminal|Type|Name|Exec|TryExec|Icon|Categories|NoDisplay)" + "^\\s*(Terminal|Type|Name|GenericName|Exec|TryExec|Icon|Categories|NoDisplay)" "(\\[((\\w\\w)(_\\w\\w)?)\\])?\\s*=\\s*(.*){0,1}?\\s*$", std::regex_constants::ECMAScript); @@ -265,6 +265,13 @@ struct DesktopFile : public tLintRefcounted { return NameLoc; } + string &GetTranslatedGenericName() { + if (GenericNameLoc.empty()) { + GenericNameLoc = gettext(GenericName.c_str()); + } + return GenericNameLoc; + } + const string &GetCommand() { if (CommandMassaged) @@ -371,7 +378,7 @@ struct DesktopFile : public tLintRefcounted { IsApp = false; } else if (key == "Name") take_loc_best(value, langLong, langShort, Name, NameLoc); - else if (key == "GenericName") + else if (generic_name && key == "GenericName") take_loc_best(value, langLong, langShort, GenericName, GenericNameLoc); } @@ -794,8 +801,23 @@ void MenuNode::print(std::ostream &prt_strm) { for (auto &p : sortedApps) { auto &pi = p.second; - prt_strm << indent_hint << "prog \"" << pi->GetTranslatedName() << "\" " - << pi->Icon << " " << pi->GetCommand() << "\n"; + + prt_strm << indent_hint << "prog \""; + if (!generic_name) + prt_strm << pi->GetTranslatedName(); + else { + auto &gn = pi->GetTranslatedGenericName(); + if (gn.empty() || gn == pi->GetTranslatedName()) + prt_strm << pi->GetTranslatedName(); + else { + if (right_to_left) + prt_strm << " (" << gn << ")" << pi->GetTranslatedName(); + else + prt_strm << pi->GetTranslatedName() << " (" << gn << ")"; + } + } + + prt_strm << "\" " << pi->Icon << " " << pi->GetCommand() << "\n"; } } From a3e98c7bdbdf68a72e7bc008f8602932f3de6bd9 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Fri, 27 Sep 2024 10:25:50 +0200 Subject: [PATCH 32/85] Drop old Perl based converter (obsolete) --- contrib/conv_cat.pl | 158 -------------------------------------------- 1 file changed, 158 deletions(-) delete mode 100644 contrib/conv_cat.pl diff --git a/contrib/conv_cat.pl b/contrib/conv_cat.pl deleted file mode 100644 index cde590c01..000000000 --- a/contrib/conv_cat.pl +++ /dev/null @@ -1,158 +0,0 @@ -#!/usr/bin/perl - -use Data::Dumper; - -my @cats = sort( -"Accessibility", -"Settings", -"Screensavers", -"Accessories", -"Development", -"Education", -"Game", -"Graphics", -"Multimedia", -"Audio", -"Video", -"AudioVideo", -"Network", -"Office", -"Science", -"System", -"WINE", -"Editors", -"Utility", -"Other" -); - -print "// WARNING: this is an autogenerated file. Any change might be overwritten!\n"; -use strict; -#my %grps, my %secs, my %hints; -#$grps{"ANY"} = ''; - -my %mapping; -my @stable; -my @scats; -my %scat_lookup; - -sub uniq { - my %seen; - grep !$seen{$_}++, @_; -} - -for(<>) -{ - chomp; - my @toks = split(/\s*,\s*|\s*;\s*|\s+or\s+/); - # trim them - @toks = map { $_=~s/^\s*//; $_=~s/\s*$//; $_ } @toks; - #print Dumper(@toks); - push(@stable, \@toks); - # collect all seen subcategory strings - push(@scats, $toks[0]); - $scat_lookup{$toks[0]} = @toks[1..$#toks]; - #next if $sec eq "GTK" or $sec eq "Qt" or $sec eq "GNOME" or $sec eq "KDE" or $sec eq "XFCE" or $sec eq "Java" or $sec eq "ConsoleOnly"; - # key is sanitized name of the filter set or ANY for no filters - #my $subcat = shift(@toks); - # expand to all categories - #@toks = @cats unless @toks; - #push(@toks, "-") unless length(join("", @toks)); - ##$mapping{$key} = @toks; - #for my $maincat (uniq(@toks)) { -# next if ! length($maincat); -# if ($mapping{$subcat}) { -# push(@{$mapping{$subcat}}, $maincat); -# } -# else { -# $mapping{$subcat} = [$maincat] ; -# } -# } -} - -errrrror ab hier die referenzen mehrfach aufloesen bis alles nur noch auf maincats verweist - -# start of the list, the end of the list are -print " -#include \"intl.h\" -#include -namespace spec { - -using mstring = const char*; -using mapping = std::tuple; - -namespace mcat { - ".join("\n\t", map { " - // TRANSLATORS: This is a menu category name from https://specifications.freedesktop.org/menu-spec/menu-spec-1.0.html#category-registry . Please add spaces as needed but no double-quotes. - const auto x$_ = N_(\"$_\");" } @cats)." - - const mstring sall[] = { - ".join(",\n\t\t", map { "x$_" } @cats)." - }; -} - -namespace scat { - ".join("\n\t", map { " - // TRANSLATORS: This is a menu category name from https://specifications.freedesktop.org/menu-spec/menu-spec-1.0.html#category-registry . Please add spaces as needed but no double-quotes. - const auto x$_ = N_(\"$_\");" } @scats)." -} - -static mapping subcat_to_maincat[] = { -"; - -#print "const char* $_\[\] = { \"$grps{$_}\", \"|\", nullptr };\n" for(sort keys %grps); - -print " -// statically presorted list of sub category mapping. See fdomenu.cc for details. -"; - -my @scam; - -for my $x ( sort { ${$a}[0] cmp ${$b}[0]} (@stable)) { - my @l = @{$x}; - my $scat = shift(@l); - if (@l) { - for my $y (uniq( sort { $a cmp $b } (@l))) { - my $true_cat = $y; - while (! grep { $_ eq $y } @cats) { - - } - - if ( grep { $_ eq $y } @cats) { - push(@scam, "\t{ scat::x$scat, mcat::x$y /*, nullptr */ }"); - } - else { - my $true_cat = $y; - - push(@scam, "\t{ scat::x$scat, nullptr /*, scat::x$y */ }"); - } - } - } - else { - push(@scam, "\t{ scat::x$scat, nullptr /*, nullptr */ }"); - } -} -print join(",\n", uniq(@scam)); -print " - }; -} -"; - - -exit(0); - - -for my $subcatkey (sort(keys %mapping)) -{ - for my $mcatref (@{$mapping{$subcatkey}}) { - print "\t// TRANSLATORS: This is a menu category name from https://specifications.freedesktop.org/menu-spec/menu-spec-1.0.html#category-registry . Please add spaces as needed but no double-quotes.\n"; - print "\t{ \"$subcatkey\", \"$mcatref\" },\n"; - } - -# my $ptr = $secs{$_} ? "&$secs{$_}" : "nullptr"; -# print "// TRANSLATORS: This is a menu category name from https://specifications.freedesktop.org/menu-spec/menu-spec-1.0.html#category-registry . Please add spaces as needed but no double-quotes.".($hints{$_} ? " Context: $hints{$_}\n" : "\n"); -# print " { N_(\"$_\"), \"folder\", (const char**) $ptr}"; -# print $_ eq $cats[-1] ? "\n" : ",\n"; -} -print "}; -} -"; From 5c867d50ba571f196766e340a30d87d776dd3ceb Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Fri, 27 Sep 2024 12:21:41 +0200 Subject: [PATCH 33/85] Restore option to remove Other menu --- man/icewm-menu-fdo.pod | 2 +- src/fdomenu.cc | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/man/icewm-menu-fdo.pod b/man/icewm-menu-fdo.pod index ebb55d7e7..513ac7859 100644 --- a/man/icewm-menu-fdo.pod +++ b/man/icewm-menu-fdo.pod @@ -49,7 +49,7 @@ Print a trailing separator. =item B<--no-sep-others> -Don't print the C category last. +Don't print the C category, only official categories. =item B<--no-sub-cats> diff --git a/src/fdomenu.cc b/src/fdomenu.cc index edd0a86bd..d5ef67465 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -510,7 +510,7 @@ static void help(bool to_stderr, int xit) { "--seps \tPrint separators before and after contents\n" "--sep-before\tPrint separator before the contents\n" "--sep-after\tPrint separator only after contents\n" - "--no-sep-others\tLegacy, has no meaning\n" + "--no-sep-others\tDon't print uncategorized apps in Other menu\n" "--no-sub-cats\tNo additional subcategories, just one level of " "menues\n" "--flat\tDisplay all apps in one layer with category hints\n" @@ -795,6 +795,7 @@ void MenuNode::print(std::ostream &prt_strm) { prt_strm << indent_hint << "}\n"; } + map sortedApps; for (auto &p : this->apps) sortedApps[p.second->GetTranslatedName()] = p.second; @@ -825,6 +826,9 @@ unordered_multimap MenuNode::fixup() { unordered_multimap ret; + if (no_sep_others) + submenues.erase("Other"); + // descend deep and then check whether the same app has been added somewhere // in the parent nodes, then remove it there vector checkStack; From e4feb39e549c487a8bb03d52d29dbb74efa257d0 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Fri, 27 Sep 2024 12:22:01 +0200 Subject: [PATCH 34/85] Option to move lone entries to their parent menues. --- man/icewm-menu-fdo.pod | 19 +++++++++++--- src/fdomenu.cc | 58 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 67 insertions(+), 10 deletions(-) diff --git a/man/icewm-menu-fdo.pod b/man/icewm-menu-fdo.pod index 513ac7859..10a167ce6 100644 --- a/man/icewm-menu-fdo.pod +++ b/man/icewm-menu-fdo.pod @@ -63,6 +63,17 @@ Write the output to I. Use I to start a terminal emulator that supports the '-e' option. +=item B<-s>, B<--no-lone-app> + +Attempt to detect a single application with no other content in lower +submenus and move this one to the parent submenu. Limitations: this +looks only one level below, multiple moving is not supported yet. + +=item B<-S>, B<--no-lone-hint> + +Decorate app entries moved by the B<-s> option with a hint about the +original menu where it would be displayed otherwise. Implies B<-s>. + =item B<--flat> Display apps from all categories in one level with the title containing @@ -122,7 +133,9 @@ a comprehensive set of menus for easy access to F<.desktop> files. B or B are considered as suggested by XDG Base Directory Specification. -B may define a terminal emulator that supports the '-e' option. +B may define a terminal emulator that supports the '-e' +option. The option is ignored if the specified command could not be +found and a default is used instead. =head2 CONFORMING TO @@ -134,8 +147,8 @@ March 2011. =head2 CAVEATS The B program is only built when the L package -is configured with the B<--enable-menus-fdo> option, which requires the -B package dependency. +is configured with the B<--enable-menus-fdo> option and only works with +B<--enable-i18n> option. =head2 SEE ALSO diff --git a/src/fdomenu.cc b/src/fdomenu.cc index d5ef67465..d0e6d9936 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -72,6 +72,8 @@ bool right_to_left = false; bool flat_output = false; bool match_in_section = false; bool match_in_section_only = false; +bool no_only_child = false; +bool no_only_child_hint = false; auto substr_filter = ""; auto substr_filter_nocase = ""; @@ -246,10 +248,11 @@ void replace_all(std::string &str, const std::string &from, } } -auto line_matcher = std::regex( - "^\\s*(Terminal|Type|Name|GenericName|Exec|TryExec|Icon|Categories|NoDisplay)" - "(\\[((\\w\\w)(_\\w\\w)?)\\])?\\s*=\\s*(.*){0,1}?\\s*$", - std::regex_constants::ECMAScript); +auto line_matcher = + std::regex("^\\s*(Terminal|Type|Name|GenericName|Exec|TryExec|Icon|" + "Categories|NoDisplay)" + "(\\[((\\w\\w)(_\\w\\w)?)\\])?\\s*=\\s*(.*){0,1}?\\s*$", + std::regex_constants::ECMAScript); struct DesktopFile : public tLintRefcounted { bool Terminal = false, IsApp = true, NoDisplay = false, @@ -257,7 +260,7 @@ struct DesktopFile : public tLintRefcounted { string Name, NameLoc, Exec, TryExec, Icon, GenericName, GenericNameLoc; vector Categories; - /// Translate with built-in l10n if needed + /// Translate with built-in l10n if needed, and cache it string &GetTranslatedName() { if (NameLoc.empty()) { NameLoc = gettext(Name.c_str()); @@ -507,6 +510,9 @@ static void help(bool to_stderr, int xit) { "-g, --generic\tInclude GenericName in parentheses of progs\n" "-o, --output=FILE\tWrite the output to FILE\n" "-t, --terminal=NAME\tUse NAME for a terminal that has '-e'\n" + "-s, --no-lone-app\tMove lone elements to parent menu\n" + "-S, --no-lone-hint\tLike -s but append the original submenu's " + "title\n" "--seps \tPrint separators before and after contents\n" "--sep-before\tPrint separator before the contents\n" "--sep-after\tPrint separator only after contents\n" @@ -611,6 +617,10 @@ int main(int argc, char **argv) { match_in_section = match_in_section_only = true; else if (is_switch(*pArg, "g", "generic-name")) generic_name = true; + else if (is_switch(*pArg, "s", "no-lone-app")) + no_only_child = true; + else if (is_switch(*pArg, "S", "no-lone-hint")) + no_only_child = no_only_child_hint = true; else { char *value = nullptr, *expand = nullptr; if (GetArgument(value, "o", "output", pArg, argv + argc)) { @@ -770,11 +780,45 @@ string indent_hint(""); void MenuNode::print(std::ostream &prt_strm) { // translated name to icon and submenu (sorted by translated) map, tLessOp4Localized> sorted; + for (auto &m : this->submenues) { auto &name = m.first; auto &deco = m.second.deco; - sorted[deco ? deco->GetTranslatedName() : name] = - make_pair(deco ? deco->Icon : ICON_FOLDER, &m.second); + + // Special mode where we detect single elements, in which case the + // menu's apps are moved to ours and the menu is skipped from the + // printed set + if (no_only_child && m.second.apps.size() == 1 && + m.second.submenues.empty()) { + + auto &lone_app = m.second.apps.begin()->second; + auto &lone_app_key = m.second.apps.begin()->first; + + if (no_only_child_hint) { + // we smuggle this into translated name because it remains + // cached + const auto &nameLoc = deco ? deco->GetTranslatedName() : name; + auto &appNameLoc = lone_app->GetTranslatedName(); + + if (generic_name) { + auto &appGnameLoc = lone_app->GetTranslatedGenericName(); + if (nameLoc == appGnameLoc) + goto skip_origin_hint; + } + if (right_to_left) + appNameLoc = string("[") + nameLoc + "] " + appNameLoc; + else + appNameLoc += string(" [") + nameLoc + "]"; + + skip_origin_hint:; + } + + apps.emplace(lone_app_key, lone_app); + m.second.apps.clear(); + } else { + sorted[deco ? deco->GetTranslatedName() : name] = + make_pair(deco ? deco->Icon : ICON_FOLDER, &m.second); + } } for (auto &m : sorted) { auto &name = m.first; From 882a3f540ce19b93219ac5c9aed4b1494824fd5a Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Fri, 27 Sep 2024 18:58:26 +0200 Subject: [PATCH 35/85] Update CMake requirement to prevent warnings --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 84d8c81d0..e277b748d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.2) +cmake_minimum_required(VERSION 3.5) CMAKE_POLICY (SET CMP0053 NEW) PROJECT(ICEWM CXX C) From 62f7803377df5dcb7b6e71a21b5a9cb2943d1745 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Fri, 27 Sep 2024 18:59:11 +0200 Subject: [PATCH 36/85] Minor updates --- po/de.po | 5304 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 2704 insertions(+), 2600 deletions(-) diff --git a/po/de.po b/po/de.po index 44a5729f4..e34735b44 100644 --- a/po/de.po +++ b/po/de.po @@ -1,13 +1,14 @@ # German messages for IceWM # Copyright (C) 2000-2001 Marko Macek # Mathias Hasselmann , 2000. +# Gemineo , 2024. # msgid "" msgstr "" "Project-Id-Version: icewm 1.2.26\n" "Report-Msgid-Bugs-To: https://github.com/bbidulock/icewm/issues\n" -"POT-Creation-Date: 2024-06-16 14:27+0200\n" -"PO-Revision-Date: 2024-02-29 14:42+0000\n" +"POT-Creation-Date: 2024-09-27 18:13+0200\n" +"PO-Revision-Date: 2024-09-27 18:55+0200\n" "Last-Translator: Gemineo \n" "Language-Team: German \n" @@ -16,99 +17,42 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.9.1\n" +"X-Generator: Gtranslator 46.1\n" "X-Language: de_DE\n" "X-Source-Language: C\n" -#: src/aapm.cc:113 -#, c-format -msgid "Can't open the APM device %s" -msgstr "Kann OSS-Gerät %s nicht öffnen" - -#: src/aapm.cc:121 src/aapm.cc:139 -#, c-format -msgid "Can't ioctl the APM device %s" -msgstr "APM-Gerät %s kann nicht über ioctl gesteuert werden" - -#: src/aapm.cc:169 -#, c-format -msgid "Unknown format used by APM device %s (%d)." -msgstr "Unbekanntes Format von APM-Gerät %s (%d) verwendet." - -#: src/aapm.cc:201 src/aapm.cc:473 src/aapm.cc:632 src/aapm.cc:758 -msgid " - Power" -msgstr " - Energie" - -#: src/aapm.cc:203 src/aapm.cc:476 src/aapm.cc:635 -msgid "P" -msgstr "P" - -#: src/aapm.cc:207 src/aapm.cc:450 src/aapm.cc:615 src/aapm.cc:726 -msgid " - Charging" -msgstr " - Laden" - -#: src/aapm.cc:209 src/aapm.cc:452 src/aapm.cc:617 -msgid "C" -msgstr "C" - -#: src/aapm.cc:454 -msgid " - Full" -msgstr " - Voll" - -#: src/aapm.cc:940 -#, c-format -msgid "power:\t%s" -msgstr "Energie:\t%s" - -#: src/aclock.cc:195 -msgid "CLOCK" -msgstr "UHR" - -#: src/aclock.cc:201 -msgid "Date" -msgstr "Datum" - -#: src/aclock.cc:202 src/themes.cc:83 -msgid "Default" -msgstr "Standard" - -#: src/aclock.cc:203 src/acpustatus.cc:912 src/amailbox.cc:964 -#: src/amemstatus.cc:264 -msgid "_Disable" -msgstr "_Deaktivieren" - -#: src/aclock.cc:204 -msgid "_UTC" -msgstr "_UTC" - -#. TRANSLATORS: Please translate the string "C" into "Celsius Temperature" in your language. -#. TRANSLATORS: Please make sure the translated string could be shown in your non-utf8 locale. -#: src/acpustatus.cc:348 -msgid "°C" -msgstr "°C" - -#: src/acpustatus.cc:552 -#, c-format -msgid "CPU %s Load: %3.2f %3.2f %3.2f, %u" -msgstr "CPU %s Auslastung: %3.2f %3.2f %3.2f, %u" - -#: src/acpustatus.cc:558 -#, c-format +#: src/wmapp.cc:1629 msgid "" "\n" -"Ram (free): %5.3f (%.3f) G" +" --debug Print generic debug messages.\n" +" --debug-z Print debug messages regarding window stacking.\n" msgstr "" "\n" -"RAM (frei):\t%5.3f (%.3f) G" +" --debug Gibt generische Debug-Nachrichten aus.\n" +" --debug-z Gibt Debug-Nachrichten mit dem Blick auf window " +"stacking aus.\n" -#: src/acpustatus.cc:563 -#, c-format +#: src/wmapp.cc:1637 msgid "" "\n" -"Swap (free): %.3f (%.3f) G" +" -a, --alpha Use a 32-bit visual for translucency.\n" +" -c, --config=FILE Load preferences from FILE.\n" +" -t, --theme=FILE Load theme from FILE.\n" +" -s, --splash=IMAGE Briefly show IMAGE on startup.\n" +" -p, --postpreferences Print preferences after all processing.\n" +" --rewrite-preferences Update an existing preferences file.\n" +" --trace=conf,icon Trace paths used to load configuration.\n" msgstr "" "\n" -"Swap (frei):\t%.3f (%.3f) G" +" -a, --alpha Verwendet einen 32Bit-Sichtkontakt zur Lichtdurchlässigkeit.\n" +" -c, --config=DATEI Einstellungen aus DATEI laden.\n" +" -t, --theme=DATEI Theme aus DATEI laden.\n" +" -s, --spash=BILD Kurz BILD beim Start anzeigen.\n" +" -p, --postpreferences Einstellungen nach der ganzen Verarbeitung " +"ausgeben.\n" +" --rewrite-preferences Vorhandene Einstellungsdatei aktualisieren.\n" +" --trace=conf,icon Pfade zeichnen, die zum Laden der Konfiguration " +"verwendet werden.\n" #: src/acpustatus.cc:571 #, c-format @@ -128,13 +72,31 @@ msgstr "" "\n" "CPU-Takt:\t%.3f GHz" -#: src/acpustatus.cc:607 src/acpustatus.cc:907 -msgid "CPU" -msgstr "CPU" +#: src/icesm.cc:85 +msgid "" +"\n" +"Debugging options:\n" +" -v, --valgrind Let \"/usr/bin/valgrind\" run icewm.\n" +" Thoroughly examines the execution of icewm.\n" +" -g, --catchsegv Let \"/usr/bin/catchsegv\" run icewm.\n" +" Gives a backtrace if icewm segfaults.\n" +msgstr "" +"\n" +"Debugging-Optionen:\n" +" -v, --valgrind Lässt \"/usr/bin/valgrind\" icewm ausführen.\n" +" Untersucht gründlich die Ausführung von icewm.\n" +" -g, --catchsegv Lässt \"/usr/bin/catchsegv\" icewm ausführen.\n" +" Gibt einen Backtrace aus, wenn bei icewm eine " +"Schutzverletzung auftritt.\n" -#: src/acpustatus.cc:607 -msgid "Load: " -msgstr "Last: " +#: src/acpustatus.cc:558 +#, c-format +msgid "" +"\n" +"Ram (free): %5.3f (%.3f) G" +msgstr "" +"\n" +"RAM (frei):\t%5.3f (%.3f) G" #: src/acpustatus.cc:622 #, c-format @@ -145,2157 +107,2152 @@ msgstr "" "\n" "Ram (Benutzer)%5.3f (%.3f) G" -#: src/acpustatus.cc:908 -#, c-format -msgid "CPU%d" -msgstr "CPU%d" - -#: src/acpustatus.cc:914 -msgid "_Combine" -msgstr "_Kombinieren" - -#: src/acpustatus.cc:916 -msgid "_Separate" -msgstr "_Aufteilen" - -#: src/akeyboard.cc:78 src/icesm.cc:468 src/wmmenu.cc:503 +#: src/acpustatus.cc:563 #, c-format -msgid "%s exited with status %d." -msgstr "%s endete mit Status %d." +msgid "" +"\n" +"Swap (free): %.3f (%.3f) G" +msgstr "" +"\n" +"Swap (frei):\t%.3f (%.3f) G" -#: src/akeyboard.cc:81 src/icesm.cc:474 src/icesm.cc:628 src/wmmenu.cc:506 -#, c-format -msgid "%s was killed by signal %d." -msgstr "%s wurde durch Signal %d getötet." +#: src/wmapp.cc:1623 +msgid "" +" --client-id=ID Client id to use when contacting session manager.\n" +msgstr "" +" --client-id=ID zu verwendende Client-ID, wenn der Sitzungs-Manager " +"kontaktiert wird.\n" -#: src/akeyboard.cc:94 -msgid "rules:" -msgstr "Regeln:" +#: src/icesm.cc:69 +msgid "" +" -c, --config=FILE Let IceWM load preferences from FILE.\n" +" -t, --theme=FILE Let IceWM load the theme from FILE.\n" +"\n" +" -d, --display=NAME Use NAME to connect to the X server.\n" +" -a, --alpha Use a 32-bit visual for translucency.\n" +" --sync Synchronize communication with X11 server.\n" +"\n" +" -i, --icewm=FILE Use FILE as the IceWM window manager.\n" +" -o, --output=FILE Redirect all output to FILE.\n" +"\n" +" -b, --nobg Do not start icewmbg.\n" +" -n, --notray Do not start icewmtray.\n" +" -s, --sound Also start icesound.\n" +msgstr "" +" -c, --config=DATEI Lässt IceWM Prioritäten aus DATEI laden.\n" +" -t, --theme=DATEI Lässt IceWM das Thema aus DATEI laden.\n" +"\n" +" -d, --display=NAME Verwendet NAME zur Verbindung mit dem X-Server.\n" +" -a, --alpha Verwendet einen 32-Bit-Sichtkontakt zur " +"Lichtdurchlässigkeit.\n" +" --sync Synchronisierung der Kommunikation mit dem X11-" +"Server.\n" +"\n" +" -i, --icewm=DATEI Verwendet DATEI als IceWM Window Manager.\n" +" -o, --output=DATEI Alle Ausgaben in DATEI umleiten\n" +"\n" +" -b, --nobg Nicht icewmbg starten.\n" +" -n, --notray Nicht icewmtray starten.\n" +" -s, --sound Auch icesound starten.\n" -#: src/akeyboard.cc:95 -msgid "model:" -msgstr "Modell:" +#: src/yxapp.cc:1008 +msgid "" +" -d, --display=NAME NAME of the X server to use.\n" +" --sync Synchronize X11 commands.\n" +msgstr "" +" -d, --display=NAME NAME des zu verwendenden X-Servers.\n" +" --sync Synchronisation von X11-Befehlen.\n" -#: src/akeyboard.cc:96 -msgid "layout:" -msgstr "Layout:" +#: src/wmapp.cc:1654 +msgid " -i, --install=THEME Install THEME from extra or 'list'.\n" +msgstr " -i, --install=THEME Installiere Thema von außerhalb, oder 'list'.\n" -#: src/akeyboard.cc:97 -msgid "options:" -msgstr "Optionen:" +#: src/icetray.cc:220 +msgid "" +" -n, --notify Notify parent process by sending signal USR1.\n" +" --display=NAME Use NAME to connect to the X server.\n" +" --sync Synchronize communication with X11 server.\n" +"\n" +" -c, --config=FILE Load preferences from FILE.\n" +" -t, --theme=FILE Load the theme from FILE.\n" +msgstr "" +" -n, --notify Eltern-Prozess mit dem Senden des Signals USR1 " +"benachrichtigen.\n" +" --display=NAME Verwenden von NAME um sich mit dem X-Server zu " +"verbinden.\n" +" --sync Synchronisation der Kommunikation mit dem X11-Server.\n" +"\n" +" -c, --config=DATEI Laden der Prioritäten aus DATEI.\n" +" -t, --theme=DATEI Laden des Themes aus DATEI.\n" -#: src/akeyboard.cc:153 -msgid "Keyboard" -msgstr "Tastatur" +#: src/wmapp.cc:1648 +msgid " -o, --output=FILE Redirect all output to FILE.\n" +msgstr " -o, --output=DATEI Gesamte Ausgabe an DATEI umleiten.\n" -#: src/amailbox.cc:64 -#, c-format -msgid "Invalid mailbox protocol: \"%s\"" -msgstr "Unbekanntes E-Mail-Protokoll: \"%s\"" +#: src/aapm.cc:207 src/aapm.cc:450 src/aapm.cc:615 src/aapm.cc:726 +msgid " - Charging" +msgstr " - Laden" -#: src/amailbox.cc:66 -#, c-format -msgid "Invalid mailbox path: \"%s\"" -msgstr "Ungültiger Mailbox-Pfad: \"%s\"" +#: src/aapm.cc:454 +msgid " - Full" +msgstr " - Voll" -#: src/amailbox.cc:140 -#, c-format -msgid "DNS name lookup failed for %s" -msgstr "DNS-Namenssuche fehlgeschlagen für %s" +#: src/aapm.cc:201 src/aapm.cc:473 src/aapm.cc:632 src/aapm.cc:758 +msgid " - Power" +msgstr " - Energie" -#: src/amailbox.cc:156 -#, c-format -msgid "Invalid mailbox port: \"%s\"" -msgstr "Ungültiger Mailbox-Port: \"%s\"" - -#: src/amailbox.cc:314 -#, c-format -msgid "Could not connect to %s: %s" -msgstr "Keine Verbindung möglich zu %s: %s" - -#: src/amailbox.cc:334 -#, c-format -msgid "Failed to find %s command" -msgstr "Kommando %s kann nicht gefunden werden" - -#: src/amailbox.cc:363 src/wmmenu.cc:471 src/wmmenu.cc:488 src/yapp.cc:433 -#, c-format -msgid "Failed to execute %s" -msgstr "Fehler beim Ausführen von %s" - -#: src/amailbox.cc:447 -#, c-format -msgid "Write to socket failed: %s" -msgstr "Schreiben in Socket fehlgeschlagen: %s" - -#: src/amailbox.cc:694 -#, c-format -msgid "Using MailBox \"%s\"\n" -msgstr "Benutze Postfach: \"%s\"\n" - -#: src/amailbox.cc:801 -msgid "Suspended" -msgstr "Angehalten" +#: src/icesm.cc:513 +msgid "" +" IceWM crashed for the second time in 10 seconds. \n" +" Do you wish to:\n" +"\n" +"\t1: Restart IceWM?\n" +"\t2: Abort this session?\n" +"\t3: Run a terminal?\n" +msgstr "" +" IceWM stürzte das zweite Mal in 10 sekunden ab. \n" +" Möchten Sie:\n" +"\n" +"1: IceWM neu starten?\n" +"2: Diese Sitzung abbrechen?\n" +"3: Ein Terminal laufen lassen?\n" -#: src/amailbox.cc:805 -msgid "Error checking mailbox." -msgstr "Fehler beim Prüfen des Postfachs." +#: src/ysmapp.cc:95 +msgid "$USER or $LOGNAME not set?" +msgstr "Sind die Umgebungsvariablen $USER oder $LOGNAME nicht gesetzt?" #: src/amailbox.cc:812 #, c-format msgid "%ld mail message, %ld unread." msgstr "%ld E-Mail-Nachricht, %ld ungelesen." -#: src/amailbox.cc:813 -#, c-format -msgid "%ld mail messages, %ld unread." -msgstr "%ld E-Mail-Nachrichten, %ld ungelesen." - #: src/amailbox.cc:819 #, c-format msgid "%ld mail message." msgstr "%ld E-Mail-Nachricht." +#: src/amailbox.cc:813 +#, c-format +msgid "%ld mail messages, %ld unread." +msgstr "%ld E-Mail-Nachrichten, %ld ungelesen." + #: src/amailbox.cc:820 #, c-format msgid "%ld mail messages." msgstr "%ld E-Mail-Nachrichten." -#: src/amailbox.cc:961 -msgid "MAIL" -msgstr "MAIL" - -#: src/amailbox.cc:963 -msgid "_Check" -msgstr "_Abholen" - -#: src/amailbox.cc:965 -msgid "_Suspend" -msgstr "_Unterbrechen" - -#: src/amemstatus.cc:144 -msgid "GB" -msgstr "GB" - -#: src/amemstatus.cc:148 -msgid "MB" -msgstr "MB" - -#: src/amemstatus.cc:152 -msgid "kB" -msgstr "kB" - -#: src/amemstatus.cc:156 -msgid "bytes" -msgstr "Bytes" - -#: src/amemstatus.cc:176 -msgid "Memory Total: " -msgstr "Speicher Total: " - -#: src/amemstatus.cc:177 -msgid "Free: " -msgstr "Frei: " - -#: src/amemstatus.cc:178 -msgid "Cached: " -msgstr "Cache: " +#: src/wmwinmenu.cc:100 +#, c-format +msgid "%lu. Workspace %-.32s" +msgstr "%lu. Arbeitsbereich %-.32s" -#: src/amemstatus.cc:179 -msgid "Buffers: " -msgstr "Puffer: " +#: src/wmapp.cc:1723 +#, c-format +msgid "%s configuration directories:\n" +msgstr "%s Konfigurationsverzeichnisse:\n" -#: src/amemstatus.cc:180 -msgid "User: " -msgstr "Benutzer: " +#: src/wmapp.cc:1808 +#, c-format +msgid "%s configured options:%s\n" +msgstr "%s konfigurierte Optionen: %s\n" -#: src/amemstatus.cc:262 -msgid "MEM" -msgstr "SPEICHER" +#: src/akeyboard.cc:78 src/icesm.cc:468 src/wmmenu.cc:507 +#, c-format +msgid "%s exited with status %d." +msgstr "%s endete mit Status %d." -#: src/apppstatus.cc:268 +#: src/akeyboard.cc:81 src/icesm.cc:474 src/icesm.cc:628 src/wmmenu.cc:510 #, c-format -msgid "" -"Interface %s:\n" -" Current rate (in/out):\t%li %s/%li %s\n" -" Current average (in/out):\t%lli %s/%lli %s\n" -" Transferred (in/out):\t%lli %s/%lli %s\n" -" Online time:\t%ld:%02ld:%02ld%s%s" -msgstr "" -"Schnittstelle %s:\n" -" Aktueller Durchsatz (ein/aus):\t%li %s/%li %s\n" -" Aktueller Durchschnitt (ein/aus):\t%lli %s/%lli %s\n" -" Gesamt (ein/aus):\t%lli %s/%lli %s\n" -" Onlinezeit:\t%ld:%02ld:%02ld%s%s" +msgid "%s was killed by signal %d." +msgstr "%s wurde durch Signal %d getötet." -#: src/apppstatus.cc:284 -msgid "disconnected" -msgstr "Verbindung getrennt" +#: src/icesound.cc:329 +#, c-format +msgid "%s: Invalid number of channels" +msgstr "%s: Ungültige Anzahl an Kanälen" -#: src/apppstatus.cc:284 -msgid "down" -msgstr "abwärts" +#: src/yapp.cc:299 +#, c-format +msgid "%s: select failed" +msgstr "%s: Auswahl fehlgeschlagen" -#: src/apppstatus.cc:705 -msgid "NET" -msgstr "NETZ" +#: src/wmmenu.cc:516 +#, c-format +msgid "'%s' produces no output" +msgstr "'%s' produziert keine Ausgabe" -#: src/aworkspaces.cc:685 src/wmstatus.cc:204 -msgid "Workspace: " -msgstr "Arbeitsbereich: " +#: src/wmmenu.cc:502 +#, c-format +msgid "'%s' timed out!" +msgstr "Zeitüberschreitung bei '%s'!" -#: src/decorate.cc:132 -msgid "Tabs" -msgstr "Registerkarte" +#: src/wmabout.cc:29 +msgid "(C)" +msgstr "©" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Graphics -#: src/fdospecgen.h:43 +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: 2D based graphical application +#: src/fdospecgen.h:146 src/fdospecgen.h:178 src/fdospecgen.h:196 msgid "2DGraphics" msgstr "2D-Grafiken" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Graphics -#: src/fdospecgen.h:45 +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for viewing, creating, or processing 3-D graphics +#: src/fdospecgen.h:202 msgid "3DGraphics" msgstr "3D-Grafiken" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Settings or Utility -#: src/fdospecgen.h:47 src/fdospecgen.h:49 +#: src/wmapp.cc:1291 src/yxapp.cc:1050 +msgid "" +msgstr "" + +# +#: src/wmapp.cc:91 +msgid "A window manager is already running, use --replace to replace it" +msgstr "Ein Fenstermanager ist bereits aktiv, zum Ersetzen --replace verwenden" + +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Accessibility +#: src/fdospecgen.h:208 src/fdospecgen.h:214 src/fdospecgen.h:1154 msgid "Accessibility" msgstr "Erreichbarkeit" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:51 -msgid "Accessories" -msgstr "Zubehör" +#: src/icesh.cc:4166 +#, c-format +msgid "Action `%s' requires at least %d arguments." +msgstr "Aktion `%s` benötigt mindestens %d Argumente." -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game -#: src/fdospecgen.h:53 +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An action game +#: src/fdospecgen.h:220 msgid "ActionGame" msgstr "Actionspiel" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:55 +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application handles adult or explicit material +#: src/fdospecgen.h:226 msgid "Adult" msgstr "Erwachsener" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game -#: src/fdospecgen.h:57 +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Adventure style game +#: src/fdospecgen.h:232 msgid "AdventureGame" msgstr "Abenteuerspiel" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:59 +#: src/wmwinlist.cc:83 +msgid "All Workspaces" +msgstr "Alle Arbeitsbereiche" + +#: src/wmabout.cc:62 +msgid "AlphaBlending" +msgstr "AlphaBlending" + +#: src/icehelp.cc:1348 +msgid "Alt+Left" +msgstr "Alt+Links" + +#: src/icehelp.cc:1350 +msgid "Alt+Right" +msgstr "Alt+Rechts" + +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A simple amusement +#: src/fdospecgen.h:238 msgid "Amusement" msgstr "Unterhaltung" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game -#: src/fdospecgen.h:61 +# +#: src/wmapp.cc:740 +msgid "Another window manager already running, exiting..." +msgstr "Ein anderer Fenstermanager ist bereits aktiv, beenden..." + +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Arcade style game +#: src/fdospecgen.h:244 msgid "ArcadeGame" msgstr "Arcadespiel" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Utility -#: src/fdospecgen.h:63 +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tool to archive/backup data +#: src/fdospecgen.h:42 src/fdospecgen.h:250 msgid "Archiving" msgstr "Archivieren" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science -#: src/fdospecgen.h:65 +#. TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout +#: src/wmtaskbar.cc:230 +msgid "Arrange _Icons" +msgstr "_Symbole anordnen" + +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Software to teach arts +#: src/fdospecgen.h:256 src/fdospecgen.h:262 msgid "Art" msgstr "Kunst" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science -#: src/fdospecgen.h:67 -msgid "ArtificialIntelligence" -msgstr "KünstlicheIntelligenz" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Artificial Intelligence software +#: src/fdospecgen.h:268 src/fdospecgen.h:274 +msgid "Artificialtelligence" +msgstr "Künstliche Intelligenz" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science -#: src/fdospecgen.h:69 +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Astronomy software +#: src/fdospecgen.h:280 src/fdospecgen.h:286 msgid "Astronomy" msgstr "Astronomie" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:71 +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An audio application +#: src/fdospecgen.h:90 src/fdospecgen.h:98 src/fdospecgen.h:154 +#: src/fdospecgen.h:170 src/fdospecgen.h:300 src/fdospecgen.h:654 +#: src/fdospecgen.h:894 src/fdospecgen.h:954 src/fdospecgen.h:1158 msgid "Audio" msgstr "Audio" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:73 +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for presenting, creating, or processing multimedia (audio/video) +#: src/fdospecgen.h:92 src/fdospecgen.h:100 src/fdospecgen.h:156 +#: src/fdospecgen.h:164 src/fdospecgen.h:172 src/fdospecgen.h:306 +#: src/fdospecgen.h:450 src/fdospecgen.h:492 src/fdospecgen.h:828 +#: src/fdospecgen.h:900 src/fdospecgen.h:960 src/fdospecgen.h:1162 msgid "AudioVideo" msgstr "AudioVideo" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Audio or Video or AudioVideo -#: src/fdospecgen.h:75 +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to edit audio/video files +#: src/fdospecgen.h:292 src/fdospecgen.h:298 src/fdospecgen.h:304 msgid "AudioVideoEditing" msgstr "Video-Bearbeitung" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science -#: src/fdospecgen.h:77 +#: src/ycursor.cc:179 +#, c-format +msgid "BUG? Imlib was able to read \"%s\"" +msgstr "BUG? Imlib war in der Lage \"%s\" zu lesen" + +#: src/ycursor.cc:204 +#, c-format +msgid "BUG? Malformed XPM header but Imlib was able to parse \"%s\"" +msgstr "BUG? Fehlerhafter XPM-Header, aberImlib konnte die Datei \"%s\" parsen" + +#: src/ycursor.cc:215 +#, c-format +msgid "BUG? Unexpected character but Imlib was able to parse \"%s\"" +msgstr "BUG? Unerwartetes Zeichen, aber Imlib konnte die Datei \"%s\" parsen" + +#: src/ycursor.cc:212 +#, c-format +msgid "BUG? Unexpected end of XPM file but Imlib was able to parse \"%s\"" +msgstr "" +"BUG? Unerwartetes Ende der XPM-Datei, aber Imlib konnte die Datei \"%s\" " +"parsen" + +#: src/icehelp.cc:1348 +msgid "Back" +msgstr "Zurück" + +#: src/wmmenu.cc:55 +#, c-format +msgid "Bad argument %d to command '%s'" +msgstr "Schlechtes Argument %d zum Befehl '%s'" + +#: src/yconfig.cc:170 src/yconfig.cc:181 src/yconfig.cc:193 +#, c-format +msgid "Bad argument: %s for %s [%d,%d]" +msgstr "Schlechtes Argument: %s für %s [%d,%d]" + +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Biology software +#: src/fdospecgen.h:310 src/fdospecgen.h:316 msgid "Biology" msgstr "Biologie" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game -#: src/fdospecgen.h:79 +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Falling blocks game +#: src/fdospecgen.h:322 msgid "BlocksGame" msgstr "Klötzchenspiel" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game -#: src/fdospecgen.h:81 +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A board game +#: src/fdospecgen.h:328 msgid "BoardGame" msgstr "Brettspiel" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Development -#: src/fdospecgen.h:83 -msgid "Building" -msgstr "Bauen" +#: src/wmapp.cc:620 +msgid "Bottom Half" +msgstr "Untere Hälfte" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Utility -#: src/fdospecgen.h:85 -msgid "Calculator" -msgstr "Rechner" +#: src/wmapp.cc:624 +msgid "Bottom Left" +msgstr "Unten links" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office -#: src/fdospecgen.h:87 -msgid "Calendar" -msgstr "Kalender" +#: src/wmapp.cc:625 +msgid "Bottom Right" +msgstr "Unten rechts" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game -#: src/fdospecgen.h:89 -msgid "CardGame" -msgstr "Kartenspiel" +#: src/amemstatus.cc:179 +msgid "Buffers: " +msgstr "Puffer: " + +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tool to build applications +#: src/fdospecgen.h:334 +msgid "Building" +msgstr "Bauen" + +#: src/aapm.cc:209 src/aapm.cc:452 src/aapm.cc:617 +msgid "C" +msgstr "C" + +#: src/aclock.cc:195 +msgid "CLOCK" +msgstr "UHR" + +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on COSMIC libraries +#: src/fdospecgen.h:340 +msgid "COSMIC" +msgstr "COSMIC" + +#: src/acpustatus.cc:607 src/acpustatus.cc:907 +msgid "CPU" +msgstr "CPU" + +#: src/acpustatus.cc:552 +#, c-format +msgid "CPU %s Load: %3.2f %3.2f %3.2f, %u" +msgstr "CPU %s Auslastung: %3.2f %3.2f %3.2f, %u" + +#: src/acpustatus.cc:908 +#, c-format +msgid "CPU%d" +msgstr "CPU%d" + +#. TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout +#: src/wmtaskbar.cc:219 src/wmwinlist.cc:457 src/wmwinlist.cc:490 +msgid "Ca_scade" +msgstr "_Überlappend anordnen" + +#: src/amemstatus.cc:178 +msgid "Cached: " +msgstr "Cache: " + +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A calculator +#: src/fdospecgen.h:346 +msgid "Calculator" +msgstr "Rechner" + +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Calendar application +#: src/fdospecgen.h:352 +msgid "Calendar" +msgstr "Kalender" + +#: src/aapm.cc:121 src/aapm.cc:139 +#, c-format +msgid "Can't ioctl the APM device %s" +msgstr "APM-Gerät %s kann nicht über ioctl gesteuert werden" + +#: src/icesh.cc:4186 src/icesound.cc:800 src/icewmbg.cc:1087 +#: src/icewmhint.cc:37 src/wmapp.cc:1290 src/yxapp.cc:1049 +#, c-format +msgid "Can't open display: %s. X must be running and $DISPLAY set." +msgstr "" +"Das Display kann nicht geöffnet werden: %s. Der X muss laufen und $DISPLAY " +"gesetzt sein." + +#: src/aapm.cc:113 +#, c-format +msgid "Can't open the APM device %s" +msgstr "Kann OSS-Gerät %s nicht öffnen" + +#: src/icesh.cc:3770 +#, c-format +msgid "Cannot get geometry of window 0x%lx" +msgstr "Geometrie von Fenster 0x%lx kann nicht abgerufen werden" + +#: src/icewmbg.cc:1335 +msgid "Cannot start, because another icewmbg is still running." +msgstr "Kann nicht starten, weil ein anderes icewmbg schon läuft." + +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A card game +#: src/fdospecgen.h:358 +msgid "CardGame" +msgstr "Kartenspiel" + +#: src/wmapp.cc:626 +msgid "Center" +msgstr "Mitte" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office -#: src/fdospecgen.h:91 +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Chart application +#: src/fdospecgen.h:364 msgid "Chart" msgstr "Tabelle" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network -#: src/fdospecgen.h:93 +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A chat client +#: src/fdospecgen.h:370 msgid "Chat" msgstr "Chat" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science -#: src/fdospecgen.h:95 +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Chemistry software +#: src/fdospecgen.h:376 src/fdospecgen.h:382 msgid "Chemistry" msgstr "Chemie" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Utility -#: src/fdospecgen.h:97 +#: src/wmclient.cc:470 +#, c-format +msgid "" +"Client %s with PID %ld fails to respond.\n" +"Do you wish to terminate this client?\n" +msgstr "" +"Client %s mitPID %ld antwortet nicht.\n" +"Möchten Sie diesen Client beenden?\n" + +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A clock application/applet +#: src/fdospecgen.h:388 msgid "Clock" msgstr "Uhr" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Utility;Archiving -#: src/fdospecgen.h:99 +#: src/icehelp.cc:1365 src/icesame.cc:62 src/iceview.cc:63 src/wmbutton.cc:147 +msgid "Close" +msgstr "Schließen" + +#: src/wmabout.cc:56 +msgid "CodeSet:" +msgstr "Kodierung:" + +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tool to manage compressed data/archives +#: src/fdospecgen.h:40 msgid "Compression" msgstr "Komprimierung" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science -#: src/fdospecgen.h:101 +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Computer Science software +#: src/fdospecgen.h:130 src/fdospecgen.h:138 src/fdospecgen.h:394 +#: src/fdospecgen.h:400 msgid "ComputerScience" msgstr "Informatik" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science -#: src/fdospecgen.h:103 +#: src/wmapp.cc:1949 +msgid "Confirm Logout" +msgstr "Abmelden bestätigen" + +#: src/wmapp.cc:1003 +msgid "Confirm Restart as Terminal" +msgstr "Neustart als Terminal bestätigen" + +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application that only works inside a terminal (text-based or command line application) +#: src/fdospecgen.h:406 +msgid "ConsoleOnly" +msgstr "Reiner Textmodus" + +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside:   +#: src/fdospecgen.h:412 src/fdospecgen.h:418 msgid "Construction" msgstr "Konstruktion" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office -#: src/fdospecgen.h:105 +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: E.g. an address book +#: src/fdospecgen.h:424 msgid "ContactManagement" msgstr "Kontaktverwaltung" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:107 +#: src/icehelp.cc:1356 +msgid "Contents" +msgstr "Inhalte" + +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Important application, core to the desktop such as a file manager or a help browser +#: src/fdospecgen.h:430 msgid "Core" msgstr "Core" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science -#: src/fdospecgen.h:109 -msgid "DataVisualization" -msgstr "Datenvisualisierung" +#: src/amailbox.cc:314 +#, c-format +msgid "Could not connect to %s: %s" +msgstr "Keine Verbindung möglich zu %s: %s" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office or Development or AudioVideo -#: src/fdospecgen.h:111 -msgid "Database" -msgstr "Datenbank" +#: src/icesound.cc:862 +msgid "Could not get GUI event property" +msgstr "Konnte keine GUI-Event-Property erhalten" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Development -#: src/fdospecgen.h:113 -msgid "Debugger" -msgstr "Debugger" +#: src/yfontcore.cc:121 src/yfontxft.cc:127 +#, c-format +msgid "Could not load font \"%s\"." +msgstr "Die Schriftart \"%s\" konnte nicht geladen werden." -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Settings -#: src/fdospecgen.h:115 -msgid "DesktopSettings" -msgstr "Desktop-Einstellungen" +#: src/yfontcore.cc:261 +#, c-format +msgid "Could not load fontset \"%s\"." +msgstr "Schriftsatz \"%s\" konnte nicht geladen werden." -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:117 -msgid "Development" -msgstr "Entwicklung" +#: src/yximage.cc:191 src/yximage.cc:214 +#, c-format +msgid "Could not load image \"%s\"" +msgstr "Bild \"%s\" konnte nicht geladen werden" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network -#: src/fdospecgen.h:119 -msgid "Dialup" -msgstr "Einwahl" +#: src/icehelp.cc:2461 +msgid "Could not locate curl or wget in PATH" +msgstr "curl oder wget konnten in PATH nicht gefunden werden" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office or TextTools -#: src/fdospecgen.h:121 -msgid "Dictionary" -msgstr "Wörterbuch" +#: src/icesound.cc:397 +#, c-format +msgid "Could not open OSS device %s" +msgstr "Konnte OSS-Gerät %s nicht öffnen" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: AudioVideo -#: src/fdospecgen.h:123 -msgid "DiscBurning" -msgstr "CD brennen" +#: src/ycolor.cc:229 src/ycolor.cc:240 +#, c-format +msgid "Could not parse color \"%s\"" +msgstr "Farbe \"%s\" konnte nicht geparst werden" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:125 -msgid "Documentation" -msgstr "Dokumentation" +#: src/icesound.cc:368 +msgid "Could not post OSS" +msgstr "Konnte OSS nicht versenden" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science -#: src/fdospecgen.h:127 -msgid "Economy" -msgstr "Wirtschaft" +#: src/icesound.cc:407 +msgid "Could not reset OSS DSP" +msgstr "Konnte OSS-DSP nicht zurücksetzen" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:129 -msgid "Editors" -msgstr "Editoren" +#: src/wmapp.cc:815 +#, c-format +msgid "" +"Could not restart: %s\n" +"Does $PATH lead to %s?" +msgstr "" +"Neustart fehlgeschlagen: %s\n" +"Verweist die Variable $PATH auf das Programm %s?" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:131 -msgid "Education" -msgstr "Bildung" +#: src/icesound.cc:335 src/icesound.cc:340 +msgid "Could not set OSS channels" +msgstr "Konnte OSS-Kanäle nicht festlegen" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science -#: src/fdospecgen.h:133 -msgid "Electricity" -msgstr "Elektrizität" +#: src/icesound.cc:412 +msgid "Could not set OSS format" +msgstr "Konnte OSS-Format nicht einstellen" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:135 -msgid "Electronics" -msgstr "Elektronik" +#: src/icesound.cc:402 +msgid "Could not set OSS stereo" +msgstr "Konnte OSS-Stereo nicht festlegen" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office or Network -#: src/fdospecgen.h:137 -msgid "Email" -msgstr "E-Mail" +#: src/icesound.cc:345 src/icesound.cc:373 +msgid "Could not sync OSS" +msgstr "Konnte OSS nicht synchronisieren" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: System or Game -#: src/fdospecgen.h:139 -msgid "Emulator" -msgstr "Emulator" +#: src/yinputline.cc:23 +msgid "Ctrl+A" +msgstr "Strg+A" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:141 -msgid "Engineering" -msgstr "Ingenieurwesen" +#: src/icehelp.cc:1362 +msgid "Ctrl+B" +msgstr "Strg+B" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network -#: src/fdospecgen.h:143 -msgid "Feed" -msgstr "Feed" +#: src/yinputline.cc:18 +msgid "Ctrl+C" +msgstr "Strg+C" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: System;FileTools -#: src/fdospecgen.h:145 -msgid "FileManager" -msgstr "Dateimanager" +#: src/icehelp.cc:1359 +msgid "Ctrl+F" +msgstr "Strg+F" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Utility or System -#: src/fdospecgen.h:147 -msgid "FileTools" -msgstr "Datei-Tools" +#: src/iceview.cc:59 +msgid "Ctrl+H" +msgstr "Strg+H" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network -#: src/fdospecgen.h:149 -msgid "FileTransfer" -msgstr "Datei-Transfer" +#: src/icehelp.cc:1370 +msgid "Ctrl+I" +msgstr "Strg+I" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: System -#: src/fdospecgen.h:151 -msgid "Filesystem" -msgstr "Dateisystem" +#: src/icehelp.cc:1378 +msgid "Ctrl+M" +msgstr "Strg+M" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office -#: src/fdospecgen.h:153 -msgid "Finance" -msgstr "Finanzen" +#: src/icesame.cc:59 +msgid "Ctrl+N" +msgstr "Strg+N" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office -#: src/fdospecgen.h:155 -msgid "FlowChart" -msgstr "Flussdiagramm" +#: src/yinputline.cc:21 +msgid "Ctrl+P" +msgstr "Strg+P" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Development -#: src/fdospecgen.h:157 -msgid "GUIDesigner" -msgstr "GUI-Designer" +#: src/icehelp.cc:1365 src/icesame.cc:62 src/iceview.cc:63 +msgid "Ctrl+Q" +msgstr "Strg+Q" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:159 -msgid "Game" -msgstr "Spiel" +#: src/icehelp.cc:1364 src/icesame.cc:60 +msgid "Ctrl+R" +msgstr "Strg+R" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science -#: src/fdospecgen.h:161 -msgid "Geography" -msgstr "Geographie" +#: src/icehelp.cc:1382 src/iceview.cc:60 +msgid "Ctrl+T" +msgstr "Strg+T" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science -#: src/fdospecgen.h:163 -msgid "Geology" -msgstr "Geologie" +#: src/icehelp.cc:1395 src/yinputline.cc:20 +msgid "Ctrl+V" +msgstr "Strg+V" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science -#: src/fdospecgen.h:165 -msgid "Geoscience" -msgstr "Geo-Wissenschaften" +#: src/icehelp.cc:1384 src/iceview.cc:61 +msgid "Ctrl+W" +msgstr "Strg+W" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:167 -msgid "Graphics" -msgstr "Grafiken" +#: src/icehelp.cc:1390 src/yinputline.cc:19 +msgid "Ctrl+X" +msgstr "Strg+X" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network or Audio -#: src/fdospecgen.h:169 -msgid "HamRadio" -msgstr "Amateurfunk" +#: src/icesame.cc:57 +msgid "Ctrl+Z" +msgstr "Strg+Z" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Settings -#: src/fdospecgen.h:171 -msgid "HardwareSettings" -msgstr "Hardware-Einstellungen" +#: src/yinputline.cc:19 +msgid "Cu_t" +msgstr "Aus_schneiden" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science -#: src/fdospecgen.h:173 -msgid "History" -msgstr "Geschichte" +#: src/wmprog.cc:348 +msgid "Custo_m" +msgstr "_Benutzerdefiniert" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science -#: src/fdospecgen.h:175 -msgid "Humanities" -msgstr "Geisteswissenschaften" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on DDE libraries +#: src/fdospecgen.h:48 +msgid "DDE" +msgstr "DDE" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Development -#: src/fdospecgen.h:177 -msgid "IDE" -msgstr "IDE" +#: src/amailbox.cc:140 +#, c-format +msgid "DNS name lookup failed for %s" +msgstr "DNS-Namenssuche fehlgeschlagen für %s" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network -#: src/fdospecgen.h:179 -msgid "IRCClient" -msgstr "IRC-Client" +#: src/wmapp.cc:563 +msgid "D_esktop" +msgstr "D_esktop" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science -#: src/fdospecgen.h:181 -msgid "ImageProcessing" -msgstr "Bildverarbeitung" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Data visualization software +#: src/fdospecgen.h:436 src/fdospecgen.h:442 +msgid "DataVisualization" +msgstr "Datenvisualisierung" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network -#: src/fdospecgen.h:183 -msgid "InstantMessaging" -msgstr "Instant-Messaging" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to manage a database +#: src/fdospecgen.h:448 src/fdospecgen.h:454 src/fdospecgen.h:460 +msgid "Database" +msgstr "Datenbank" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game -#: src/fdospecgen.h:185 -msgid "KidsGame" -msgstr "Kinderspiele" +#: src/aclock.cc:201 +msgid "Date" +msgstr "Datum" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science -#: src/fdospecgen.h:187 -msgid "Languages" -msgstr "Sprachen" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tool to debug applications +#: src/fdospecgen.h:466 +msgid "Debugger" +msgstr "Debugger" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science -#: src/fdospecgen.h:189 -msgid "Literature" -msgstr "Literatur" +#: src/aclock.cc:202 src/themes.cc:83 +msgid "Default" +msgstr "Standard" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game -#: src/fdospecgen.h:191 -msgid "LogicGame" -msgstr "Logikspiel" +#: src/wmwinlist.cc:468 +msgid "Del" +msgstr "Entf" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science or Utility -#: src/fdospecgen.h:193 -msgid "Maps" -msgstr "Karten" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Configuration tool for the GUI +#: src/fdospecgen.h:472 +msgid "DesktopSettings" +msgstr "Desktop-Einstellungen" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science -#: src/fdospecgen.h:195 -msgid "Math" -msgstr "Mathe" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An application for development +#: src/fdospecgen.h:336 src/fdospecgen.h:456 src/fdospecgen.h:468 +#: src/fdospecgen.h:612 src/fdospecgen.h:696 src/fdospecgen.h:912 +#: src/fdospecgen.h:918 src/fdospecgen.h:972 src/fdospecgen.h:1104 +#: src/fdospecgen.h:1134 src/fdospecgen.h:1166 +msgid "Development" +msgstr "Entwicklung" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science -#: src/fdospecgen.h:197 -msgid "MedicalSoftware" -msgstr "Medizinische Software" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A dial-up program +#: src/fdospecgen.h:478 +msgid "Dialup" +msgstr "Einwahl" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: AudioVideo;Audio -#: src/fdospecgen.h:199 -msgid "Midi" -msgstr "Midi" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A dictionary +#: src/fdospecgen.h:56 src/fdospecgen.h:484 +msgid "Dictionary" +msgstr "Wörterbuch" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: AudioVideo;Audio -#: src/fdospecgen.h:201 -msgid "Mixer" -msgstr "Mixer" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to burn a disc +#: src/fdospecgen.h:490 +msgid "DiscBurning" +msgstr "CD brennen" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: System or Network -#: src/fdospecgen.h:203 -msgid "Monitor" -msgstr "Monitor" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Help or documentation +#: src/fdospecgen.h:496 +msgid "Documentation" +msgstr "Dokumentation" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:205 -msgid "Motif" -msgstr "Motiv" +#: src/wmabout.cc:61 +msgid "DoubleBuffer" +msgstr "DoubleBuffer" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:207 -msgid "Multimedia" -msgstr "Multimedia" +#: src/icesh.cc:2294 +msgid "EWMH window state" +msgstr "EWMH-Fensterzustand" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: AudioVideo or Education -#: src/fdospecgen.h:209 -msgid "Music" -msgstr "Musik" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Economy software +#: src/fdospecgen.h:502 src/fdospecgen.h:508 +msgid "Economy" +msgstr "Wirtschaft" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:211 -msgid "Network" -msgstr "Netzwerk" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Educational software +#: src/fdospecgen.h:108 src/fdospecgen.h:132 src/fdospecgen.h:258 +#: src/fdospecgen.h:270 src/fdospecgen.h:282 src/fdospecgen.h:312 +#: src/fdospecgen.h:378 src/fdospecgen.h:396 src/fdospecgen.h:414 +#: src/fdospecgen.h:438 src/fdospecgen.h:504 src/fdospecgen.h:516 +#: src/fdospecgen.h:618 src/fdospecgen.h:630 src/fdospecgen.h:642 +#: src/fdospecgen.h:672 src/fdospecgen.h:684 src/fdospecgen.h:708 +#: src/fdospecgen.h:738 src/fdospecgen.h:750 src/fdospecgen.h:768 +#: src/fdospecgen.h:786 src/fdospecgen.h:798 src/fdospecgen.h:834 +#: src/fdospecgen.h:876 src/fdospecgen.h:978 src/fdospecgen.h:1026 +#: src/fdospecgen.h:1044 src/fdospecgen.h:1170 +msgid "Education" +msgstr "Bildung" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network -#: src/fdospecgen.h:213 -msgid "News" -msgstr "Neuigkeiten" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Electricity software +#: src/fdospecgen.h:514 src/fdospecgen.h:520 +msgid "Electricity" +msgstr "Elektrizität" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education;Math or Science;Math -#: src/fdospecgen.h:215 -msgid "NumericalAnalysis" -msgstr "Numerische Analysis" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Electronics software, e.g. a circuit designer +#: src/fdospecgen.h:526 +msgid "Electronics" +msgstr "Elektronik" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Graphics;Scanning -#: src/fdospecgen.h:217 -msgid "OCR" -msgstr "Optische Zeichenerkennung" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Email application +#: src/fdospecgen.h:532 src/fdospecgen.h:538 +msgid "Email" +msgstr "E-Mail" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:219 -msgid "Office" -msgstr "Büro" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Emulator of another platform, such as a DOS emulator +#: src/fdospecgen.h:544 src/fdospecgen.h:550 +msgid "Emulator" +msgstr "Emulator" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:221 -msgid "Other" -msgstr "Sonstiges" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Engineering software, e.g. CAD programs +#: src/fdospecgen.h:556 +msgid "Engineering" +msgstr "Ingenieurwesen" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network -#: src/fdospecgen.h:223 -msgid "P2P" -msgstr "P2P" +#: src/wmpref.cc:179 +#, c-format +msgid "Enter a new value for %s: " +msgstr "Geben Sie einen neuen Wert für %s ein: " -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office -#: src/fdospecgen.h:225 -msgid "PDA" -msgstr "PDA" +#: src/wmmenu.cc:160 +#, c-format +msgid "Error at %s '%s'" +msgstr "Fehler bei %s '%s'" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Settings -#: src/fdospecgen.h:227 -msgid "PackageManager" -msgstr "Paket-Manager" +#: src/wmmenu.cc:369 +#, c-format +msgid "Error at includeprog '%s'" +msgstr "Fehler bei includeprog '%s'" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education;ComputerScience or Science;ComputerScience -#: src/fdospecgen.h:229 -msgid "ParallelComputing" -msgstr "Paralleles Rechnen" +#: src/wmmenu.cc:110 +#, c-format +msgid "Error at keyword '%s' for %s" +msgstr "Fehler bei Schlüsselwort '%s' für %s" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Graphics or Office -#: src/fdospecgen.h:231 -msgid "Photography" -msgstr "Fotografie" +#: src/wmmenu.cc:280 +#, c-format +msgid "Error at menuprog '%s'" +msgstr "Fehler bei menuprog '%s'" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science -#: src/fdospecgen.h:233 -msgid "Physics" -msgstr "Physik" +#: src/wmmenu.cc:324 +#, c-format +msgid "Error at menuprogreload: '%s'" +msgstr "Fehler bei menuprogreload: '%s'" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Audio or Video or AudioVideo -#: src/fdospecgen.h:235 -msgid "Player" -msgstr "Player" +#: src/amailbox.cc:805 +msgid "Error checking mailbox." +msgstr "Fehler beim Prüfen des Postfachs." -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office -#: src/fdospecgen.h:237 -msgid "Presentation" -msgstr "Präsentation" +#: src/iceview.cc:60 +msgid "Expand Tabs" +msgstr "Tabs erweitern" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Settings;HardwareSettings -#: src/fdospecgen.h:239 -msgid "Printing" -msgstr "Drucken" +#: src/icehelp.cc:1360 +msgid "F3" +msgstr "F3" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Development -#: src/fdospecgen.h:241 -msgid "Profiling" -msgstr "Profilerstellung" +#: src/icehelp.cc:1376 +msgid "FAQ" +msgstr "FAQ" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office or Development -#: src/fdospecgen.h:243 -msgid "ProjectManagement" -msgstr "Projektmanagement" +#: src/wmapp.cc:107 +#, c-format +msgid "Failed to become the owner of the %s selection" +msgstr "Konnte nicht der Besitzer der Auswahl von %s werden" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Graphics or Office -#: src/fdospecgen.h:245 -msgid "Publishing" -msgstr "Veröffentlichen" +#: src/icesound.cc:934 +#, c-format +msgid "Failed to connect to audio interfaces %s." +msgstr "Konnte sich nicht mit Audio-Schnittstellen %s verbinden." -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Graphics;2DGraphics -#: src/fdospecgen.h:247 -msgid "RasterGraphics" -msgstr "Raster-Grafiken" +#: src/icehelp.cc:2341 +msgid "Failed to create a temporary file" +msgstr "Erstellung einer temporären Datei ist fehlgeschlagen" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Audio or Video or AudioVideo -#: src/fdospecgen.h:249 -msgid "Recorder" -msgstr "Rekorder" +#: src/icehelp.cc:2453 +#, c-format +msgid "Failed to decompress %s" +msgstr "Konnte %s nicht entpacken" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network -#: src/fdospecgen.h:251 -msgid "RemoteAccess" -msgstr "Fernzugriff" +#: src/ylocale.cc:93 +msgid "" +"Failed to determinate the current locale's codeset. Assuming ISO-8859-1.\n" +msgstr "" +"Die Kodierung der momentanen lokalen Variablen konnte nicht bestimmt werden. " +"Es wird ISO-8859-1 angenommen.\n" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Development -#: src/fdospecgen.h:253 -msgid "RevisionControl" -msgstr "Revisionskontrolle" +#: src/amailbox.cc:363 src/wmmenu.cc:475 src/wmmenu.cc:492 src/yapp.cc:436 +#, c-format +msgid "Failed to execute %s" +msgstr "Fehler beim Ausführen von %s" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science -#: src/fdospecgen.h:255 -msgid "Robotics" -msgstr "Robotik" +#: src/icehelp.cc:2431 +#, c-format +msgid "Failed to execute system(%s) (%d)" +msgstr "Ausführung vom system(%s) ist fehlgeschlagen (%d)" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game -#: src/fdospecgen.h:257 -msgid "RolePlaying" -msgstr "Rollenspiel" +#: src/amailbox.cc:334 +#, c-format +msgid "Failed to find %s command" +msgstr "Kommando %s kann nicht gefunden werden" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Graphics -#: src/fdospecgen.h:259 -msgid "Scanning" -msgstr "Scannen" +#: src/icewmbg.cc:35 src/icewmbg.cc:372 +#, c-format +msgid "Failed to load image '%s'." +msgstr "Konnte Bild '%s' nicht laden." -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:261 -msgid "Science" -msgstr "Wissenschaft" +#: src/wmconfig.cc:35 src/wmconfig.cc:40 src/wmconfig.cc:46 +#, c-format +msgid "Failed to load theme %s" +msgstr "Konnte Theme %s nicht laden" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:263 -msgid "Screensavers" -msgstr "Bildschirmschoner" +#: src/icehelp.cc:2312 +msgid "Failed to open file for reading." +msgstr "Konnte nicht zum lesen geöffnet werden." -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Settings or System -#: src/fdospecgen.h:265 -msgid "Security" -msgstr "Sicherheit" +#: src/yurl.cc:145 +#, c-format +msgid "Failed to parse URL \"%s\"." +msgstr "Konnte die URL \"%s\" nicht analysieren." -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: AudioVideo;Audio -#: src/fdospecgen.h:267 -msgid "Sequencer" -msgstr "Sequenzer" +#: src/wmtaskbar.cc:336 +msgid "Favorite Applications" +msgstr "Lieblings-Anwendungen" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:269 -msgid "Settings" -msgstr "Einstellungen" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: RSS, podcast and other subscription based contents +#: src/fdospecgen.h:562 +msgid "Feed" +msgstr "Feed" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game -#: src/fdospecgen.h:271 -msgid "Shooter" -msgstr "Schütze" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A file manager +#: src/fdospecgen.h:64 +msgid "FileManager" +msgstr "Dateimanager" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game -#: src/fdospecgen.h:273 -msgid "Simulation" -msgstr "Simulation" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A file tool utility +#: src/fdospecgen.h:66 src/fdospecgen.h:568 src/fdospecgen.h:574 +msgid "FileTools" +msgstr "Datei-Tools" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science or Utility -#: src/fdospecgen.h:275 -msgid "Spirituality" -msgstr "Spiritualität" - -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Education or Science -#: src/fdospecgen.h:277 -msgid "Sports" -msgstr "Sport" - -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game -#: src/fdospecgen.h:279 -msgid "SportsGame" -msgstr "Sportspiel" - -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office -#: src/fdospecgen.h:281 -msgid "Spreadsheet" -msgstr "Tabellenkalkulation" - -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Game -#: src/fdospecgen.h:283 -msgid "StrategyGame" -msgstr "Strategiespiel" - -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:285 -msgid "System" -msgstr "System" - -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: AudioVideo;Video -#: src/fdospecgen.h:287 -msgid "TV" -msgstr "TV" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Tools like FTP or P2P programs +#: src/fdospecgen.h:580 +msgid "FileTransfer" +msgstr "Datei-Transfer" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network -#: src/fdospecgen.h:289 -msgid "Telephony" -msgstr "Telefonie" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A file system tool +#: src/fdospecgen.h:586 +msgid "Filesystem" +msgstr "Dateisystem" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Utility -#: src/fdospecgen.h:291 -msgid "TelephonyTools" -msgstr "Telefonie-Tools" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to manage your finance +#: src/fdospecgen.h:592 +msgid "Finance" +msgstr "Finanzen" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: System -#: src/fdospecgen.h:293 -msgid "TerminalEmulator" -msgstr "Terminal-Emulator" +#: src/icehelp.cc:1360 +msgid "Find next" +msgstr "Weitersuchen" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Utility -#: src/fdospecgen.h:295 -msgid "TextEditor" -msgstr "Texteditor" +#: src/icehelp.cc:1359 +msgid "Find..." +msgstr "Suchen..." -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Utility -#: src/fdospecgen.h:297 -msgid "TextTools" -msgstr "Text-Tools" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A flowchart application +#: src/fdospecgen.h:598 +msgid "FlowChart" +msgstr "Flussdiagramm" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Development -#: src/fdospecgen.h:299 -msgid "Translation" -msgstr "Übersetzung" +#: src/icesh.cc:76 +msgid "For help please consult the man page icesh(1).\n" +msgstr "Für Hilfe bitte die Manpage (1) hinzuziehen.\n" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: AudioVideo;Audio -#: src/fdospecgen.h:301 -msgid "Tuner" -msgstr "Empfänger" +#: src/wmmgr.cc:3701 +msgid "For keyboard switching, please install setxkbmap." +msgstr "Um die Tastatur zu ändern, installieren Sie bitte setxkbmap." -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:303 -msgid "Utility" -msgstr "Utility" +#: src/icehelp.cc:1350 +msgid "Forward" +msgstr "Weiter" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Graphics;2DGraphics -#: src/fdospecgen.h:305 -msgid "VectorGraphics" -msgstr "Vektor-Grafiken" +#: src/amemstatus.cc:177 +msgid "Free: " +msgstr "Frei: " -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:307 -msgid "Video" -msgstr "Video" +#: src/amemstatus.cc:144 +msgid "GB" +msgstr "GB" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network -#: src/fdospecgen.h:309 -msgid "VideoConference" -msgstr "Videokonferenz" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on GNOME libraries +#: src/fdospecgen.h:72 +msgid "GNOME" +msgstr "GNOME" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Graphics or Office -#: src/fdospecgen.h:311 -msgid "Viewer" -msgstr "Betrachter" +#: src/icesh.cc:2289 +msgid "GNOME window layer" +msgstr "GNOME-Fensterebene" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. -#: src/fdospecgen.h:313 -msgid "WINE" -msgstr "WINE" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on GTK+ libraries +#: src/fdospecgen.h:74 src/fdospecgen.h:186 src/fdospecgen.h:604 +msgid "GTK" +msgstr "GTK" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network -#: src/fdospecgen.h:315 -msgid "WebBrowser" -msgstr "Webbrowser" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A GUI designer application +#: src/fdospecgen.h:610 +msgid "GUIDesigner" +msgstr "GUI-Designer" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Network or Development -#: src/fdospecgen.h:317 -msgid "WebDevelopment" -msgstr "Webentwicklung" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A game +#: src/fdospecgen.h:222 src/fdospecgen.h:234 src/fdospecgen.h:246 +#: src/fdospecgen.h:324 src/fdospecgen.h:330 src/fdospecgen.h:360 +#: src/fdospecgen.h:552 src/fdospecgen.h:732 src/fdospecgen.h:762 +#: src/fdospecgen.h:990 src/fdospecgen.h:1014 src/fdospecgen.h:1020 +#: src/fdospecgen.h:1056 src/fdospecgen.h:1068 src/fdospecgen.h:1174 +msgid "Game" +msgstr "Spiel" -#. TRANSLATORS: This is a menu category name from freedesktop.org. Please add spaces as needed but no double-quotes. Context: Office -#: src/fdospecgen.h:319 -msgid "WordProcessor" -msgstr "Textverarbeitung" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Geography software +#: src/fdospecgen.h:616 src/fdospecgen.h:622 +msgid "Geography" +msgstr "Geographie" -#: src/icehelp.cc:1348 -msgid "Back" -msgstr "Zurück" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Geology software +#: src/fdospecgen.h:628 src/fdospecgen.h:634 +msgid "Geology" +msgstr "Geologie" -#: src/icehelp.cc:1348 -msgid "Alt+Left" -msgstr "Alt+Links" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Geoscience software, GIS +#: src/fdospecgen.h:640 src/fdospecgen.h:646 +msgid "Geoscience" +msgstr "Geo-Wissenschaften" -#: src/icehelp.cc:1350 -msgid "Forward" -msgstr "Weiter" +#: src/icehelp.cc:1386 +msgid "Github" +msgstr "Github" -#: src/icehelp.cc:1350 -msgid "Alt+Right" -msgstr "Alt+Rechts" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for viewing, creating, or processing graphics +#: src/fdospecgen.h:124 src/fdospecgen.h:148 src/fdospecgen.h:180 +#: src/fdospecgen.h:198 src/fdospecgen.h:204 src/fdospecgen.h:864 +#: src/fdospecgen.h:930 src/fdospecgen.h:996 src/fdospecgen.h:1116 +#: src/fdospecgen.h:1178 +msgid "Graphics" +msgstr "Grafiken" -#: src/icehelp.cc:1353 -msgid "Previous" -msgstr "Vorherige" +#: src/icesh.cc:2291 +msgid "Gravity symbols" +msgstr "Gravitationssymbole" -#: src/icehelp.cc:1354 -msgid "Next" -msgstr "Nächste" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: HAM radio software +#: src/fdospecgen.h:652 src/fdospecgen.h:658 +msgid "HamRadio" +msgstr "Amateurfunk" -#: src/icehelp.cc:1356 -msgid "Contents" -msgstr "Inhalte" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tool to manage hardware components, like sound cards, video cards or printers +#: src/fdospecgen.h:30 src/fdospecgen.h:664 +msgid "HardwareSettings" +msgstr "Hardware-Einstellungen" -#: src/icehelp.cc:1357 -msgid "Index" -msgstr "Index" +#: src/iceview.cc:59 +msgid "Hex View" +msgstr "Hexadezimalansicht" -#: src/icehelp.cc:1359 -msgid "Find..." -msgstr "Suchen..." +#: src/wmbutton.cc:127 +msgid "Hide" +msgstr "Verstecken" -#: src/icehelp.cc:1359 -msgid "Ctrl+F" -msgstr "Strg+F" +#: src/wmtaskbar.cc:313 src/wmtaskbar.cc:1025 +msgid "Hide Taskbar" +msgstr "Taskleiste verbergen" -#: src/icehelp.cc:1360 -msgid "Find next" -msgstr "Weitersuchen" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: History software +#: src/fdospecgen.h:670 src/fdospecgen.h:676 +msgid "History" +msgstr "Geschichte" -#: src/icehelp.cc:1360 -msgid "F3" -msgstr "F3" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Software for philosophy, psychology and other humanities +#: src/fdospecgen.h:682 src/fdospecgen.h:688 +msgid "Humanities" +msgstr "Geisteswissenschaften" -#: src/icehelp.cc:1362 -msgid "Open in Browser" -msgstr "In Browser öffnen" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: IDE application +#: src/fdospecgen.h:694 +msgid "IDE" +msgstr "IDE" -#: src/icehelp.cc:1362 -msgid "Ctrl+B" -msgstr "Strg+B" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An IRC client +#: src/fdospecgen.h:700 +msgid "IRCClient" +msgstr "IRC-Client" -#: src/icehelp.cc:1364 -msgid "Reload" -msgstr "Neu laden" +#: src/icesm.cc:519 +msgid "IceWM crash response" +msgstr "IceWM-Absturz-Reaktion" -#: src/icehelp.cc:1364 src/icesame.cc:60 -msgid "Ctrl+R" -msgstr "Strg+R" +#: src/icesh.cc:2290 +msgid "IceWM tray option" +msgstr "IceWM-Trayoption" -#: src/icehelp.cc:1365 src/icesame.cc:62 src/iceview.cc:63 src/wmbutton.cc:147 -msgid "Close" -msgstr "Schließen" +#: src/wmprog.cc:373 +msgid "Ice_Sound(1)" +msgstr "Ice_Sound(1)" -#: src/icehelp.cc:1365 src/icesame.cc:62 src/iceview.cc:63 -msgid "Ctrl+Q" -msgstr "Strg+Q" +#: src/icehelp.cc:1374 +msgid "Icesound(1)" +msgstr "Icesound(1)" #: src/icehelp.cc:1370 msgid "Icewm(1)" msgstr "Icewm(1)" -#: src/icehelp.cc:1370 -msgid "Ctrl+I" -msgstr "Strg+I" +#: src/wmprog.cc:372 +msgid "Icewm_Bg(1)" +msgstr "Icewm_Bg(1)" #: src/icehelp.cc:1372 msgid "Icewmbg(1)" msgstr "Icewmbg(1)" -#: src/icehelp.cc:1374 -msgid "Icesound(1)" -msgstr "Icesound(1)" +#: src/icelist.cc:61 +msgid "Icon View" +msgstr "Symbolansicht" -#: src/icehelp.cc:1376 -msgid "FAQ" -msgstr "FAQ" +#: src/icehelp.cc:2592 +#, c-format +msgid "Ignoring option '%s'" +msgstr "Option '%s' wird ignoriert" -#: src/icehelp.cc:1378 -msgid "Manual" -msgstr "Handbuch" +#: src/wpixres.cc:93 src/wpixres.cc:100 +#, c-format +msgid "Image not readable: %s" +msgstr "Bild nicht lesbar: %s" -#: src/icehelp.cc:1378 -msgid "Ctrl+M" -msgstr "Strg+M" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Image Processing software +#: src/fdospecgen.h:706 src/fdospecgen.h:712 +msgid "ImageProcessing" +msgstr "Bildverarbeitung" -#: src/icehelp.cc:1380 -msgid "Support" -msgstr "Unterstützung" +#: src/yurl.cc:161 +#, c-format +msgid "Incomplete hex escape in URL at position %d." +msgstr "Unvollständiges hex escape in der URL an der Position %d." -#: src/icehelp.cc:1382 -msgid "Theme Howto" -msgstr "Theme HowTo" +#: src/icehelp.cc:1357 +msgid "Index" +msgstr "Index" -#: src/icehelp.cc:1382 src/iceview.cc:60 -msgid "Ctrl+T" -msgstr "Strg+T" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An instant messaging client +#: src/fdospecgen.h:718 +msgid "InstantMessaging" +msgstr "Instant-Messaging" -#: src/icehelp.cc:1384 -msgid "Website" -msgstr "Webseite" +#: src/apppstatus.cc:268 +#, c-format +msgid "" +"Interface %s:\n" +" Current rate (in/out):\t%li %s/%li %s\n" +" Current average (in/out):\t%lli %s/%lli %s\n" +" Transferred (in/out):\t%lli %s/%lli %s\n" +" Online time:\t%ld:%02ld:%02ld%s%s" +msgstr "" +"Schnittstelle %s:\n" +" Aktueller Durchsatz (ein/aus):\t%li %s/%li %s\n" +" Aktueller Durchschnitt (ein/aus):\t%lli %s/%lli %s\n" +" Gesamt (ein/aus):\t%lli %s/%lli %s\n" +" Onlinezeit:\t%ld:%02ld:%02ld%s%s" -#: src/icehelp.cc:1384 src/iceview.cc:61 -msgid "Ctrl+W" -msgstr "Strg+W" +#: src/icesh.cc:4516 +#, c-format +msgid "Invalid PID: `%s'" +msgstr "Ungültige PID: `%s'" -#: src/icehelp.cc:1386 -msgid "Github" -msgstr "Github" - -#: src/icehelp.cc:1390 src/yinputline.cc:19 -msgid "Ctrl+X" -msgstr "Strg+X" - -#: src/icehelp.cc:1395 src/yinputline.cc:20 -msgid "Ctrl+V" -msgstr "Strg+V" +#: src/icesh.cc:3795 +#, c-format +msgid "Invalid Xinerama: `%s'." +msgstr "Ungültiges Xinemara: `%s'." -#: src/icehelp.cc:2204 -msgid "Unsupported protocol." -msgstr "Nicht unterstütztes Protokoll." +#: src/icesh.cc:2729 src/icesh.cc:4150 src/icesh.cc:4200 src/icesh.cc:5497 +#, c-format +msgid "Invalid argument: `%s'" +msgstr "Ungültiges Argument: `%s'" -#: src/icehelp.cc:2283 +#: src/icesh.cc:4175 #, c-format -msgid "Invalid path: %s\n" -msgstr "Ungültiger Pfad: %s\n" +msgid "Invalid expression: `%s'" +msgstr "Ungültiger Ausdruck: `%s`" -#: src/icehelp.cc:2307 -msgid "Path does not refer to a file." -msgstr "Der Pfad führt zu keiner Datei." +#: src/yurl.cc:168 +#, c-format +msgid "Invalid hex escape in URL at position %d." +msgstr "Ungültiges hex escape in der URL an der Position %d." -#: src/icehelp.cc:2312 -msgid "Failed to open file for reading." -msgstr "Konnte nicht zum lesen geöffnet werden." +#: src/icesh.cc:4549 +#, c-format +msgid "Invalid layer: `%s'." +msgstr "Ungültige Schicht: `%s'." -#: src/icehelp.cc:2341 -msgid "Failed to create a temporary file" -msgstr "Erstellung einer temporären Datei ist fehlgeschlagen" +#: src/amailbox.cc:66 +#, c-format +msgid "Invalid mailbox path: \"%s\"" +msgstr "Ungültiger Mailbox-Pfad: \"%s\"" -#: src/icehelp.cc:2431 +#: src/amailbox.cc:156 #, c-format -msgid "Failed to execute system(%s) (%d)" -msgstr "Ausführung vom system(%s) ist fehlgeschlagen (%d)" +msgid "Invalid mailbox port: \"%s\"" +msgstr "Ungültiger Mailbox-Port: \"%s\"" -#: src/icehelp.cc:2453 +#: src/amailbox.cc:64 #, c-format -msgid "Failed to decompress %s" -msgstr "Konnte %s nicht entpacken" +msgid "Invalid mailbox protocol: \"%s\"" +msgstr "Unbekanntes E-Mail-Protokoll: \"%s\"" -#: src/icehelp.cc:2461 -msgid "Could not locate curl or wget in PATH" -msgstr "curl oder wget konnten in PATH nicht gefunden werden" +#: src/ylocale.cc:239 +#, c-format +msgid "Invalid multibyte string \"%s\": %s" +msgstr "Ungültige Multibyte-Zeichenkette \"%s\": %s" -#: src/icehelp.cc:2465 -msgid "Unsafe characters in URL" -msgstr "Unsichere Zeichen in der URL" +#: src/icehelp.cc:2283 +#, c-format +msgid "Invalid path: %s\n" +msgstr "Ungültiger Pfad: %s\n" -#: src/icehelp.cc:2502 +#: src/icesh.cc:2700 src/icesh.cc:4576 src/icesh.cc:5176 #, c-format -msgid "" -"Usage: %s [OPTIONS] [ FILENAME | URL ]\n" -"\n" -"IceHelp is a very simple HTML browser for the IceWM window manager.\n" -"It can display a HTML document from file, or browse a website.\n" -"It remembers visited pages in a history, which is navigable\n" -"by key bindings and a context menu (right mouse click).\n" -"It neither supports rendering of images nor JavaScript.\n" -"If no file or URL is given it will display the IceWM Manual\n" -"from %s.\n" -"\n" -"Options:\n" -" -d, --display=NAME NAME of the X server to use.\n" -" --sync Synchronize X11 commands.\n" -"\n" -" -B Display the IceWM icewmbg manpage.\n" -" -b, --bugs Display the IceWM bug reports (primitively).\n" -" -f, --faq Display the IceWM FAQ and Howto.\n" -" -g Display the IceWM Github website.\n" -" -i, --icewm Display the IceWM icewm manpage.\n" -" -m, --manual Display the IceWM Manual (default).\n" -" -s Display the IceWM icesound manpage.\n" -" -t, --theme Display the IceWM themes Howto.\n" -" -w, --website Display the IceWM website.\n" -"\n" -" -V, --version Prints version information and exits.\n" -" -h, --help Prints this usage screen and exits.\n" -"\n" -"Environment variables:\n" -" DISPLAY=NAME Name of the X server to use.\n" -"\n" -"To report bugs, support requests, comments please visit:\n" -"%s\n" -"\n" -msgstr "" -"Syntax: %s [OPTIONEN] [ DATEINAME | URL ]\n" -"\n" -"IceHelp ist ein sehr einfacher HTML-Browser für den IceWM-Fenstermanager.\n" -"Er kann zum Anzeigen eines HTML-Dokuments aus einer Datei oder Browsen " -"einer \n" -"Website verwendet werden. Die besuchten Seiten werden im Verlauf " -"gespeichert,\n" -"durch den Sie mit Tastenkombinationen und einem Kontextmenü (Klicken mit " -"der \n" -"rechten Maustaste) navigieren können. Der Browser unterstützt weder die " -"Darstellung \n" -"von Bildern noch JavaScript. Wenn keine Datei oder URL angegeben wird, wird " -"das \n" -"IceWM-Handbuch unter %s angezeigt.\n" -"\n" -"Optionen:\n" -" -d, --display=NAME NAME des zu verwendenden X-Servers.\n" -" --sync X11-Befehle synchronisieren.\n" -"\n" -" -B IceWM icewmbg-Hilfeseite anzeigen.\n" -" -b, --bugs IceWM-Fehlerberichte anzeigen (einfach).\n" -" -f, --faq IceWM FAQ und Howto anzeigen.\n" -" -g IceWM Github-Webseite anzeigen.\n" -" -i, --icewm IceWM icewm-Hilfeseite anzeigen.\n" -" -m, --manual IceWM-Handbuch anzeigen (Standard).\n" -" -s IceWM icesound-Hilfeseite anzeigen.\n" -" -t, --theme Howto für IceWM-Themen anzeigen.\n" -" -w, --website IceWM-Webseite anzeigen.\n" -"\n" -" -V, --version Versionsinformationen ausgeben und beenden.\n" -" -h, --help Hilfebildschirm ausgeben und beenden.\n" -"\n" -"Umgebungsvariablen:\n" -" DISPLAY=NAME Name des zu verwendenden X-Servers.\n" -"\n" -"Für Fehlerberichte, Support-Anfragen, Kommentare besuchen Sie bitte:\n" -"%s\n" -"\n" +msgid "Invalid state: `%s'." +msgstr "Ungültiger Status: `%s'." -#: src/icehelp.cc:2592 +#: src/icesh.cc:4500 #, c-format -msgid "Ignoring option '%s'" -msgstr "Option '%s' wird ignoriert" +msgid "Invalid window identifier: `%s'" +msgstr "Ungültiger Fensterbezeichner: `%s`" -#: src/icelist.cc:60 -msgid "List View" -msgstr "Listenansicht" +#: src/icesh.cc:1778 +#, c-format +msgid "Invalid workspace name: `%s'" +msgstr "Ungültiger Name des Arbeitsbereichs: `%s`" -#: src/icelist.cc:61 -msgid "Icon View" -msgstr "Symbolansicht" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on Java GUI libraries, such as AWT or Swing +#: src/fdospecgen.h:724 +msgid "Java" +msgstr "Java" -#: src/icelist.cc:65 -msgid "Open" -msgstr "Öffnen" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on KDE libraries +#: src/fdospecgen.h:80 +msgid "KDE" +msgstr "KDE" -#: src/icesame.cc:57 -msgid "Undo" -msgstr "Rückgängig" +#: src/akeyboard.cc:153 +msgid "Keyboard" +msgstr "Tastatur" -#: src/icesame.cc:57 -msgid "Ctrl+Z" -msgstr "Strg+Z" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A game for kids +#: src/fdospecgen.h:730 +msgid "KidsGame" +msgstr "Kinderspiele" -#: src/icesame.cc:59 -msgid "New" -msgstr "Neu" +# +#: src/wmframe.cc:1971 +msgid "Kill Client: " +msgstr "Client töten: " -#: src/icesame.cc:59 -msgid "Ctrl+N" -msgstr "Strg+N" +#: src/wmwinlist.cc:473 +msgid "Kill _Process" +msgstr "Prozess _töten" -#: src/icesame.cc:60 -msgid "Restart" -msgstr "Neustart" +#: src/wmapp.cc:671 src/wmwinlist.cc:447 +msgid "La_yer" +msgstr "_Ebene" -#: src/icesame.cc:65 -msgid "Same Game" -msgstr "Gleiches Spiel" +#: src/wmabout.cc:57 +msgid "Language:" +msgstr "Sprache:" -#: src/icesh.cc:76 -msgid "For help please consult the man page icesh(1).\n" -msgstr "Für Hilfe bitte die Manpage (1) hinzuziehen.\n" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Software to learn foreign languages +#: src/fdospecgen.h:736 src/fdospecgen.h:742 +msgid "Languages" +msgstr "Sprachen" -#: src/icesh.cc:1668 -#, c-format -msgid "Named symbols of the domain `%s' (numeric range: %ld-%ld):\n" -msgstr "Benannte Symbole aus der Domain `%s` (Wertebereich: %ld-%ld):\n" +#: src/wmapp.cc:617 +msgid "Left Half" +msgstr "Linke Hälfte" -#: src/icesh.cc:1737 -#, c-format -msgid "Workspace out of range: %ld" -msgstr "Arbeitsbereich außerhalb des Wertebereichs: %ld" +#: src/wmapp.cc:685 +msgid "Limit _Workarea" +msgstr "_Beschränke Arbeitsfläche" -#: src/icesh.cc:1758 -#, c-format -msgid "Invalid workspace name: `%s'" -msgstr "Ungültiger Name des Arbeitsbereichs: `%s`" +#: src/icelist.cc:60 +msgid "List View" +msgstr "Listenansicht" -#: src/icesh.cc:2269 -msgid "GNOME window layer" -msgstr "GNOME-Fensterebene" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Literature software +#: src/fdospecgen.h:748 src/fdospecgen.h:754 +msgid "Literature" +msgstr "Literatur" -#: src/icesh.cc:2270 -msgid "IceWM tray option" -msgstr "IceWM-Trayoption" +#: src/acpustatus.cc:607 +msgid "Load: " +msgstr "Last: " -#: src/icesh.cc:2271 -msgid "Gravity symbols" -msgstr "Gravitationssymbole" +#: src/ycursor.cc:135 +#, c-format +msgid "Loading of pixmap \"%s\" failed" +msgstr "Laden der Bilddatei \"%s\" fehlgeschlagen" -#: src/icesh.cc:2272 -msgid "Motif functions" -msgstr "Motif-Funktionen" +#: src/ycursor.cc:110 +#, c-format +msgid "Loading of pixmap \"%s\" failed: %s" +msgstr "Laden der Bilddatei \"%s\" fehlgeschlagen: %s" -#: src/icesh.cc:2273 -msgid "Motif decorations" -msgstr "Motif-Ausstattung" +#: src/wmdialog.cc:85 +msgid "Loc_k Workstation" +msgstr "Arbeitsplatz _sperren" -#: src/icesh.cc:2274 -msgid "EWMH window state" -msgstr "EWMH-Fensterzustand" +#: src/ylocale.cc:59 +msgid "Locale not supported by C library or Xlib. Falling back to 'C' locale'." +msgstr "" +"Lokale wird von der C-Bibliothek nicht unterstützt. Es wird auf die lokale " +"Variable 'C' zurückgegriffen." -#: src/icesh.cc:2356 src/icesh.cc:2429 -#, c-format -msgid "workspace #%d: `%s'\n" -msgstr "Arbeitsbereich #%d: `%s`\n" +#: src/wmapp.cc:533 +msgid "Lock _Workstation" +msgstr "Arbeitsplatz _sperren" -#: src/icesh.cc:2680 src/icesh.cc:4511 src/icesh.cc:5108 -#, c-format -msgid "Invalid state: `%s'." -msgstr "Ungültiger Status: `%s'." +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Logic games like puzzles, etc +#: src/fdospecgen.h:760 +msgid "LogicGame" +msgstr "Logikspiel" -#: src/icesh.cc:2709 src/icesh.cc:4090 src/icesh.cc:4140 src/icesh.cc:5429 -#, c-format -msgid "Invalid argument: `%s'" -msgstr "Ungültiges Argument: `%s'" +#: src/wmapp.cc:1950 +msgid "" +"Logout will close all active applications.\n" +"Proceed?" +msgstr "" +"Beim Abmelden werden alle aktiven Anwendungen geschlossen.\n" +"Fortfahren?" -#: src/icesh.cc:3710 -#, c-format -msgid "Cannot get geometry of window 0x%lx" -msgstr "Geometrie von Fenster 0x%lx kann nicht abgerufen werden" +#: src/amailbox.cc:961 +msgid "MAIL" +msgstr "MAIL" -#: src/icesh.cc:3735 -#, c-format -msgid "Invalid Xinerama: `%s'." -msgstr "Ungültiges Xinemara: `%s'." +#: src/amemstatus.cc:148 +msgid "MB" +msgstr "MB" -#: src/icesh.cc:3867 src/icesh.cc:3875 src/wmconfig.cc:139 src/wmsave.cc:65 -#: src/wmsave.cc:298 src/wmsave.cc:301 -#, c-format -msgid "Unable to write to %s" -msgstr "Kann nicht in %s schreiben" +#: src/amemstatus.cc:262 +msgid "MEM" +msgstr "SPEICHER" -#: src/icesh.cc:4106 -#, c-format -msgid "Action `%s' requires at least %d arguments." -msgstr "Aktion `%s` benötigt mindestens %d Argumente." +#: src/wmapp.cc:650 src/wmwinlist.cc:438 +msgid "Ma_ximize" +msgstr "Ma_ximieren" -#: src/icesh.cc:4115 -#, c-format -msgid "Invalid expression: `%s'" -msgstr "Ungültiger Ausdruck: `%s`" +#: src/icehelp.cc:1378 +msgid "Manual" +msgstr "Handbuch" -#: src/icesh.cc:4126 src/icesound.cc:800 src/icewmbg.cc:1087 -#: src/icewmhint.cc:37 src/wmapp.cc:1293 src/yxapp.cc:1049 -#, c-format -msgid "Can't open display: %s. X must be running and $DISPLAY set." -msgstr "" -"Das Display kann nicht geöffnet werden: %s. Der X muss laufen und $DISPLAY " -"gesetzt sein." +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Software for viewing maps, navigation, mapping, GPS +#: src/fdospecgen.h:766 src/fdospecgen.h:772 src/fdospecgen.h:778 +msgid "Maps" +msgstr "Karten" -#: src/icesh.cc:4242 -#, c-format -msgid "Unexpected: `%s'." -msgstr "Unerwartet: '%s'." +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Math software +#: src/fdospecgen.h:106 src/fdospecgen.h:114 src/fdospecgen.h:784 +#: src/fdospecgen.h:790 +msgid "Math" +msgstr "Mathe" -#: src/icesh.cc:4274 -msgid "No windows found." -msgstr "Keine Fenster gefunden." +#: src/wmbutton.cc:133 +msgid "Maximize" +msgstr "Maximieren" -#: src/icesh.cc:4290 -msgid "No actions specified." -msgstr "Keine Aktionen angegeben." +#: src/wmapp.cc:652 src/wmwinlist.cc:440 +msgid "MaximizeHori_z" +msgstr "MaximierenHori_z" -#: src/icesh.cc:4435 -#, c-format -msgid "Invalid window identifier: `%s'" -msgstr "Ungültiger Fensterbezeichner: `%s`" +#: src/wmapp.cc:651 src/wmwinlist.cc:439 +msgid "Maximize_Vert" +msgstr "Maximieren_Vert" -#: src/icesh.cc:4451 -#, c-format -msgid "Invalid PID: `%s'" -msgstr "Ungültige PID: `%s'" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Medical software +#: src/fdospecgen.h:796 src/fdospecgen.h:802 +msgid "MedicalSoftware" +msgstr "Medizinische Software" -#: src/icesh.cc:4484 -#, c-format -msgid "Invalid layer: `%s'." -msgstr "Ungültige Schicht: `%s'." +#: src/amemstatus.cc:176 +msgid "Memory Total: " +msgstr "Speicher Total: " -#: src/icesh.cc:5560 -#, c-format -msgid "Unknown action: `%s'" -msgstr "Unbekannte Aktion: `%s`" +#: src/wmapp.cc:648 src/wmwinlist.cc:437 +msgid "Mi_nimize" +msgstr "Mi_nimieren" -#: src/iceskt.cc:41 +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An app related to MIDI +#: src/fdospecgen.h:88 +msgid "Midi" +msgstr "Midi" + +#: src/wmbutton.cc:137 +msgid "Minimize" +msgstr "Minimieren" + +#: src/yfontcore.cc:233 #, c-format -msgid "Socket error: %d" -msgstr "Socketfehler: %d" +msgid "Missing codesets for fontset \"%s\":" +msgstr "Fehlende Zeichensätze im Schriftsatz \"%s\":" -#: src/icesm.cc:69 -msgid "" -" -c, --config=FILE Let IceWM load preferences from FILE.\n" -" -t, --theme=FILE Let IceWM load the theme from FILE.\n" -"\n" -" -d, --display=NAME Use NAME to connect to the X server.\n" -" -a, --alpha Use a 32-bit visual for translucency.\n" -" --sync Synchronize communication with X11 server.\n" -"\n" -" -i, --icewm=FILE Use FILE as the IceWM window manager.\n" -" -o, --output=FILE Redirect all output to FILE.\n" -"\n" -" -b, --nobg Do not start icewmbg.\n" -" -n, --notray Do not start icewmtray.\n" -" -s, --sound Also start icesound.\n" -msgstr "" -" -c, --config=DATEI Lässt IceWM Prioritäten aus DATEI laden.\n" -" -t, --theme=DATEI Lässt IceWM das Thema aus DATEI laden.\n" -"\n" -" -d, --display=NAME Verwendet NAME zur Verbindung mit dem X-Server.\n" -" -a, --alpha Verwendet einen 32-Bit-Sichtkontakt zur " -"Lichtdurchlässigkeit.\n" -" --sync Synchronisierung der Kommunikation mit dem X11-" -"Server.\n" -"\n" -" -i, --icewm=DATEI Verwendet DATEI als IceWM Window Manager.\n" -" -o, --output=DATEI Alle Ausgaben in DATEI umleiten\n" -"\n" -" -b, --nobg Nicht icewmbg starten.\n" -" -n, --notray Nicht icewmtray starten.\n" -" -s, --sound Auch icesound starten.\n" +#: src/wmmenu.cc:37 +msgid "Missing command argument" +msgstr "Fehlendes Argument für Kommandozeilenparameter" -#: src/icesm.cc:85 -msgid "" -"\n" -"Debugging options:\n" -" -v, --valgrind Let \"/usr/bin/valgrind\" run icewm.\n" -" Thoroughly examines the execution of icewm.\n" -" -g, --catchsegv Let \"/usr/bin/catchsegv\" run icewm.\n" -" Gives a backtrace if icewm segfaults.\n" -msgstr "" -"\n" -"Debugging-Optionen:\n" -" -v, --valgrind Lässt \"/usr/bin/valgrind\" icewm ausführen.\n" -" Untersucht gründlich die Ausführung von icewm.\n" -" -g, --catchsegv Lässt \"/usr/bin/catchsegv\" icewm ausführen.\n" -" Gibt einen Backtrace aus, wenn bei icewm eine " -"Schutzverletzung auftritt.\n" +#: src/wmmenu.cc:351 +msgid "Missing filename argument to include statement" +msgstr "Fehlendes Dateinamen-Argument um einen Bericht hinzuzufügen" -#: src/icesm.cc:188 -#, c-format -msgid "Unknown option '%s'" -msgstr "Unbekannte Option: '%s'" +#: src/wmmgr.cc:3700 +msgid "Missing program setxkbmap" +msgstr "Fehlendes Program: 'setxkbmap'" -#: src/icesm.cc:462 src/icesm.cc:622 -#, c-format -msgid "restart %s." -msgstr "Neustart %s." +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Just a mixer +#: src/fdospecgen.h:96 +msgid "Mixer" +msgstr "Mixer" -#: src/icesm.cc:513 -msgid "" -" IceWM crashed for the second time in 10 seconds. \n" -" Do you wish to:\n" -"\n" -"\t1: Restart IceWM?\n" -"\t2: Abort this session?\n" -"\t3: Run a terminal?\n" -msgstr "" -" IceWM stürzte das zweite Mal in 10 sekunden ab. \n" -" Möchten Sie:\n" -"\n" -"1: IceWM neu starten?\n" -"2: Diese Sitzung abbrechen?\n" -"3: Ein Terminal laufen lassen?\n" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Monitor application/applet that monitors some resource or activity +#: src/fdospecgen.h:808 src/fdospecgen.h:814 +msgid "Monitor" +msgstr "Monitor" -#: src/icesm.cc:519 -msgid "IceWM crash response" -msgstr "IceWM-Absturz-Reaktion" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on Motif libraries +#: src/fdospecgen.h:820 +msgid "Motif" +msgstr "Motiv" -#: src/icesound.cc:211 src/icesound.cc:319 src/icesound.cc:479 -#, c-format -msgid "Playing sample #%d (%s)" -msgstr "Spiele Sample #%d (%s)" +#: src/icesh.cc:2293 +msgid "Motif decorations" +msgstr "Motif-Ausstattung" -#: src/icesound.cc:329 -#, c-format -msgid "%s: Invalid number of channels" -msgstr "%s: Ungültige Anzahl an Kanälen" +#: src/icesh.cc:2292 +msgid "Motif functions" +msgstr "Motif-Funktionen" -#: src/icesound.cc:335 src/icesound.cc:340 -msgid "Could not set OSS channels" -msgstr "Konnte OSS-Kanäle nicht festlegen" +#: src/wmapp.cc:678 src/wmwinlist.cc:450 +msgid "Move _To" +msgstr "Verschieben _nach" -#: src/icesound.cc:345 src/icesound.cc:373 -msgid "Could not sync OSS" -msgstr "Konnte OSS nicht synchronisieren" +#: src/wmapp.cc:607 src/wmwinlist.cc:369 +msgid "Move to New _Window" +msgstr "In neues _Fenster verschieben" -#: src/icesound.cc:357 -msgid "OSS write failed" -msgstr "Schreibfehler bei OSS" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Musical software +#: src/fdospecgen.h:826 src/fdospecgen.h:832 +msgid "Music" +msgstr "Musik" -#: src/icesound.cc:361 +#: src/apppstatus.cc:705 +msgid "NET" +msgstr "NETZ" + +#: src/icesh.cc:1688 #, c-format -msgid "OSS incomplete write (%d/%d)" -msgstr "Unvollständiger Schreibvorgang bei OSS (%d/%d)" +msgid "Named symbols of the domain `%s' (numeric range: %ld-%ld):\n" +msgstr "Benannte Symbole aus der Domain `%s` (Wertebereich: %ld-%ld):\n" -#: src/icesound.cc:368 -msgid "Could not post OSS" -msgstr "Konnte OSS nicht versenden" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Network application such as a web browser +#: src/fdospecgen.h:372 src/fdospecgen.h:480 src/fdospecgen.h:534 +#: src/fdospecgen.h:564 src/fdospecgen.h:582 src/fdospecgen.h:660 +#: src/fdospecgen.h:702 src/fdospecgen.h:720 src/fdospecgen.h:816 +#: src/fdospecgen.h:840 src/fdospecgen.h:846 src/fdospecgen.h:966 +#: src/fdospecgen.h:1074 src/fdospecgen.h:1110 src/fdospecgen.h:1128 +#: src/fdospecgen.h:1140 src/fdospecgen.h:1182 +msgid "Network" +msgstr "Netzwerk" -#: src/icesound.cc:397 -#, c-format -msgid "Could not open OSS device %s" -msgstr "Konnte OSS-Gerät %s nicht öffnen" +#: src/icesame.cc:59 +msgid "New" +msgstr "Neu" -#: src/icesound.cc:402 -msgid "Could not set OSS stereo" -msgstr "Konnte OSS-Stereo nicht festlegen" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A news reader or a news ticker +#: src/fdospecgen.h:838 +msgid "News" +msgstr "Neuigkeiten" -#: src/icesound.cc:407 -msgid "Could not reset OSS DSP" -msgstr "Konnte OSS-DSP nicht zurücksetzen" +#: src/icehelp.cc:1354 +msgid "Next" +msgstr "Nächste" -#: src/icesound.cc:412 -msgid "Could not set OSS format" -msgstr "Konnte OSS-Format nicht einstellen" +#: src/icesh.cc:4350 +msgid "No actions specified." +msgstr "Keine Aktionen angegeben." -#: src/icesound.cc:499 +#: src/icesound.cc:785 #, c-format -msgid "ao_open_live failed with %d" -msgstr "ao_open_live ist mit %d fehlgeschlagen" +msgid "No audio for %s" +msgstr "Kein Audio für %s" -#: src/icesound.cc:510 -msgid "ao_play failed" -msgstr "ao_play ist fehlgeschlagen" +#: src/icesh.cc:4334 +msgid "No windows found." +msgstr "Keine Fenster gefunden." -#: src/icesound.cc:680 -#, c-format -msgid "Unrecognized option: %s\n" -msgstr "Nicht erkannte Option: %s\n" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Numerical analysis software +#: src/fdospecgen.h:104 src/fdospecgen.h:112 +msgid "NumericalAnalysis" +msgstr "Numerische Analysis" -#: src/icesound.cc:683 src/icesound.cc:978 -#, c-format -msgid "Unrecognized argument: %s\n" -msgstr "Nicht erkanntes Argument: %s\n" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Optical character recognition application +#: src/fdospecgen.h:120 +msgid "OCR" +msgstr "Optische Zeichenerkennung" -#: src/icesound.cc:694 +#: src/icesound.cc:361 #, c-format -msgid "" -"Usage: %s [OPTION]...\n" -"\n" -"Plays audio files on GUI events raised by IceWM.\n" -"The currently configured sound interfaces are: %s.\n" -"Icesound will choose the first of these which is usable.\n" -"\n" -"Options:\n" -"\n" -" -d, --display=DISPLAY X11 display used by IceWM (default: $DISPLAY).\n" -"\n" -" -s, --sample-dir=DIR Specifies a directory with sound files.\n" -" Default is $HOME/.config/icewm/sounds.\n" -"\n" -" -i, --interface=LIST Specifies audio output interfaces. One or more of:\n" -" %s separated by commas.\n" -"\n" -" -D, --device=DEVICE Backwards compatibility only: the default device. \n" -" Please prefer one of the -A/-O/-S options.\n" -"\n" -" -O, --oss=DEVICE Specifies the OSS device (default: \"%s\").\n" -"\n" -" -A, --alsa=DEVICE Specifies the ALSA device (default: \"%s\").\n" -"\n" -" -z, --snooze=millisecs Specifies the snooze interval between sound events\n" -" in milliseconds. Default is 500 milliseconds.\n" -"\n" -" -p, --play=sound Plays the given sound (name or number) and exits.\n" -"\n" -" -l, --list-files Lists the available sound file paths and exits.\n" -"\n" -" --list-sounds Lists the supported sound filenames and exits.\n" -"\n" -" --list-interfaces Lists the supported audio interfaces and exits.\n" -"\n" -" -v, --verbose Be verbose and print out each sound event.\n" -"\n" -" -V, --version Prints version information and exits.\n" -"\n" -" -h, --help Prints this help screen and exits.\n" -"\n" -"Return values:\n" -"\n" -" 0 Success.\n" -" 1 General error.\n" -" 2 Command line error.\n" -" 3 Subsystems error (ie cannot connect to server).\n" -"\n" -msgstr "" -"Syntax: %s [OPTION]...\n" -"\n" -"Spielt zu den von IceWM erzeugten GUI-Ereignissen passende Audiodateien.\n" -"Die momentan konfigurierten Sound-Schnittstellen sind: %s.\n" -"Icesound wird das Erste von den Brauchbaren verwenden.\n" -"\n" -"Optionen:\n" -"\n" -" -d, --display=DISPLAY X11 Display von IceWM verwendet (Standard: " -"$DISPLAY).\n" -"\n" -" -s, --sample-dir=VERZEICHNIS Ein Verzeichnis, das die zu spielenden " -"Audiodateien enthält.\n" -" Standard ist $HOME/.config/icewm/sounds.\n" -"\n" -" -i, --interface=LISTE Spezifiziert Audio-Output-Interfaces. Eins " -"oder mehr von:\n" -" %s separiert durch Kommas.\n" -"\n" -" -D, --device=GERÄT Nur Rückwärts-Kompatibilität: das Standard-" -"Gerät. \n" -" Bitte eine der Optionen -A/-O/-S bevorzugen.\n" -"\n" -" -O, --oss=GERÄT Spezifiziert das OSS-Gerät (Standard: \"%s\").\n" -"\n" -" -A, --alsa=GERÄT Spezifiziert das ALSA-Gerät (Standard: \"%s\").\n" -" \n" -" -z, --snooze=Millisek Spezifiziert das Snooze-Intervall zwischen " -"Soundereignissen\n" -" in Millisekunden. Standard ist 500 Millisekunden.\n" -"\n" -" -p, --play=Sound Spielt den gegebenen Sound (Name oder Nummer) und " -"beendet.\n" -"\n" -" -l, --list-files Listet alle verfügbaren Sound-Dateipfade und " -"beendet.\n" -"\n" -" --list-sounds Listet die unterstützten Sound-Dateinamen und " -"beendet.\n" -"\n" -" --list-interfaces Listet die unterstützten Audio-Interfaces und " -"beendet.\n" -"\n" -"-v, --verbose Extra ausführlich und gibt jedes Soundereignis " -"aus.\n" -"\n" -"-V, --version Zeigt die Programmversion und beendet.\n" -"\n" -"-h, --help Zeigt diese Hilfe an und beendet.\n" -"\n" -"Rückgabewerte:\n" -"\n" -"0 Erfolg.\n" -"1 Allgemeiner Fehler.\n" -"2 Ungültige Befehlszeile.\n" -"3 Fehler im Subsystem (d.h. Verbindungsaufbau zum Server gescheitert).\n" -"\n" +msgid "OSS incomplete write (%d/%d)" +msgstr "Unvollständiger Schreibvorgang bei OSS (%d/%d)" -#: src/icesound.cc:785 -#, c-format -msgid "No audio for %s" -msgstr "Kein Audio für %s" +#: src/icesound.cc:357 +msgid "OSS write failed" +msgstr "Schreibfehler bei OSS" -#: src/icesound.cc:862 -msgid "Could not get GUI event property" -msgstr "Konnte keine GUI-Event-Property erhalten" +#: src/wmapp.cc:679 src/wmwinlist.cc:451 +msgid "Occupy _All" +msgstr "_Alles Belegen" -#: src/icesound.cc:866 -#, c-format -msgid "Received invalid GUI event %d" -msgstr "Ungültiges GUI-Event %d erhalten" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An office type application +#: src/fdospecgen.h:354 src/fdospecgen.h:366 src/fdospecgen.h:426 +#: src/fdospecgen.h:462 src/fdospecgen.h:486 src/fdospecgen.h:540 +#: src/fdospecgen.h:594 src/fdospecgen.h:600 src/fdospecgen.h:852 +#: src/fdospecgen.h:870 src/fdospecgen.h:906 src/fdospecgen.h:924 +#: src/fdospecgen.h:936 src/fdospecgen.h:1062 src/fdospecgen.h:1122 +#: src/fdospecgen.h:1146 src/fdospecgen.h:1186 +msgid "Office" +msgstr "Büro" -#: src/icesound.cc:870 -#, c-format -msgid "Received GUI event %s" -msgstr "GUI-Event %s erhalten" +#: src/icelist.cc:65 +msgid "Open" +msgstr "Öffnen" -#: src/icesound.cc:884 -#, c-format -msgid "Too quick; ignoring %s." -msgstr "Zu schnell; %s wird ignoriert." +#: src/icehelp.cc:1362 +msgid "Open in Browser" +msgstr "In Browser öffnen" -#: src/icesound.cc:888 -#, c-format -msgid "Support for the %s interface not compiled." -msgstr "Die Unterstützung für das %s-Interface wurde nicht kompiliert." +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other +#: src/fdospecgen.h:32 src/fdospecgen.h:52 src/fdospecgen.h:60 +#: src/fdospecgen.h:76 src/fdospecgen.h:84 src/fdospecgen.h:188 +#: src/fdospecgen.h:228 src/fdospecgen.h:240 src/fdospecgen.h:342 +#: src/fdospecgen.h:408 src/fdospecgen.h:432 src/fdospecgen.h:498 +#: src/fdospecgen.h:528 src/fdospecgen.h:558 src/fdospecgen.h:606 +#: src/fdospecgen.h:726 src/fdospecgen.h:822 src/fdospecgen.h:942 +#: src/fdospecgen.h:1190 +msgid "Other" +msgstr "Sonstiges" -#: src/icesound.cc:921 +#: src/icewmhint.cc:57 #, c-format -msgid "Unsupported interface: %s." -msgstr "Nicht unterstütztes Interface: %s." +msgid "Out of memory (len=%d)." +msgstr "Speichermangel (len=%d)." -#: src/icesound.cc:930 -#, c-format -msgid "Using %s audio." -msgstr "%s Audio wird verwendet." +#: src/aapm.cc:203 src/aapm.cc:476 src/aapm.cc:635 +msgid "P" +msgstr "P" -#: src/icesound.cc:934 -#, c-format -msgid "Failed to connect to audio interfaces %s." -msgstr "Konnte sich nicht mit Audio-Schnittstellen %s verbinden." +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A P2P program +#: src/fdospecgen.h:844 +msgid "P2P" +msgstr "P2P" -#: src/icesound.cc:946 -#, c-format -msgid "Received signal %s: Terminating..." -msgstr "Signal %s erhalten: Beende das Programm..." +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Tool to manage your PDA +#: src/fdospecgen.h:850 +msgid "PDA" +msgstr "PDA" -#: src/icetray.cc:220 -msgid "" -" -n, --notify Notify parent process by sending signal USR1.\n" -" --display=NAME Use NAME to connect to the X server.\n" -" --sync Synchronize communication with X11 server.\n" -"\n" -" -c, --config=FILE Load preferences from FILE.\n" -" -t, --theme=FILE Load the theme from FILE.\n" -msgstr "" -" -n, --notify Eltern-Prozess mit dem Senden des Signals USR1 " -"benachrichtigen.\n" -" --display=NAME Verwenden von NAME um sich mit dem X-Server zu " -"verbinden.\n" -" --sync Synchronisation der Kommunikation mit dem X11-Server.\n" -"\n" -" -c, --config=DATEI Laden der Prioritäten aus DATEI.\n" -" -t, --theme=DATEI Laden des Themes aus DATEI.\n" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A package manager application +#: src/fdospecgen.h:856 +msgid "PackageManager" +msgstr "Paket-Manager" -#: src/iceview.cc:59 -msgid "Hex View" -msgstr "Hexadezimalansicht" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Parallel computing software +#: src/fdospecgen.h:128 src/fdospecgen.h:136 +msgid "ParallelComputing" +msgstr "Paralleles Rechnen" -#: src/iceview.cc:59 -msgid "Ctrl+H" -msgstr "Strg+H" +#: src/yinputline.cc:21 +msgid "Paste _Selection" +msgstr "Aus_wahl einfügen" -#: src/iceview.cc:60 -msgid "Expand Tabs" -msgstr "Tabs erweitern" +#: src/icehelp.cc:2307 +msgid "Path does not refer to a file." +msgstr "Der Pfad führt zu keiner Datei." -#: src/iceview.cc:61 -msgid "Wrap Lines" -msgstr "Lange Zeilen umbrechen" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Camera tools, etc. +#: src/fdospecgen.h:862 src/fdospecgen.h:868 +msgid "Photography" +msgstr "Fotografie" -#: src/icewmbg.cc:35 src/icewmbg.cc:372 +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Physics software +#: src/fdospecgen.h:874 src/fdospecgen.h:880 +msgid "Physics" +msgstr "Physik" + +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to play audio/video files +#: src/fdospecgen.h:886 src/fdospecgen.h:892 src/fdospecgen.h:898 +msgid "Player" +msgstr "Player" + +#: src/icesound.cc:211 src/icesound.cc:319 src/icesound.cc:479 #, c-format -msgid "Failed to load image '%s'." -msgstr "Konnte Bild '%s' nicht laden." +msgid "Playing sample #%d (%s)" +msgstr "Spiele Sample #%d (%s)" -#: src/icewmbg.cc:969 -msgid "" -"Usage: icewmbg [OPTIONS]\n" -"Where multiple values can be given they are separated by commas.\n" -"When image is a directory then all images from that directory are used.\n" -"\n" -"Options:\n" -" -p, --replace Replace an existing icewmbg.\n" -" -q, --quit Tell the running icewmbg to quit.\n" -" -r, --restart Tell the running icewmbg to restart itself.\n" -" -u, --shuffle Shuffle/reshuffle the list of background images.\n" -"\n" -" -c, --config=FILE Load preferences from FILE.\n" -" -t, --theme=NAME Load the theme with name NAME.\n" -"\n" -" -i, --image=FILE(S) Load background image(s) from FILE(S).\n" -" -k, --color=NAME(S) Use background color(s) from NAME(S).\n" -"\n" -" -s, --semis=FILE(S) Load transparency image(s) from FILE(S).\n" -" -x, --trans=NAME(S) Use transparency color(s) from NAME(S).\n" -"\n" -" -e, --center=0/1 Disable/Enable centering background.\n" -" -a, --scaled=0/1 Disable/Enable scaling background.\n" -" -m, --multi=0/1 Disable/Enable multihead background.\n" -" -y, --cycle=SECONDS Cycle backgrounds every SECONDS.\n" -"\n" -" --display=NAME Use NAME to connect to the X server.\n" -" --sync Synchronize communication with X11 server.\n" -"\n" -" -h, --help Print this usage screen and exit.\n" -" -V, --version Prints version information and exits.\n" -"\n" -"Loads desktop background according to preferences file:\n" -" DesktopBackgroundCenter - Display desktop background centered\n" -" DesktopBackgroundScaled - Display desktop background scaled\n" -" DesktopBackgroundColor - Desktop background color(s)\n" -" DesktopBackgroundImage - Desktop background image(s)\n" -" ShuffleBackgroundImages - Shuffle the list of background images\n" -" SupportSemitransparency - Support for semitransparent terminals\n" -" DesktopTransparencyColor - Semitransparency background color(s)\n" -" DesktopTransparencyImage - Semitransparency background image(s)\n" -" DesktopBackgroundMultihead - One background over all monitors\n" -" CycleBackgroundsPeriod - Seconds between cycling over backgrounds\n" -"\n" -" center:0 scaled:0 = tiled\n" -" center:1 scaled:0 = centered\n" -" center:1 scaled:1 = fill one dimension and keep aspect ratio\n" -" center:0 scaled:1 = fill both dimensions and keep aspect ratio\n" -"\n" -msgstr "" -"Aufruf: icewmbg [OPTIONEN]\n" -"Wo unterschiedliche Werte gegeben werden können, werden diese mit Kommas " -"getrennt.\n" -"Wenn ein Bild ein Verzeichnis ist, dann werden alle Bilder aus diesem " -"Verzeichnis verwendet.\n" -"\n" -"Optionen:\n" -" -p, --replace Ein bestehendes icewmbg ersetzen.\n" -" -q, --quit Dem laufenden icewmbg sagen sich zu beenden.\n" -" -r, --restart Dem laufenden icewmbg sagen sich selbst neu zu " -"starten.\n" -" -u, --shuffle Die Liste an Hintergrundbildern mischen/ " -"umstrukturieren.\n" -"\n" -" -c, --config=DATEI Prioritäten aus DATEI laden.\n" -" -t, --theme=DATEI Theme aus DATEI laden.\n" -"\n" -" -i, --image=DATEI(EN) Hintergrundbild(er) aus DATEI(EN) laden.\n" -" -k, --color=NAME(N) Hintergrundfarb(en) aus NAME(N) verwenden.\n" -"\n" -" -s, --semis=DATEI(EN) Nachvollziehbare Bilde(r) aus DATEI(EN) laden.\n" -" -x, --trans=NAME(N) Nachvollziehbare Farbe(n) aus NAME(N) verwenden.\n" -"\n" -" -e, --center=0/1 Zentrierten Hintergrund deaktivieren/aktivieren.\n" -" -a, --scaled=0/1 Skalierten Hintergrund deaktivieren/aktivieren.\n" -" -m, --multi=0/1 Multihead-Hintergrund deaktivieren/aktivieren.\n" -" -y, --cycle=SEKUNDEN Hintergründe alle SEKUNDEN ablaufen.\n" -"\n" -" --display=NAME NAME zur Verbindung mit den X-Server verwenden.\n" -" --sync Synchronisierung der Kommunikation mit dem X11-" -"Server.\n" -"\n" -" -h, --help Ausgabe der Verwendung und beenden.\n" -" -V, --version Ausgabe der Versionsinformationen und beenden.\n" -"\n" -"Lädt den Desktop-Hintergrund gemäß der Datei »preferences«\n" -" DesktopBackgroundCenter - Zeigt den Hintergrund zentriert an\n" -" DesktopBackgroundScaled - Zeigt den Hintergrund vergrössert an\n" -" SupportSemitransparency - Unterstützt semi-trasparente Fenster\n" -" DesktopBackgroundColor - Hintergrundfarbe des Desktops\n" -" DesktopBackgroundImage - Hintergrundbild des Desktops\n" -" ShuffleBackgroundImages - Mischung der Liste an Hintergrundbildern\n" -" DesktopTransparencyColor - Farbe, die semi-transp. Fenstern gemeldet wird\n" -" DesktopTransparencyImage - Bild, das semi-transp. Fenstern gemeldet wird\n" -" DesktopBackgroundMultihead - Ein Hintergrund über alle Monitore\n" -" CycleBackgroundsPeriod - Sekunden zwischen Abläufen über Hintergründen\n" -"\n" -" center:0 scaled:0 = gekachelt\n" -" center:1 scaled:0 = zentriert\n" -" center:1 scaled:1 = eine Dimension füllen und Seitenverhältnis beibehalten\n" -" center:0 scaled:1 = beide Dimensionen füllen und Seitenverhältnis " -"beibehalten\n" -"\n" - -#: src/icewmbg.cc:1248 src/wmapp.cc:1902 -#, c-format -msgid "Unrecognized option '%s'." -msgstr "Unbekannte Option: '%s'." - -#: src/icewmbg.cc:1335 -msgid "Cannot start, because another icewmbg is still running." -msgstr "Kann nicht starten, weil ein anderes icewmbg schon läuft." - -#: src/icewmhint.cc:20 -msgid "Usage: icewmhint class.instance option arg\n" -msgstr "Verwendung: icewmhint Klasse.Instanz Option Argument\n" - -#: src/icewmhint.cc:57 -#, c-format -msgid "Out of memory (len=%d)." -msgstr "Speichermangel (len=%d)." +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Presentation software +#: src/fdospecgen.h:904 +msgid "Presentation" +msgstr "Präsentation" -#: src/misc.cc:71 src/misc.cc:83 -msgid "Warning: " -msgstr "Warnung: " +#: src/icehelp.cc:1353 +msgid "Previous" +msgstr "Vorherige" -#: src/misc.cc:394 -#, c-format -msgid "" -"Usage: %s [OPTIONS]\n" -"Options:\n" -"%s\n" -" -C, --copying Prints license information and exits.\n" -" -V, --version Prints version information and exits.\n" -" -h, --help Prints this usage screen and exits.\n" -"\n" -msgstr "" -"Verwendung: %s [OPTIONEN]\n" -"Optionen:\n" -"%s\n" -" -C, --copying Gibt Lizenzinformationen aus und beendet.\n" -" -V, --version Gibt Versionsinformationen aus und beendet.\n" -" -h, --help Gibt die Verwendung/ Hilfe aus und beendet.\n" -"\n" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tool to manage printers +#: src/fdospecgen.h:26 +msgid "Printing" +msgstr "Drucken" -#: src/movesize.cc:859 -#, c-format -msgid "Unknown direction in move/resize request: %d" -msgstr "Unbekannte Richtung in Verschieben/Vergrößern-Anfrage: %d" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A profiling tool +#: src/fdospecgen.h:910 +msgid "Profiling" +msgstr "Profilerstellung" -#: src/upath.cc:172 -#, c-format -msgid "Unable to create directory %s" -msgstr "Kann Verzeichnis %s nicht erstellen" +#: src/wmprog.cc:422 +msgid "Programs" +msgstr "Programme" -#: src/wmabout.cc:29 -msgid "(C)" -msgstr "©" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Project management application +#: src/fdospecgen.h:916 src/fdospecgen.h:922 +msgid "ProjectManagement" +msgstr "Projektmanagement" -#: src/wmabout.cc:45 -msgid "Theme:" -msgstr "Theme:" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Desktop Publishing applications and Color Management tools +#: src/fdospecgen.h:928 src/fdospecgen.h:934 +msgid "Publishing" +msgstr "Veröffentlichen" -#: src/wmabout.cc:46 -msgid "Theme Description:" -msgstr "Theme-Beschreibung:" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: QT +#: src/fdospecgen.h:82 +msgid "QT" +msgstr "QT" -#: src/wmabout.cc:47 -msgid "Theme Author:" -msgstr "Autor des Themes:" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on Qt libraries +#: src/fdospecgen.h:50 src/fdospecgen.h:940 +msgid "Qt" +msgstr "Qt" -#: src/wmabout.cc:56 -msgid "CodeSet:" -msgstr "Kodierung:" +#: src/wmapp.cc:667 +msgid "R_aise" +msgstr "An_heben" -#: src/wmabout.cc:57 -msgid "Language:" -msgstr "Sprache:" +#: src/wmapp.cc:691 src/wmwinlist.cc:453 +msgid "R_ename title" +msgstr "Titel _umbenennen" -#: src/wmabout.cc:61 -msgid "DoubleBuffer" -msgstr "DoubleBuffer" +# +#: src/wmbutton.cc:124 +msgid "Raise/Lower" +msgstr "Anheben/Senken" -#: src/wmabout.cc:62 -msgid "AlphaBlending" -msgstr "AlphaBlending" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for viewing, creating, or processing raster (bitmap) graphics +#: src/fdospecgen.h:144 +msgid "RasterGraphics" +msgstr "Raster-Grafiken" -#: src/wmabout.cc:63 -msgid "Renderer:" -msgstr "Renderer:" +#: src/wmapp.cc:535 src/wmdialog.cc:89 +msgid "Re_boot" +msgstr "_Neustart" -#: src/wmabout.cc:71 -msgid "icewm - About" -msgstr "IceWM - Über" +#: src/icesound.cc:870 +#, c-format +msgid "Received GUI event %s" +msgstr "GUI-Event %s erhalten" -# -#: src/wmapp.cc:91 -msgid "A window manager is already running, use --replace to replace it" -msgstr "Ein Fenstermanager ist bereits aktiv, zum Ersetzen --replace verwenden" +#: src/icesound.cc:866 +#, c-format +msgid "Received invalid GUI event %d" +msgstr "Ungültiges GUI-Event %d erhalten" -#: src/wmapp.cc:107 +#: src/icesound.cc:946 #, c-format -msgid "Failed to become the owner of the %s selection" -msgstr "Konnte nicht der Besitzer der Auswahl von %s werden" +msgid "Received signal %s: Terminating..." +msgstr "Signal %s erhalten: Beende das Programm..." -#: src/wmapp.cc:111 -msgid "Waiting to replace the old window manager" -msgstr "Warte auf den Austausch vom alten Fenstermanager" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to record audio/video files +#: src/fdospecgen.h:946 src/fdospecgen.h:952 src/fdospecgen.h:958 +msgid "Recorder" +msgstr "Rekorder" -#: src/wmapp.cc:116 -msgid "done." -msgstr "erledigt." +#: src/icehelp.cc:1364 +msgid "Reload" +msgstr "Neu laden" -# OS/2 is dead, but... ;-) -#: src/wmapp.cc:529 -msgid "_Logout" -msgstr "_Abmelden" +#: src/wmdialog.cc:96 +msgid "Reload ke_ys" +msgstr "S_chlüssel neu laden" -#: src/wmapp.cc:530 -msgid "_Cancel logout" -msgstr "Abmelde_vorgang abbrechen" +#: src/wmdialog.cc:95 +msgid "Reload win_options" +msgstr "Win-_Optionen neu laden" -#: src/wmapp.cc:536 -msgid "Lock _Workstation" -msgstr "Arbeitsplatz _sperren" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tool to remotely manage your PC +#: src/fdospecgen.h:964 +msgid "RemoteAccess" +msgstr "Fernzugriff" -#: src/wmapp.cc:538 src/wmdialog.cc:89 -msgid "Re_boot" -msgstr "_Neustart" +#: src/wmframe.cc:1458 +msgid "Rename" +msgstr "Umbenennen" -#: src/wmapp.cc:540 src/wmdialog.cc:90 -msgid "Shut_down" -msgstr "_Herunterfahren" +#: src/wmframe.cc:1459 +msgid "Rename the window title" +msgstr "Fenstertitel umbenennen" -#: src/wmapp.cc:542 src/wmdialog.cc:86 -msgid "_Sleep mode" -msgstr "Schlaf-_Modus" +#: src/wmabout.cc:63 +msgid "Renderer:" +msgstr "Renderer:" -#: src/wmapp.cc:544 src/wmdialog.cc:91 -msgid "_Hibernate" -msgstr "_Tiefschlaf" +#: src/icesame.cc:60 +msgid "Restart" +msgstr "Neustart" -#: src/wmapp.cc:548 +#: src/wmapp.cc:545 msgid "Restart _Icewm" msgstr "_IceWM neu starten" -#: src/wmapp.cc:550 +#: src/wmapp.cc:547 msgid "Restart _Xterm" msgstr "_Xterm neu starten" -#: src/wmapp.cc:560 -msgid "_Menu" -msgstr "_Menü" +#: src/wmbutton.cc:131 +msgid "Restore" +msgstr "Wiederherstellen" -#: src/wmapp.cc:561 -msgid "_Above Dock" -msgstr "_Über Dock" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Applications like cvs or subversion +#: src/fdospecgen.h:970 +msgid "RevisionControl" +msgstr "Revisionskontrolle" -#: src/wmapp.cc:562 -msgid "_Dock" -msgstr "_Dock" +#: src/wmapp.cc:618 +msgid "Right Half" +msgstr "Rechte Hälfte" -#: src/wmapp.cc:563 -msgid "_OnTop" -msgstr "_Obenauf" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Robotics software +#: src/fdospecgen.h:976 src/fdospecgen.h:982 +msgid "Robotics" +msgstr "Robotik" -#: src/wmapp.cc:564 -msgid "_Normal" -msgstr "_Normal" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A role playing game +#: src/fdospecgen.h:988 +msgid "RolePlaying" +msgstr "Rollenspiel" -#: src/wmapp.cc:565 -msgid "_Below" -msgstr "_Darunter" +#: src/wmapp.cc:660 src/wmwinlist.cc:444 +msgid "Roll_up" +msgstr "Auf_rollen" -#: src/wmapp.cc:566 -msgid "D_esktop" -msgstr "D_esktop" +#: src/wmbutton.cc:141 +msgid "Rolldown" +msgstr "Herunterrollen" -#: src/wmapp.cc:610 src/wmwinlist.cc:381 -msgid "Move to New _Window" -msgstr "In neues _Fenster verschieben" +#: src/wmbutton.cc:143 +msgid "Rollup" +msgstr "Einrollen" -#: src/wmapp.cc:620 -msgid "Left Half" -msgstr "Linke Hälfte" +#: src/wmprog.cc:346 +msgid "S_trict mouse focus" +msgstr "Strenger _Maus-Fokus" -#: src/wmapp.cc:621 -msgid "Right Half" -msgstr "Rechte Hälfte" +#: src/icesame.cc:65 +msgid "Same Game" +msgstr "Gleiches Spiel" -#: src/wmapp.cc:622 -msgid "Top Half" -msgstr "Obere Hälfte" +#: src/wmpref.cc:101 +msgid "Save Modifications" +msgstr "Änderungen speichern" -#: src/wmapp.cc:623 -msgid "Bottom Half" -msgstr "Untere Hälfte" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Tool to scan a file/text +#: src/fdospecgen.h:122 src/fdospecgen.h:994 +msgid "Scanning" +msgstr "Scannen" -#: src/wmapp.cc:625 -msgid "Top Left" -msgstr "Oben links" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software +#: src/fdospecgen.h:116 src/fdospecgen.h:140 src/fdospecgen.h:264 +#: src/fdospecgen.h:276 src/fdospecgen.h:288 src/fdospecgen.h:318 +#: src/fdospecgen.h:384 src/fdospecgen.h:402 src/fdospecgen.h:420 +#: src/fdospecgen.h:444 src/fdospecgen.h:510 src/fdospecgen.h:522 +#: src/fdospecgen.h:624 src/fdospecgen.h:636 src/fdospecgen.h:648 +#: src/fdospecgen.h:678 src/fdospecgen.h:690 src/fdospecgen.h:714 +#: src/fdospecgen.h:744 src/fdospecgen.h:756 src/fdospecgen.h:774 +#: src/fdospecgen.h:792 src/fdospecgen.h:804 src/fdospecgen.h:882 +#: src/fdospecgen.h:984 src/fdospecgen.h:1032 src/fdospecgen.h:1050 +#: src/fdospecgen.h:1194 +msgid "Science" +msgstr "Wissenschaft" -#: src/wmapp.cc:626 -msgid "Top Right" -msgstr "Oben rechts" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Screensavers +#: src/fdospecgen.h:1198 +msgid "Screensavers" +msgstr "Bildschirmschoner" -#: src/wmapp.cc:627 -msgid "Bottom Left" -msgstr "Unten links" +#: src/wmprog.cc:460 +msgid "Se_ttings" +msgstr "_Einstellungen" -#: src/wmapp.cc:628 -msgid "Bottom Right" -msgstr "Unten rechts" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A security tool +#: src/fdospecgen.h:1000 src/fdospecgen.h:1006 +msgid "Security" +msgstr "Sicherheit" -#: src/wmapp.cc:629 -msgid "Center" -msgstr "Mitte" +#: src/yinputline.cc:23 +msgid "Select _All" +msgstr "_Alles auswählen" -#. TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout -#: src/wmapp.cc:631 src/wmtaskbar.cc:217 src/wmwinlist.cc:468 -#: src/wmwinlist.cc:501 -msgid "T_ile Horizontally" -msgstr "_Horizontal anordnen" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A sequencer +#: src/fdospecgen.h:152 +msgid "Sequencer" +msgstr "Sequenzer" -#. TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout -#: src/wmapp.cc:633 src/wmtaskbar.cc:215 src/wmwinlist.cc:467 -#: src/wmwinlist.cc:500 -msgid "Tile _Vertically" -msgstr "Ve_rtikal anordnen" +#: src/wmsession.cc:214 src/wmsession.cc:230 src/wmsession.cc:240 +#, c-format +msgid "Session Manager: Unknown line %s" +msgstr "Sitzungsmanager: Unbekannte Zeile %s" -#: src/wmapp.cc:645 src/wmwinlist.cc:448 -msgid "_Restore" -msgstr "_Wiederherstellen" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Settings applications +#: src/fdospecgen.h:28 src/fdospecgen.h:210 src/fdospecgen.h:474 +#: src/fdospecgen.h:666 src/fdospecgen.h:858 src/fdospecgen.h:1002 +#: src/fdospecgen.h:1202 +msgid "Settings" +msgstr "Einstellungen" -#: src/wmapp.cc:647 -msgid "_Move" -msgstr "_Verschieben" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A shooter game +#: src/fdospecgen.h:1012 +msgid "Shooter" +msgstr "Schütze" -#: src/wmapp.cc:649 -msgid "_Size" -msgstr "_Größe" +#: src/wmtaskbar.cc:372 +msgid "Show Desktop" +msgstr "Desktop anzeigen" -#: src/wmapp.cc:651 src/wmwinlist.cc:449 -msgid "Mi_nimize" -msgstr "Mi_nimieren" +#: src/wmtaskbar.cc:1025 +msgid "Show Taskbar" +msgstr "Taskleiste anzeigen" -#: src/wmapp.cc:653 src/wmwinlist.cc:450 -msgid "Ma_ximize" -msgstr "Ma_ximieren" +#: src/wmapp.cc:537 src/wmdialog.cc:90 +msgid "Shut_down" +msgstr "_Herunterfahren" -#: src/wmapp.cc:654 src/wmwinlist.cc:451 -msgid "Maximize_Vert" -msgstr "Maximieren_Vert" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A simulation game +#: src/fdospecgen.h:1018 +msgid "Simulation" +msgstr "Simulation" -#: src/wmapp.cc:655 src/wmwinlist.cc:452 -msgid "MaximizeHori_z" -msgstr "MaximierenHori_z" +#: src/iceskt.cc:41 +#, c-format +msgid "Socket error: %d" +msgstr "Socketfehler: %d" -#: src/wmapp.cc:658 src/wmwinlist.cc:453 -msgid "_Fullscreen" -msgstr "ganzer Bi_ldschirm" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Religious and spiritual software, theology +#: src/fdospecgen.h:1024 src/fdospecgen.h:1030 src/fdospecgen.h:1036 +msgid "Spirituality" +msgstr "Spiritualität" -#: src/wmapp.cc:661 src/wmwinlist.cc:455 -msgid "_Hide" -msgstr "Vers_tecken" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Sports software +#: src/fdospecgen.h:1042 src/fdospecgen.h:1048 +msgid "Sports" +msgstr "Sport" -#: src/wmapp.cc:663 src/wmwinlist.cc:456 -msgid "Roll_up" -msgstr "Auf_rollen" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A sports game +#: src/fdospecgen.h:1054 +msgid "SportsGame" +msgstr "Sportspiel" -#: src/wmapp.cc:670 -msgid "R_aise" -msgstr "An_heben" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A spreadsheet +#: src/fdospecgen.h:1060 +msgid "Spreadsheet" +msgstr "Tabellenkalkulation" -#: src/wmapp.cc:672 src/wmwinlist.cc:458 -msgid "_Lower" -msgstr "Sen_ken" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A strategy game +#: src/fdospecgen.h:1066 +msgid "StrategyGame" +msgstr "Strategiespiel" -#: src/wmapp.cc:674 src/wmwinlist.cc:459 -msgid "La_yer" -msgstr "_Ebene" +#: src/icehelp.cc:1380 +msgid "Support" +msgstr "Unterstützung" -#: src/wmapp.cc:677 src/wmwinlist.cc:460 -msgid "Tile" -msgstr "Anordnen" +#: src/yximage.cc:181 +msgid "Support for JPEG images was not enabled" +msgstr "Unterstützung für JPEG-Bilder wurde nicht aktiviert" -#: src/wmapp.cc:681 src/wmwinlist.cc:462 -msgid "Move _To" -msgstr "Verschieben _nach" +#: src/yximage.cc:173 +msgid "Support for PNG images was not enabled" +msgstr "Unterstützung für PNG-Bilder wurde nicht aktiviert" -#: src/wmapp.cc:682 src/wmwinlist.cc:463 -msgid "Occupy _All" -msgstr "_Alles Belegen" +#: src/icesound.cc:888 +#, c-format +msgid "Support for the %s interface not compiled." +msgstr "Die Unterstützung für das %s-Interface wurde nicht kompiliert." -#: src/wmapp.cc:688 -msgid "Limit _Workarea" -msgstr "_Beschränke Arbeitsfläche" +#: src/amailbox.cc:801 +msgid "Suspended" +msgstr "Angehalten" -#: src/wmapp.cc:692 src/wmwinlist.cc:464 -msgid "Tray _icon" -msgstr "Tray_Icon" +#: src/wmoption.cc:357 +#, c-format +msgid "Syntax error in window options on line %d of %s" +msgstr "Syntaxfehler in Fensteroptionen in Zeile %d von %s" -#: src/wmapp.cc:694 src/wmwinlist.cc:465 -msgid "R_ename title" -msgstr "Titel _umbenennen" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: System application, "System Tools" such as say a log viewer or network monitor +#: src/fdospecgen.h:68 src/fdospecgen.h:546 src/fdospecgen.h:570 +#: src/fdospecgen.h:588 src/fdospecgen.h:810 src/fdospecgen.h:1008 +#: src/fdospecgen.h:1086 src/fdospecgen.h:1206 +msgid "System" +msgstr "System" -#: src/wmapp.cc:699 src/wmwinlist.cc:480 src/wmwinlist.cc:488 -msgid "_Close" -msgstr "_Schließen" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A TV application +#: src/fdospecgen.h:160 +msgid "TV" +msgstr "TV" -#: src/wmapp.cc:701 src/wmwinlist.cc:482 -msgid "_Kill Client" -msgstr "Anwendung _töten" +#. TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout +#: src/wmapp.cc:628 src/wmtaskbar.cc:217 src/wmwinlist.cc:456 +#: src/wmwinlist.cc:489 +msgid "T_ile Horizontally" +msgstr "_Horizontal anordnen" -#: src/wmapp.cc:704 src/wmdialog.cc:92 src/wmwinmenu.cc:141 -msgid "_Window list" -msgstr "_Fensterliste" +#: src/decorate.cc:132 +msgid "Tabs" +msgstr "Registerkarte" -# -#: src/wmapp.cc:743 -msgid "Another window manager already running, exiting..." -msgstr "Ein anderer Fenstermanager ist bereits aktiv, beenden..." +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Telephony via PC +#: src/fdospecgen.h:1072 +msgid "Telephony" +msgstr "Telefonie" -#: src/wmapp.cc:818 -#, c-format -msgid "" -"Could not restart: %s\n" -"Does $PATH lead to %s?" -msgstr "" -"Neustart fehlgeschlagen: %s\n" -"Verweist die Variable $PATH auf das Programm %s?" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Telephony tools, to dial a number, manage PBX, ... +#: src/fdospecgen.h:1078 +msgid "TelephonyTools" +msgstr "Telefonie-Tools" -#: src/wmapp.cc:1006 -msgid "Confirm Restart as Terminal" -msgstr "Neustart als Terminal bestätigen" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A terminal emulator application +#: src/fdospecgen.h:1084 +msgid "TerminalEmulator" +msgstr "Terminal-Emulator" -#: src/wmapp.cc:1007 -msgid "" -"Unmanage all applications and restart\n" -"as a terminal. Proceed?" -msgstr "" -"Verwaltung aller Anwendungen aufheben und\n" -"als Terminal neu starten. Fortfahren?" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A text editor +#: src/fdospecgen.h:1090 +msgid "TextEditor" +msgstr "Texteditor" -#: src/wmapp.cc:1294 src/yxapp.cc:1050 -msgid "" -msgstr "" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A text tool utility +#: src/fdospecgen.h:58 src/fdospecgen.h:1096 +msgid "TextTools" +msgstr "Text-Tools" -#: src/wmapp.cc:1626 -msgid "" -" --client-id=ID Client id to use when contacting session manager.\n" -msgstr "" -" --client-id=ID zu verwendende Client-ID, wenn der Sitzungs-Manager " -"kontaktiert wird.\n" +#: src/wmabout.cc:47 +msgid "Theme Author:" +msgstr "Autor des Themes:" -#: src/wmapp.cc:1632 -msgid "" -"\n" -" --debug Print generic debug messages.\n" -" --debug-z Print debug messages regarding window stacking.\n" -msgstr "" -"\n" -" --debug Gibt generische Debug-Nachrichten aus.\n" -" --debug-z Gibt Debug-Nachrichten mit dem Blick auf window " -"stacking aus.\n" +#: src/wmabout.cc:46 +msgid "Theme Description:" +msgstr "Theme-Beschreibung:" -#: src/wmapp.cc:1640 -msgid "" -"\n" -" -a, --alpha Use a 32-bit visual for translucency.\n" -" -c, --config=FILE Load preferences from FILE.\n" -" -t, --theme=FILE Load theme from FILE.\n" -" -s, --splash=IMAGE Briefly show IMAGE on startup.\n" -" -p, --postpreferences Print preferences after all processing.\n" -" --rewrite-preferences Update an existing preferences file.\n" -" --trace=conf,icon Trace paths used to load configuration.\n" -msgstr "" -"\n" -" -a, --alpha Verwendet einen 32Bit-Sichtkontakt zur Lichtdurchlässigkeit.\n" -" -c, --config=DATEI Einstellungen aus DATEI laden.\n" -" -t, --theme=DATEI Theme aus DATEI laden.\n" -" -s, --spash=BILD Kurz BILD beim Start anzeigen.\n" -" -p, --postpreferences Einstellungen nach der ganzen Verarbeitung " -"ausgeben.\n" -" --rewrite-preferences Vorhandene Einstellungsdatei aktualisieren.\n" -" --trace=conf,icon Pfade zeichnen, die zum Laden der Konfiguration " -"verwendet werden.\n" +#: src/icehelp.cc:1382 +msgid "Theme Howto" +msgstr "Theme HowTo" -#: src/wmapp.cc:1651 -msgid " -o, --output=FILE Redirect all output to FILE.\n" -msgstr " -o, --output=DATEI Gesamte Ausgabe an DATEI umleiten.\n" +#: src/wmabout.cc:45 +msgid "Theme:" +msgstr "Theme:" -#: src/wmapp.cc:1657 -msgid " -i, --install=THEME Install THEME from extra or 'list'.\n" +#: src/wmapp.cc:674 src/wmwinlist.cc:448 +msgid "Tile" +msgstr "Anordnen" + +#. TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout +#: src/wmapp.cc:630 src/wmtaskbar.cc:215 src/wmwinlist.cc:455 +#: src/wmwinlist.cc:488 +msgid "Tile _Vertically" +msgstr "Ve_rtikal anordnen" + +#: src/icesound.cc:884 +#, c-format +msgid "Too quick; ignoring %s." +msgstr "Zu schnell; %s wird ignoriert." + +#: src/wmapp.cc:619 +msgid "Top Half" +msgstr "Obere Hälfte" + +#: src/wmapp.cc:622 +msgid "Top Left" +msgstr "Oben links" + +#: src/wmapp.cc:623 +msgid "Top Right" +msgstr "Oben rechts" + +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A translation tool +#: src/fdospecgen.h:1102 +msgid "Translation" +msgstr "Übersetzung" + +#: src/wmapp.cc:689 src/wmwinlist.cc:452 +msgid "Tray _icon" +msgstr "Tray_Icon" + +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tuner +#: src/fdospecgen.h:168 +msgid "Tuner" +msgstr "Empfänger" + +#: src/upath.cc:172 +#, c-format +msgid "Unable to create directory %s" +msgstr "Kann Verzeichnis %s nicht erstellen" + +#: src/wmconfig.cc:175 src/wmsave.cc:306 +#, c-format +msgid "Unable to rename %s to %s" +msgstr "Kann %s nicht in %s umbenennen" + +#: src/icesh.cc:3927 src/icesh.cc:3935 src/wmconfig.cc:139 src/wmsave.cc:65 +#: src/wmsave.cc:298 src/wmsave.cc:301 +#, c-format +msgid "Unable to write to %s" +msgstr "Kann nicht in %s schreiben" + +#: src/icesame.cc:57 +msgid "Undo" +msgstr "Rückgängig" + +#: src/wmmenu.cc:226 +#, c-format +msgid "Unexepected menu keyword: '%s'" +msgstr "Unerwartetes Menüschlüsselwort '%s'" + +#: src/icesh.cc:4302 +#, c-format +msgid "Unexpected: `%s'." +msgstr "Unerwartet: '%s'." + +#: src/icesh.cc:5628 +#, c-format +msgid "Unknown action: `%s'" +msgstr "Unbekannte Aktion: `%s`" + +#: src/movesize.cc:865 +#, c-format +msgid "Unknown direction in move/resize request: %d" +msgstr "Unbekannte Richtung in Verschieben/Vergrößern-Anfrage: %d" + +#: src/aapm.cc:169 +#, c-format +msgid "Unknown format used by APM device %s (%d)." +msgstr "Unbekanntes Format von APM-Gerät %s (%d) verwendet." + +#: src/yconfig.cc:83 +#, c-format +msgid "Unknown key name %s in %s" +msgstr "Unbekanntes Tastensymbol %s in %s" + +#: src/wmmenu.cc:412 +#, c-format +msgid "Unknown keyword '%s'" +msgstr "Unbekanntes Schlüsselwort '%s'" + +#: src/wmmenu.cc:423 +#, c-format +msgid "" +"Unknown keyword for a non-container: '%s'.\n" +"Expected either 'key' or 'runonce' here.\n" +msgstr "" +"Unbekanntes Schlüsselwort für einen Nicht-Container: '%s'.\n" +"Hier wurde entweder 'key' oder 'runonce' erwartet.\n" + +#: src/icesm.cc:188 +#, c-format +msgid "Unknown option '%s'" +msgstr "Unbekannte Option: '%s'" + +#: src/wmconfig.cc:113 +#, c-format +msgid "Unknown value '%s' for option '%s'." +msgstr "Unbekannter Wert '%s' für Option '%s'." + +#: src/wmoption.cc:285 +#, c-format +msgid "Unknown window option: %s" +msgstr "Unbekannte Fensteroption: %s" + +#: src/wmapp.cc:1004 +msgid "" +"Unmanage all applications and restart\n" +"as a terminal. Proceed?" +msgstr "" +"Verwaltung aller Anwendungen aufheben und\n" +"als Terminal neu starten. Fortfahren?" + +#: src/icesound.cc:683 src/icesound.cc:978 +#, c-format +msgid "Unrecognized argument: %s\n" +msgstr "Nicht erkanntes Argument: %s\n" + +#: src/icewmbg.cc:1248 src/wmapp.cc:1899 +#, c-format +msgid "Unrecognized option '%s'." +msgstr "Unbekannte Option: '%s'." + +#: src/icesound.cc:680 +#, c-format +msgid "Unrecognized option: %s\n" +msgstr "Nicht erkannte Option: %s\n" + +#: src/icehelp.cc:2465 +msgid "Unsafe characters in URL" +msgstr "Unsichere Zeichen in der URL" + +#: src/yximage.cc:187 +#, c-format +msgid "Unsupported file format: %s" +msgstr "Nicht unterstütztes Dateiformat: %s" + +#: src/icesound.cc:921 +#, c-format +msgid "Unsupported interface: %s." +msgstr "Nicht unterstütztes Interface: %s." + +#: src/icehelp.cc:2204 +msgid "Unsupported protocol." +msgstr "Nicht unterstütztes Protokoll." + +#: src/misc.cc:394 +#, c-format +msgid "" +"Usage: %s [OPTIONS]\n" +"Options:\n" +"%s\n" +" -C, --copying Prints license information and exits.\n" +" -V, --version Prints version information and exits.\n" +" -h, --help Prints this usage screen and exits.\n" +"\n" msgstr "" +"Verwendung: %s [OPTIONEN]\n" +"Optionen:\n" +"%s\n" +" -C, --copying Gibt Lizenzinformationen aus und beendet.\n" +" -V, --version Gibt Versionsinformationen aus und beendet.\n" +" -h, --help Gibt die Verwendung/ Hilfe aus und beendet.\n" +"\n" -#: src/wmapp.cc:1660 +#: src/wmapp.cc:1657 #, c-format msgid "" "Usage: %s [OPTIONS]\n" @@ -2356,909 +2313,714 @@ msgstr "" "%s\n" "\n" -#: src/wmapp.cc:1726 -#, c-format -msgid "%s configuration directories:\n" -msgstr "%s Konfigurationsverzeichnisse:\n" - -#: src/wmapp.cc:1811 +#: src/icehelp.cc:2502 #, c-format -msgid "%s configured options:%s\n" -msgstr "%s konfigurierte Optionen: %s\n" - -#: src/wmapp.cc:1952 -msgid "Confirm Logout" -msgstr "Abmelden bestätigen" - -#: src/wmapp.cc:1953 msgid "" -"Logout will close all active applications.\n" -"Proceed?" +"Usage: %s [OPTIONS] [ FILENAME | URL ]\n" +"\n" +"IceHelp is a very simple HTML browser for the IceWM window manager.\n" +"It can display a HTML document from file, or browse a website.\n" +"It remembers visited pages in a history, which is navigable\n" +"by key bindings and a context menu (right mouse click).\n" +"It neither supports rendering of images nor JavaScript.\n" +"If no file or URL is given it will display the IceWM Manual\n" +"from %s.\n" +"\n" +"Options:\n" +" -d, --display=NAME NAME of the X server to use.\n" +" --sync Synchronize X11 commands.\n" +"\n" +" -B Display the IceWM icewmbg manpage.\n" +" -b, --bugs Display the IceWM bug reports (primitively).\n" +" -f, --faq Display the IceWM FAQ and Howto.\n" +" -g Display the IceWM Github website.\n" +" -i, --icewm Display the IceWM icewm manpage.\n" +" -m, --manual Display the IceWM Manual (default).\n" +" -s Display the IceWM icesound manpage.\n" +" -t, --theme Display the IceWM themes Howto.\n" +" -w, --website Display the IceWM website.\n" +"\n" +" -V, --version Prints version information and exits.\n" +" -h, --help Prints this usage screen and exits.\n" +"\n" +"Environment variables:\n" +" DISPLAY=NAME Name of the X server to use.\n" +"\n" +"To report bugs, support requests, comments please visit:\n" +"%s\n" +"\n" msgstr "" -"Beim Abmelden werden alle aktiven Anwendungen geschlossen.\n" -"Fortfahren?" - -# -#: src/wmbutton.cc:124 -msgid "Raise/Lower" -msgstr "Anheben/Senken" - -#: src/wmbutton.cc:127 -msgid "Hide" -msgstr "Verstecken" - -#: src/wmbutton.cc:131 -msgid "Restore" -msgstr "Wiederherstellen" - -#: src/wmbutton.cc:133 -msgid "Maximize" -msgstr "Maximieren" - -#: src/wmbutton.cc:137 -msgid "Minimize" -msgstr "Minimieren" - -#: src/wmbutton.cc:141 -msgid "Rolldown" -msgstr "Herunterrollen" - -#: src/wmbutton.cc:143 -msgid "Rollup" -msgstr "Einrollen" - -#: src/wmclient.cc:470 -#, c-format -msgid "" -"Client %s with PID %ld fails to respond.\n" -"Do you wish to terminate this client?\n" -msgstr "" -"Client %s mitPID %ld antwortet nicht.\n" -"Möchten Sie diesen Client beenden?\n" - -#: src/wmconfig.cc:35 src/wmconfig.cc:40 src/wmconfig.cc:46 -#, c-format -msgid "Failed to load theme %s" -msgstr "Konnte Theme %s nicht laden" - -#: src/wmconfig.cc:113 -#, c-format -msgid "Unknown value '%s' for option '%s'." -msgstr "Unbekannter Wert '%s' für Option '%s'." +"Syntax: %s [OPTIONEN] [ DATEINAME | URL ]\n" +"\n" +"IceHelp ist ein sehr einfacher HTML-Browser für den IceWM-Fenstermanager.\n" +"Er kann zum Anzeigen eines HTML-Dokuments aus einer Datei oder Browsen " +"einer \n" +"Website verwendet werden. Die besuchten Seiten werden im Verlauf " +"gespeichert,\n" +"durch den Sie mit Tastenkombinationen und einem Kontextmenü (Klicken mit " +"der \n" +"rechten Maustaste) navigieren können. Der Browser unterstützt weder die " +"Darstellung \n" +"von Bildern noch JavaScript. Wenn keine Datei oder URL angegeben wird, wird " +"das \n" +"IceWM-Handbuch unter %s angezeigt.\n" +"\n" +"Optionen:\n" +" -d, --display=NAME NAME des zu verwendenden X-Servers.\n" +" --sync X11-Befehle synchronisieren.\n" +"\n" +" -B IceWM icewmbg-Hilfeseite anzeigen.\n" +" -b, --bugs IceWM-Fehlerberichte anzeigen (einfach).\n" +" -f, --faq IceWM FAQ und Howto anzeigen.\n" +" -g IceWM Github-Webseite anzeigen.\n" +" -i, --icewm IceWM icewm-Hilfeseite anzeigen.\n" +" -m, --manual IceWM-Handbuch anzeigen (Standard).\n" +" -s IceWM icesound-Hilfeseite anzeigen.\n" +" -t, --theme Howto für IceWM-Themen anzeigen.\n" +" -w, --website IceWM-Webseite anzeigen.\n" +"\n" +" -V, --version Versionsinformationen ausgeben und beenden.\n" +" -h, --help Hilfebildschirm ausgeben und beenden.\n" +"\n" +"Umgebungsvariablen:\n" +" DISPLAY=NAME Name des zu verwendenden X-Servers.\n" +"\n" +"Für Fehlerberichte, Support-Anfragen, Kommentare besuchen Sie bitte:\n" +"%s\n" +"\n" -#: src/wmconfig.cc:175 src/wmsave.cc:306 +#: src/icesound.cc:694 #, c-format -msgid "Unable to rename %s to %s" -msgstr "Kann %s nicht in %s umbenennen" - -#: src/wmdialog.cc:85 -msgid "Loc_k Workstation" -msgstr "Arbeitsplatz _sperren" - -#: src/wmdialog.cc:87 src/ymsgbox.cc:51 -msgid "_Cancel" -msgstr "Ab_brechen" - -#. TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout -#: src/wmdialog.cc:88 src/wmprog.cc:466 src/wmprog.cc:468 src/wmtaskbar.cc:243 -#: src/wmtaskbar.cc:245 -msgid "_Logout..." -msgstr "_Abmelden..." - -#: src/wmdialog.cc:93 -msgid "_Restart icewm" -msgstr "_IceWM neu starten" - -#. TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout -#: src/wmdialog.cc:94 src/wmprog.cc:434 src/wmtaskbar.cc:238 -msgid "_About" -msgstr "_Über" - -#: src/wmdialog.cc:95 -msgid "Reload win_options" -msgstr "Win-_Optionen neu laden" - -#: src/wmdialog.cc:96 -msgid "Reload ke_ys" -msgstr "S_chlüssel neu laden" - -#: src/wmframe.cc:1457 -msgid "Rename" -msgstr "Umbenennen" - -#: src/wmframe.cc:1458 -msgid "Rename the window title" -msgstr "Fenstertitel umbenennen" - -#: src/wmframe.cc:1952 msgid "" -"WARNING! All unsaved changes will be lost when\n" -"this client is killed. Do you wish to proceed?" +"Usage: %s [OPTION]...\n" +"\n" +"Plays audio files on GUI events raised by IceWM.\n" +"The currently configured sound interfaces are: %s.\n" +"Icesound will choose the first of these which is usable.\n" +"\n" +"Options:\n" +"\n" +" -d, --display=DISPLAY X11 display used by IceWM (default: $DISPLAY).\n" +"\n" +" -s, --sample-dir=DIR Specifies a directory with sound files.\n" +" Default is $HOME/.config/icewm/sounds.\n" +"\n" +" -i, --interface=LIST Specifies audio output interfaces. One or more of:\n" +" %s separated by commas.\n" +"\n" +" -D, --device=DEVICE Backwards compatibility only: the default device. \n" +" Please prefer one of the -A/-O/-S options.\n" +"\n" +" -O, --oss=DEVICE Specifies the OSS device (default: \"%s\").\n" +"\n" +" -A, --alsa=DEVICE Specifies the ALSA device (default: \"%s\").\n" +"\n" +" -z, --snooze=millisecs Specifies the snooze interval between sound events\n" +" in milliseconds. Default is 500 milliseconds.\n" +"\n" +" -p, --play=sound Plays the given sound (name or number) and exits.\n" +"\n" +" -l, --list-files Lists the available sound file paths and exits.\n" +"\n" +" --list-sounds Lists the supported sound filenames and exits.\n" +"\n" +" --list-interfaces Lists the supported audio interfaces and exits.\n" +"\n" +" -v, --verbose Be verbose and print out each sound event.\n" +"\n" +" -V, --version Prints version information and exits.\n" +"\n" +" -h, --help Prints this help screen and exits.\n" +"\n" +"Return values:\n" +"\n" +" 0 Success.\n" +" 1 General error.\n" +" 2 Command line error.\n" +" 3 Subsystems error (ie cannot connect to server).\n" +"\n" msgstr "" -"WARNUNG! Alle nicht gesicherten Änderungen werden beim\n" -"Töten der Anwendung verloren gehen! Wünschen Sie trotzdem fortzufahren?" - -# -#: src/wmframe.cc:1957 -msgid "Kill Client: " -msgstr "Client töten: " - -#: src/wmmenu.cc:37 -msgid "Missing command argument" -msgstr "Fehlendes Argument für Kommandozeilenparameter" - -#: src/wmmenu.cc:55 -#, c-format -msgid "Bad argument %d to command '%s'" -msgstr "Schlechtes Argument %d zum Befehl '%s'" - -#: src/wmmenu.cc:110 -#, c-format -msgid "Error at keyword '%s' for %s" -msgstr "Fehler bei Schlüsselwort '%s' für %s" - -#: src/wmmenu.cc:156 -#, c-format -msgid "Error at %s '%s'" -msgstr "Fehler bei %s '%s'" - -#: src/wmmenu.cc:222 -#, c-format -msgid "Unexepected menu keyword: '%s'" -msgstr "Unerwartetes Menüschlüsselwort '%s'" - -#: src/wmmenu.cc:276 -#, c-format -msgid "Error at menuprog '%s'" -msgstr "Fehler bei menuprog '%s'" - -#: src/wmmenu.cc:320 -#, c-format -msgid "Error at menuprogreload: '%s'" -msgstr "Fehler bei menuprogreload: '%s'" - -#: src/wmmenu.cc:347 -msgid "Missing filename argument to include statement" -msgstr "Fehlendes Dateinamen-Argument um einen Bericht hinzuzufügen" - -#: src/wmmenu.cc:365 -#, c-format -msgid "Error at includeprog '%s'" -msgstr "Fehler bei includeprog '%s'" - -#: src/wmmenu.cc:408 -#, c-format -msgid "Unknown keyword '%s'" -msgstr "Unbekanntes Schlüsselwort '%s'" +"Syntax: %s [OPTION]...\n" +"\n" +"Spielt zu den von IceWM erzeugten GUI-Ereignissen passende Audiodateien.\n" +"Die momentan konfigurierten Sound-Schnittstellen sind: %s.\n" +"Icesound wird das Erste von den Brauchbaren verwenden.\n" +"\n" +"Optionen:\n" +"\n" +" -d, --display=DISPLAY X11 Display von IceWM verwendet (Standard: " +"$DISPLAY).\n" +"\n" +" -s, --sample-dir=VERZEICHNIS Ein Verzeichnis, das die zu spielenden " +"Audiodateien enthält.\n" +" Standard ist $HOME/.config/icewm/sounds.\n" +"\n" +" -i, --interface=LISTE Spezifiziert Audio-Output-Interfaces. Eins " +"oder mehr von:\n" +" %s separiert durch Kommas.\n" +"\n" +" -D, --device=GERÄT Nur Rückwärts-Kompatibilität: das Standard-" +"Gerät. \n" +" Bitte eine der Optionen -A/-O/-S bevorzugen.\n" +"\n" +" -O, --oss=GERÄT Spezifiziert das OSS-Gerät (Standard: \"%s\").\n" +"\n" +" -A, --alsa=GERÄT Spezifiziert das ALSA-Gerät (Standard: \"%s\").\n" +" \n" +" -z, --snooze=Millisek Spezifiziert das Snooze-Intervall zwischen " +"Soundereignissen\n" +" in Millisekunden. Standard ist 500 Millisekunden.\n" +"\n" +" -p, --play=Sound Spielt den gegebenen Sound (Name oder Nummer) und " +"beendet.\n" +"\n" +" -l, --list-files Listet alle verfügbaren Sound-Dateipfade und " +"beendet.\n" +"\n" +" --list-sounds Listet die unterstützten Sound-Dateinamen und " +"beendet.\n" +"\n" +" --list-interfaces Listet die unterstützten Audio-Interfaces und " +"beendet.\n" +"\n" +"-v, --verbose Extra ausführlich und gibt jedes Soundereignis " +"aus.\n" +"\n" +"-V, --version Zeigt die Programmversion und beendet.\n" +"\n" +"-h, --help Zeigt diese Hilfe an und beendet.\n" +"\n" +"Rückgabewerte:\n" +"\n" +"0 Erfolg.\n" +"1 Allgemeiner Fehler.\n" +"2 Ungültige Befehlszeile.\n" +"3 Fehler im Subsystem (d.h. Verbindungsaufbau zum Server gescheitert).\n" +"\n" -#: src/wmmenu.cc:419 -#, c-format +#: src/icewmbg.cc:969 msgid "" -"Unknown keyword for a non-container: '%s'.\n" -"Expected either 'key' or 'runonce' here.\n" -msgstr "" -"Unbekanntes Schlüsselwort für einen Nicht-Container: '%s'.\n" -"Hier wurde entweder 'key' oder 'runonce' erwartet.\n" - -#: src/wmmenu.cc:498 -#, c-format -msgid "'%s' timed out!" -msgstr "Zeitüberschreitung bei '%s'!" - -#: src/wmmenu.cc:512 -#, c-format -msgid "'%s' produces no output" -msgstr "'%s' produziert keine Ausgabe" - -#: src/wmmgr.cc:3673 -msgid "Missing program setxkbmap" -msgstr "Fehlendes Program: 'setxkbmap'" - -#: src/wmmgr.cc:3674 -msgid "For keyboard switching, please install setxkbmap." -msgstr "Um die Tastatur zu ändern, installieren Sie bitte setxkbmap." - -#: src/wmoption.cc:285 -#, c-format -msgid "Unknown window option: %s" -msgstr "Unbekannte Fensteroption: %s" - -#: src/wmoption.cc:357 -#, c-format -msgid "Syntax error in window options on line %d of %s" -msgstr "Syntaxfehler in Fensteroptionen in Zeile %d von %s" - -#: src/wmpref.cc:101 -msgid "Save Modifications" -msgstr "Änderungen speichern" - -#: src/wmpref.cc:179 -#, c-format -msgid "Enter a new value for %s: " -msgstr "Geben Sie einen neuen Wert für %s ein: " - -#: src/wmprog.cc:341 -msgid "_Click to focus" -msgstr "Fokus durch _Klicken" - -#: src/wmprog.cc:342 -msgid "_Explicit focus" -msgstr "_Expliziter Fokus" - -#: src/wmprog.cc:343 -msgid "_Sloppy mouse focus" -msgstr "_Salopper Maus-Fokus" - -#: src/wmprog.cc:344 -msgid "S_trict mouse focus" -msgstr "Strenger _Maus-Fokus" - -#: src/wmprog.cc:345 -msgid "_Quiet sloppy focus" -msgstr "Salopper Fokus (_träge)" - -#: src/wmprog.cc:346 -msgid "Custo_m" -msgstr "_Benutzerdefiniert" - -#: src/wmprog.cc:368 -msgid "_Manual" -msgstr "_Handbuch" - -#: src/wmprog.cc:369 -msgid "_Icewm(1)" -msgstr "_Icewm(1)" - -#: src/wmprog.cc:370 -msgid "Icewm_Bg(1)" -msgstr "Icewm_Bg(1)" - -#: src/wmprog.cc:371 -msgid "Ice_Sound(1)" -msgstr "Ice_Sound(1)" - -#: src/wmprog.cc:420 -msgid "Programs" -msgstr "Programme" - -#: src/wmprog.cc:424 -msgid "_Run..." -msgstr "Aus_führen..." - -#. TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout -#: src/wmprog.cc:428 src/wmtaskbar.cc:233 -msgid "_Windows" -msgstr "F_enster" - -#: src/wmprog.cc:439 -msgid "_Help" -msgstr "_Hilfe" - -#: src/wmprog.cc:444 -msgid "_Focus" -msgstr "_Fokus" - -#: src/wmprog.cc:449 -msgid "_Preferences" -msgstr "_Wünsche" - -#: src/wmprog.cc:454 -msgid "_Themes" -msgstr "_Themes" - -#: src/wmprog.cc:458 -msgid "Se_ttings" -msgstr "_Einstellungen" - -#: src/wmsession.cc:214 src/wmsession.cc:230 src/wmsession.cc:240 -#, c-format -msgid "Session Manager: Unknown line %s" -msgstr "Sitzungsmanager: Unbekannte Zeile %s" - -#. TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout -#: src/wmtaskbar.cc:219 src/wmwinlist.cc:469 src/wmwinlist.cc:502 -msgid "Ca_scade" -msgstr "_Überlappend anordnen" - -#. TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout -#: src/wmtaskbar.cc:221 src/wmwinlist.cc:470 src/wmwinlist.cc:503 -msgid "_Arrange" -msgstr "_Ordnen" - -#. TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout -#: src/wmtaskbar.cc:223 src/wmwinlist.cc:472 src/wmwinlist.cc:504 -msgid "_Minimize All" -msgstr "Alle _Minimieren" - -#. TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout -#: src/wmtaskbar.cc:225 src/wmwinlist.cc:473 src/wmwinlist.cc:505 -msgid "_Hide All" -msgstr "Alle _Verstecken" - -#. TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout -#: src/wmtaskbar.cc:227 src/wmwinlist.cc:474 src/wmwinlist.cc:506 -msgid "_Undo" -msgstr "_Rückgängig" - -#. TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout -#: src/wmtaskbar.cc:230 -msgid "Arrange _Icons" -msgstr "_Symbole anordnen" - -#. TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout -#: src/wmtaskbar.cc:236 -msgid "_Refresh" -msgstr "_Aktualisieren" - -#: src/wmtaskbar.cc:313 src/wmtaskbar.cc:1025 -msgid "Hide Taskbar" -msgstr "Taskleiste verbergen" - -#: src/wmtaskbar.cc:336 -msgid "Favorite Applications" -msgstr "Lieblings-Anwendungen" - -#: src/wmtaskbar.cc:362 -msgid "Window List Menu" -msgstr "Fensterlisten-Menü" - -#: src/wmtaskbar.cc:372 -msgid "Show Desktop" -msgstr "Desktop anzeigen" - -#: src/wmtaskbar.cc:1025 -msgid "Show Taskbar" -msgstr "Taskleiste anzeigen" - -#: src/wmwinlist.cc:83 -msgid "All Workspaces" -msgstr "Alle Arbeitsbereiche" - -#: src/wmwinlist.cc:454 -msgid "_Show" -msgstr "_Anzeigen" - -#: src/wmwinlist.cc:457 -msgid "_Raise" -msgstr "An_heben" - -#: src/wmwinlist.cc:480 -msgid "Del" -msgstr "Entf" - -#: src/wmwinlist.cc:484 -msgid "_Terminate Process" -msgstr "Prozess be_enden" - -#: src/wmwinlist.cc:485 -msgid "Kill _Process" -msgstr "Prozess _töten" +"Usage: icewmbg [OPTIONS]\n" +"Where multiple values can be given they are separated by commas.\n" +"When image is a directory then all images from that directory are used.\n" +"\n" +"Options:\n" +" -p, --replace Replace an existing icewmbg.\n" +" -q, --quit Tell the running icewmbg to quit.\n" +" -r, --restart Tell the running icewmbg to restart itself.\n" +" -u, --shuffle Shuffle/reshuffle the list of background images.\n" +"\n" +" -c, --config=FILE Load preferences from FILE.\n" +" -t, --theme=NAME Load the theme with name NAME.\n" +"\n" +" -i, --image=FILE(S) Load background image(s) from FILE(S).\n" +" -k, --color=NAME(S) Use background color(s) from NAME(S).\n" +"\n" +" -s, --semis=FILE(S) Load transparency image(s) from FILE(S).\n" +" -x, --trans=NAME(S) Use transparency color(s) from NAME(S).\n" +"\n" +" -e, --center=0/1 Disable/Enable centering background.\n" +" -a, --scaled=0/1 Disable/Enable scaling background.\n" +" -m, --multi=0/1 Disable/Enable multihead background.\n" +" -y, --cycle=SECONDS Cycle backgrounds every SECONDS.\n" +"\n" +" --display=NAME Use NAME to connect to the X server.\n" +" --sync Synchronize communication with X11 server.\n" +"\n" +" -h, --help Print this usage screen and exit.\n" +" -V, --version Prints version information and exits.\n" +"\n" +"Loads desktop background according to preferences file:\n" +" DesktopBackgroundCenter - Display desktop background centered\n" +" DesktopBackgroundScaled - Display desktop background scaled\n" +" DesktopBackgroundColor - Desktop background color(s)\n" +" DesktopBackgroundImage - Desktop background image(s)\n" +" ShuffleBackgroundImages - Shuffle the list of background images\n" +" SupportSemitransparency - Support for semitransparent terminals\n" +" DesktopTransparencyColor - Semitransparency background color(s)\n" +" DesktopTransparencyImage - Semitransparency background image(s)\n" +" DesktopBackgroundMultihead - One background over all monitors\n" +" CycleBackgroundsPeriod - Seconds between cycling over backgrounds\n" +"\n" +" center:0 scaled:0 = tiled\n" +" center:1 scaled:0 = centered\n" +" center:1 scaled:1 = fill one dimension and keep aspect ratio\n" +" center:0 scaled:1 = fill both dimensions and keep aspect ratio\n" +"\n" +msgstr "" +"Aufruf: icewmbg [OPTIONEN]\n" +"Wo unterschiedliche Werte gegeben werden können, werden diese mit Kommas " +"getrennt.\n" +"Wenn ein Bild ein Verzeichnis ist, dann werden alle Bilder aus diesem " +"Verzeichnis verwendet.\n" +"\n" +"Optionen:\n" +" -p, --replace Ein bestehendes icewmbg ersetzen.\n" +" -q, --quit Dem laufenden icewmbg sagen sich zu beenden.\n" +" -r, --restart Dem laufenden icewmbg sagen sich selbst neu zu " +"starten.\n" +" -u, --shuffle Die Liste an Hintergrundbildern mischen/ " +"umstrukturieren.\n" +"\n" +" -c, --config=DATEI Prioritäten aus DATEI laden.\n" +" -t, --theme=DATEI Theme aus DATEI laden.\n" +"\n" +" -i, --image=DATEI(EN) Hintergrundbild(er) aus DATEI(EN) laden.\n" +" -k, --color=NAME(N) Hintergrundfarb(en) aus NAME(N) verwenden.\n" +"\n" +" -s, --semis=DATEI(EN) Nachvollziehbare Bilde(r) aus DATEI(EN) laden.\n" +" -x, --trans=NAME(N) Nachvollziehbare Farbe(n) aus NAME(N) verwenden.\n" +"\n" +" -e, --center=0/1 Zentrierten Hintergrund deaktivieren/aktivieren.\n" +" -a, --scaled=0/1 Skalierten Hintergrund deaktivieren/aktivieren.\n" +" -m, --multi=0/1 Multihead-Hintergrund deaktivieren/aktivieren.\n" +" -y, --cycle=SEKUNDEN Hintergründe alle SEKUNDEN ablaufen.\n" +"\n" +" --display=NAME NAME zur Verbindung mit den X-Server verwenden.\n" +" --sync Synchronisierung der Kommunikation mit dem X11-" +"Server.\n" +"\n" +" -h, --help Ausgabe der Verwendung und beenden.\n" +" -V, --version Ausgabe der Versionsinformationen und beenden.\n" +"\n" +"Lädt den Desktop-Hintergrund gemäß der Datei »preferences«\n" +" DesktopBackgroundCenter - Zeigt den Hintergrund zentriert an\n" +" DesktopBackgroundScaled - Zeigt den Hintergrund vergrössert an\n" +" SupportSemitransparency - Unterstützt semi-trasparente Fenster\n" +" DesktopBackgroundColor - Hintergrundfarbe des Desktops\n" +" DesktopBackgroundImage - Hintergrundbild des Desktops\n" +" ShuffleBackgroundImages - Mischung der Liste an Hintergrundbildern\n" +" DesktopTransparencyColor - Farbe, die semi-transp. Fenstern gemeldet wird\n" +" DesktopTransparencyImage - Bild, das semi-transp. Fenstern gemeldet wird\n" +" DesktopBackgroundMultihead - Ein Hintergrund über alle Monitore\n" +" CycleBackgroundsPeriod - Sekunden zwischen Abläufen über Hintergründen\n" +"\n" +" center:0 scaled:0 = gekachelt\n" +" center:1 scaled:0 = zentriert\n" +" center:1 scaled:1 = eine Dimension füllen und Seitenverhältnis beibehalten\n" +" center:0 scaled:1 = beide Dimensionen füllen und Seitenverhältnis " +"beibehalten\n" +"\n" -#: src/wmwinlist.cc:520 src/wmwinlist.cc:521 -msgid "Window list" -msgstr "Fensterliste" +#: src/icewmhint.cc:20 +msgid "Usage: icewmhint class.instance option arg\n" +msgstr "Verwendung: icewmhint Klasse.Instanz Option Argument\n" -#: src/wmwinmenu.cc:100 -#, c-format -msgid "%lu. Workspace %-.32s" -msgstr "%lu. Arbeitsbereich %-.32s" +#: src/amemstatus.cc:180 +msgid "User: " +msgstr "Benutzer: " -#: src/wpixres.cc:93 src/wpixres.cc:100 +#: src/icesound.cc:930 #, c-format -msgid "Image not readable: %s" -msgstr "Bild nicht lesbar: %s" +msgid "Using %s audio." +msgstr "%s Audio wird verwendet." -#: src/yapp.cc:296 +#: src/amailbox.cc:694 #, c-format -msgid "%s: select failed" -msgstr "%s: Auswahl fehlgeschlagen" +msgid "Using MailBox \"%s\"\n" +msgstr "Benutze Postfach: \"%s\"\n" -#: src/ycolor.cc:229 src/ycolor.cc:240 -#, c-format -msgid "Could not parse color \"%s\"" -msgstr "Farbe \"%s\" konnte nicht geparst werden" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Small utility application, "Accessories" +#: src/fdospecgen.h:44 src/fdospecgen.h:216 src/fdospecgen.h:252 +#: src/fdospecgen.h:348 src/fdospecgen.h:390 src/fdospecgen.h:576 +#: src/fdospecgen.h:780 src/fdospecgen.h:1038 src/fdospecgen.h:1080 +#: src/fdospecgen.h:1092 src/fdospecgen.h:1098 src/fdospecgen.h:1210 +msgid "Utility" +msgstr "Utility" -#: src/yconfig.cc:84 -#, c-format -msgid "Unknown key name %s in %s" -msgstr "Unbekanntes Tastensymbol %s in %s" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for viewing, creating, or processing vector graphics +#: src/fdospecgen.h:176 +msgid "VectorGraphics" +msgstr "Vektor-Grafiken" -#: src/yconfig.cc:171 src/yconfig.cc:182 src/yconfig.cc:194 -#, c-format -msgid "Bad argument: %s for %s [%d,%d]" -msgstr "Schlechtes Argument: %s für %s [%d,%d]" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A video application +#: src/fdospecgen.h:162 src/fdospecgen.h:294 src/fdospecgen.h:888 +#: src/fdospecgen.h:948 src/fdospecgen.h:1214 +msgid "Video" +msgstr "Video" -#: src/ycursor.cc:110 -#, c-format -msgid "Loading of pixmap \"%s\" failed: %s" -msgstr "Laden der Bilddatei \"%s\" fehlgeschlagen: %s" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Video Conference software +#: src/fdospecgen.h:1108 +msgid "VideoConference" +msgstr "Videokonferenz" -#: src/ycursor.cc:135 -#, c-format -msgid "Loading of pixmap \"%s\" failed" -msgstr "Laden der Bilddatei \"%s\" fehlgeschlagen" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Tool to view e.g. a graphic or pdf file +#: src/fdospecgen.h:1114 src/fdospecgen.h:1120 +msgid "Viewer" +msgstr "Betrachter" -#: src/ycursor.cc:179 -#, c-format -msgid "BUG? Imlib was able to read \"%s\"" -msgstr "BUG? Imlib war in der Lage \"%s\" zu lesen" +#: src/wmframe.cc:1966 +msgid "" +"WARNING! All unsaved changes will be lost when\n" +"this client is killed. Do you wish to proceed?" +msgstr "" +"WARNUNG! Alle nicht gesicherten Änderungen werden beim\n" +"Töten der Anwendung verloren gehen! Wünschen Sie trotzdem fortzufahren?" -#: src/ycursor.cc:204 -#, c-format -msgid "BUG? Malformed XPM header but Imlib was able to parse \"%s\"" -msgstr "BUG? Fehlerhafter XPM-Header, aberImlib konnte die Datei \"%s\" parsen" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: WINE +#: src/fdospecgen.h:1218 +msgid "WINE" +msgstr "WINE" -#: src/ycursor.cc:212 -#, c-format -msgid "BUG? Unexpected end of XPM file but Imlib was able to parse \"%s\"" -msgstr "" -"BUG? Unerwartetes Ende der XPM-Datei, aber Imlib konnte die Datei \"%s\" " -"parsen" +#: src/wmapp.cc:111 +msgid "Waiting to replace the old window manager" +msgstr "Warte auf den Austausch vom alten Fenstermanager" -#: src/ycursor.cc:215 -#, c-format -msgid "BUG? Unexpected character but Imlib was able to parse \"%s\"" -msgstr "BUG? Unerwartetes Zeichen, aber Imlib konnte die Datei \"%s\" parsen" +#: src/misc.cc:71 src/misc.cc:83 +msgid "Warning: " +msgstr "Warnung: " -#: src/yfontcore.cc:121 src/yfontxft.cc:117 -#, c-format -msgid "Could not load font \"%s\"." -msgstr "Die Schriftart \"%s\" konnte nicht geladen werden." +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A web browser +#: src/fdospecgen.h:1126 +msgid "WebBrowser" +msgstr "Webbrowser" -#: src/yfontcore.cc:233 -#, c-format -msgid "Missing codesets for fontset \"%s\":" -msgstr "Fehlende Zeichensätze im Schriftsatz \"%s\":" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tool for web developers +#: src/fdospecgen.h:1132 src/fdospecgen.h:1138 +msgid "WebDevelopment" +msgstr "Webentwicklung" -#: src/yfontcore.cc:261 -#, c-format -msgid "Could not load fontset \"%s\"." -msgstr "Schriftsatz \"%s\" konnte nicht geladen werden." +#: src/icehelp.cc:1384 +msgid "Website" +msgstr "Webseite" -#: src/yinputline.cc:18 -msgid "_Copy" -msgstr "_Kopieren" +#: src/wmtaskbar.cc:362 +msgid "Window List Menu" +msgstr "Fensterlisten-Menü" -#: src/yinputline.cc:18 -msgid "Ctrl+C" -msgstr "Strg+C" +#: src/wmwinlist.cc:508 src/wmwinlist.cc:509 +msgid "Window list" +msgstr "Fensterliste" -#: src/yinputline.cc:19 -msgid "Cu_t" -msgstr "Aus_schneiden" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A word processor +#: src/fdospecgen.h:1144 +msgid "WordProcessor" +msgstr "Textverarbeitung" -#: src/yinputline.cc:20 -msgid "_Paste" -msgstr "_Einfügen" +#: src/icesh.cc:1757 +#, c-format +msgid "Workspace out of range: %ld" +msgstr "Arbeitsbereich außerhalb des Wertebereichs: %ld" -#: src/yinputline.cc:21 -msgid "Paste _Selection" -msgstr "Aus_wahl einfügen" +#: src/aworkspaces.cc:685 src/wmstatus.cc:204 +msgid "Workspace: " +msgstr "Arbeitsbereich: " -#: src/yinputline.cc:21 -msgid "Ctrl+P" -msgstr "Strg+P" +#: src/iceview.cc:61 +msgid "Wrap Lines" +msgstr "Lange Zeilen umbrechen" -#: src/yinputline.cc:23 -msgid "Select _All" -msgstr "_Alles auswählen" +#: src/amailbox.cc:447 +#, c-format +msgid "Write to socket failed: %s" +msgstr "Schreiben in Socket fehlgeschlagen: %s" -#: src/yinputline.cc:23 -msgid "Ctrl+A" -msgstr "Strg+A" +#. TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on XFCE libraries +#: src/fdospecgen.h:184 +msgid "XFCE" +msgstr "XFCE" -#: src/ylocale.cc:58 -msgid "Locale not supported by C library or Xlib. Falling back to 'C' locale'." -msgstr "" -"Lokale wird von der C-Bibliothek nicht unterstützt. Es wird auf die lokale " -"Variable 'C' zurückgegriffen." +#. TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout +#: src/wmdialog.cc:94 src/wmprog.cc:436 src/wmtaskbar.cc:238 +msgid "_About" +msgstr "_Über" -#: src/ylocale.cc:92 -msgid "" -"Failed to determinate the current locale's codeset. Assuming ISO-8859-1.\n" -msgstr "" -"Die Kodierung der momentanen lokalen Variablen konnte nicht bestimmt werden. " -"Es wird ISO-8859-1 angenommen.\n" +#: src/wmapp.cc:558 +msgid "_Above Dock" +msgstr "_Über Dock" -#: src/ylocale.cc:125 src/ylocale.cc:133 -#, c-format -msgid "iconv doesn't supply (sufficient) %s to %s converters." -msgstr "" -"iconv verfügt nicht über einen (zufriedenstellenden) %s zu %s-Konvertierer." +#. TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout +#: src/wmtaskbar.cc:221 src/wmwinlist.cc:458 src/wmwinlist.cc:491 +msgid "_Arrange" +msgstr "_Ordnen" -#: src/ylocale.cc:238 -#, c-format -msgid "Invalid multibyte string \"%s\": %s" -msgstr "Ungültige Multibyte-Zeichenkette \"%s\": %s" +#: src/wmapp.cc:562 +msgid "_Below" +msgstr "_Darunter" -#: src/ymsgbox.cc:48 -msgid "_OK" -msgstr "_OK" +#: src/wmdialog.cc:87 src/ymsgbox.cc:51 +msgid "_Cancel" +msgstr "Ab_brechen" -#: src/ysmapp.cc:95 -msgid "$USER or $LOGNAME not set?" -msgstr "Sind die Umgebungsvariablen $USER oder $LOGNAME nicht gesetzt?" +#: src/wmapp.cc:527 +msgid "_Cancel logout" +msgstr "Abmelde_vorgang abbrechen" -#: src/yurl.cc:145 -#, c-format -msgid "Failed to parse URL \"%s\"." -msgstr "Konnte die URL \"%s\" nicht analysieren." +#: src/amailbox.cc:963 +msgid "_Check" +msgstr "_Abholen" -#: src/yurl.cc:161 -#, c-format -msgid "Incomplete hex escape in URL at position %d." -msgstr "Unvollständiges hex escape in der URL an der Position %d." +#: src/wmprog.cc:343 +msgid "_Click to focus" +msgstr "Fokus durch _Klicken" -#: src/yurl.cc:168 -#, c-format -msgid "Invalid hex escape in URL at position %d." -msgstr "Ungültiges hex escape in der URL an der Position %d." +#: src/wmapp.cc:696 src/wmwinlist.cc:468 src/wmwinlist.cc:476 +msgid "_Close" +msgstr "_Schließen" -#: src/yxapp.cc:1008 -msgid "" -" -d, --display=NAME NAME of the X server to use.\n" -" --sync Synchronize X11 commands.\n" -msgstr "" -" -d, --display=NAME NAME des zu verwendenden X-Servers.\n" -" --sync Synchronisation von X11-Befehlen.\n" +#: src/acpustatus.cc:914 +msgid "_Combine" +msgstr "_Kombinieren" -#: src/yximage.cc:173 -msgid "Support for PNG images was not enabled" -msgstr "Unterstützung für PNG-Bilder wurde nicht aktiviert" +#: src/yinputline.cc:18 +msgid "_Copy" +msgstr "_Kopieren" -#: src/yximage.cc:181 -msgid "Support for JPEG images was not enabled" -msgstr "Unterstützung für JPEG-Bilder wurde nicht aktiviert" +#: src/aclock.cc:203 src/acpustatus.cc:912 src/amailbox.cc:964 +#: src/amemstatus.cc:264 +msgid "_Disable" +msgstr "_Deaktivieren" -#: src/yximage.cc:187 -#, c-format -msgid "Unsupported file format: %s" -msgstr "Nicht unterstütztes Dateiformat: %s" +#: src/wmapp.cc:559 +msgid "_Dock" +msgstr "_Dock" -#: src/yximage.cc:191 src/yximage.cc:214 -#, c-format -msgid "Could not load image \"%s\"" -msgstr "Bild \"%s\" konnte nicht geladen werden" +#: src/wmprog.cc:344 +msgid "_Explicit focus" +msgstr "_Expliziter Fokus" -#, fuzzy -#~| msgid "Close" -#~ msgid "Clos_e" -#~ msgstr "Schließen" +#: src/wmprog.cc:446 +msgid "_Focus" +msgstr "_Fokus" -#~ msgid "Loading of fallback font \"%s\" failed." -#~ msgstr "Rückgriff auf die Schriftart \"%s\" ist fehlgeschlagen." +#: src/wmapp.cc:655 src/wmwinlist.cc:441 +msgid "_Fullscreen" +msgstr "ganzer Bi_ldschirm" -#~ msgid "" -#~ "\n" -#~ " Caller id:\t" -#~ msgstr "" -#~ "\n" -#~ " Anschlußkennung:\t" +#: src/wmprog.cc:441 +msgid "_Help" +msgstr "_Hilfe" -#~ msgid "Kill IceWM, replace with Xterm" -#~ msgstr "IceWM töten, mit Xterm ersetzen" +#: src/wmapp.cc:541 src/wmdialog.cc:91 +msgid "_Hibernate" +msgstr "_Tiefschlaf" -#~ msgid "GNOME window state" -#~ msgstr "GNOME-Fensterzustand" +#: src/wmapp.cc:658 src/wmwinlist.cc:443 +msgid "_Hide" +msgstr "Vers_tecken" -#~ msgid "GNOME window hint" -#~ msgstr "GNOME-Fensterbeschreibung" +#. TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout +#: src/wmtaskbar.cc:225 src/wmwinlist.cc:461 src/wmwinlist.cc:493 +msgid "_Hide All" +msgstr "Alle _Verstecken" -#~ msgid "Invalid cursor pixmap: \"%s\" contains too much unique colors" -#~ msgstr "" -#~ "Ungültiges Cursor-Bilddatei: \"%s\" enthält zu viele einzigartige Farben" +#: src/wmprog.cc:371 +msgid "_Icewm(1)" +msgstr "_Icewm(1)" -#~ msgid "" -#~ "stat:\tuser = %llu, nice = %llu, sys = %llu, idle = %llu, iowait = %llu, " -#~ "intr = %llu, softirq = %llu, steal = %llu\n" -#~ msgstr "" -#~ "stat:\tBenutzer = %llu, nice = %llu, sys = %llu, idle = %llu, iowait = " -#~ "%llu, intr = %llu, softirq = %llu, entwendet = %llu\n" +#: src/wmapp.cc:698 src/wmwinlist.cc:470 +msgid "_Kill Client" +msgstr "Anwendung _töten" -#~ msgid "" -#~ "bars:\tuser = %llu, nice = %llu, sys = %llu, iowait = %llu, intr = %llu, " -#~ "softirq = %llu, steal = %llu (h = %i)\n" -#~ msgstr "" -#~ "Balken:\tBenutzer = %llu, nice = %llu, sys = %llu, iowait = %llu, intr = " -#~ "%llu, softirq = %llu, steal = %llu (h = %i)\n" +# OS/2 is dead, but... ;-) +#: src/wmapp.cc:526 +msgid "_Logout" +msgstr "_Abmelden" -#~ msgid "CPU: %llu %llu %llu %llu %llu %llu %llu %llu" -#~ msgstr "CPU: %llu %llu %llu %llu %llu %llu %llu %llu" +#. TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout +#: src/wmdialog.cc:88 src/wmprog.cc:468 src/wmprog.cc:470 src/wmtaskbar.cc:243 +#: src/wmtaskbar.cc:245 +msgid "_Logout..." +msgstr "_Abmelden..." -#~ msgid "" -#~ " IceWM crashed for the second time in 10 seconds. \n" -#~ " Do you wish to:\n" -#~ "\n" -#~ "\t1: Restart IceWM?\n" -#~ "\t2: Abort this session?\n" -#~ msgstr "" -#~ " IceWM stürzte das zweite Mal in 10 sekunden ab. \n" -#~ " Möchten Sie:\n" -#~ "\n" -#~ "1: IceWM neu starten?\n" -#~ "2: Diese Sitzung abbrechen?\n" +#: src/wmapp.cc:669 src/wmwinlist.cc:446 +msgid "_Lower" +msgstr "Sen_ken" -#~ msgid "Unable to get current font path." -#~ msgstr "Der aktuelle Fontpfad kann nicht bestimmt werden." +#: src/wmprog.cc:370 +msgid "_Manual" +msgstr "_Handbuch" -#~ msgid "Unexpected format of ICEWM_FONT_PATH property" -#~ msgstr "Unerwartetes Format der ICEWM_FONT_PATH-Property" +#: src/wmapp.cc:557 +msgid "_Menu" +msgstr "_Menü" -#~ msgid "Task Bar" -#~ msgstr "Taskleiste" +#. TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout +#: src/wmtaskbar.cc:223 src/wmwinlist.cc:460 src/wmwinlist.cc:492 +msgid "_Minimize All" +msgstr "Alle _Minimieren" -#~ msgid "_License" -#~ msgstr "_Lizenz" +#: src/wmapp.cc:644 +msgid "_Move" +msgstr "_Verschieben" -#~ msgid "0x%-8lx %-14s: %-20s %dx%d%+d%+d\n" -#~ msgstr "0x%-8lx %-14s: %-20s %dx%d%+d%+d\n" +#: src/wmapp.cc:561 +msgid "_Normal" +msgstr "_Normal" -#~ msgid "" -#~ "Usage: %s [OPTIONS] ACTIONS\n" -#~ "\n" -#~ "Options:\n" -#~ " -d, -display DISPLAY Connects to the X server specified by " -#~ "DISPLAY.\n" -#~ " Default: $DISPLAY or :0.0 when not set.\n" -#~ " -w, -window WINDOW_ID Specifies the window to manipulate. " -#~ "Special\n" -#~ " identifiers are `root' for the root window " -#~ "and\n" -#~ " `focus' for the currently focused window.\n" -#~ " -c, -class WM_CLASS Window management class of the window(s) " -#~ "to\n" -#~ " manipulate. If WM_CLASS contains a period, " -#~ "only\n" -#~ " windows with exactly the same WM_CLASS " -#~ "property\n" -#~ " are matched. If there is no period, windows " -#~ "of\n" -#~ " the same class and windows of the same " -#~ "instance\n" -#~ " (aka. `-name') are selected.\n" -#~ "\n" -#~ "Actions:\n" -#~ " setIconTitle TITLE Set the icon title.\n" -#~ " setWindowTitle TITLE Set the window title.\n" -#~ " setGeometry geometry Set the window geometry\n" -#~ " setState MASK STATE Set the GNOME window state to STATE.\n" -#~ " Only the bits selected by MASK are " -#~ "affected.\n" -#~ " STATE and MASK are expressions of the " -#~ "domain\n" -#~ " `GNOME window state'.\n" -#~ " toggleState STATE Toggle the GNOME window state bits " -#~ "specified by\n" -#~ " the STATE expression.\n" -#~ " setHints HINTS Set the GNOME window hints to HINTS.\n" -#~ " setLayer LAYER Moves the window to another GNOME window " -#~ "layer.\n" -#~ " setWorkspace WORKSPACE Moves the window to another workspace. " -#~ "Select\n" -#~ " the root window to change the current " -#~ "workspace.\n" -#~ " Select 0xFFFFFFFF or \"All\" for all " -#~ "workspaces.\n" -#~ " listWorkspaces Lists the names of all workspaces.\n" -#~ " setTrayOption TRAYOPTION Set the IceWM tray option hint.\n" -#~ " logout Tell IceWM to logout.\n" -#~ " reboot Tell IceWM to reboot.\n" -#~ " shutdown Tell IceWM to shutdown.\n" -#~ " cancel Tell IceWM to cancel the logout/reboot/" -#~ "shutdown.\n" -#~ " about Tell IceWM to show the about window.\n" -#~ " windowlist Tell IceWM to show the window list.\n" -#~ " restart Tell IceWM to restart.\n" -#~ " suspend Tell IceWM to suspend.\n" -#~ "\n" -#~ "Expressions:\n" -#~ " Expressions are list of symbols of one domain concatenated by `+' or " -#~ "`|':\n" -#~ "\n" -#~ " EXPRESSION ::= SYMBOL | EXPRESSION ( `+' | `|' ) SYMBOL\n" -#~ "\n" -#~ msgstr "" -#~ "Syntax: %s [OPTIONEN] AKTIONEN\n" -#~ "\n" -#~ "Optionen:\n" -#~ " -d, -display DISPLAY Mit dem durch DISPLAY beschriebenen X-" -#~ "Server\n" -#~ " verbinden. Vorgabe: $DISPLAY oder :0.0, " -#~ "falls nicht gesetzt.\n" -#~ " -w, -window FENSTER_ID Das zu beeinflussende Fenster. " -#~ "Besondere\n" -#~ " Bezeichner sind »root« für den Desktop und\n" -#~ " »focus« für das momentan aktive Fenster.\n" -#~ " -c, -class WM_CLASS Fenstermanagement-Klasse der/des zu\n" -#~ " manipulierenden Fenster/s. Wenn WM_CLASS " -#~ "einen\n" -#~ " Punkt enthält, dann sind dadurch nur " -#~ "Fenster\n" -#~ " betroffen, deren WM_CLASS-Eigenschaft " -#~ "exakt\n" -#~ " übereinstimmt. Ohne Punkt werden Fenster\n" -#~ " derselben Klasse und Fenster derselben " -#~ "Instanz\n" -#~ " (alias »-name« ausgewählt).\n" -#~ "\n" -#~ "Aktionen:\n" -#~ " setIconTitle BEZEICHNUNG Legt die Symbolbezeichnung fest.\n" -#~ " setWindowTitle BEZEICHNUNG Legt die Fensterbezeichnung fest.\n" -#~ " setState MASKE ZUSTAND Setzt den GNOME-Fensterzustand auf " -#~ "ZUSTAND.\n" -#~ " Nur die durch die MASKE gewählten Bits " -#~ "sind\n" -#~ " betroffen. ZUSTAND und MASKE sind " -#~ "Ausdrücke\n" -#~ " des Bereichs »GNOME-Fensterzustand«.\n" -#~ " toggleState ZUSTAND Wechselt die durch den Ausdruck ZUSTAND\n" -#~ " beschriebenen GNOME-Fensterzustandbits.\n" -#~ " setHints HINWEIS Legt den GNOME-Fensterhinweis fest.\n" -#~ " setLayer EBENE Legt das Fenster auf eine andere GNOME-" -#~ "Fensterebene.\n" -#~ " setWorkspace ARBEITSBEREICH Legt das Fenster auf einen anderen\n" -#~ " Arbeitsbereich. Wählen Sie das »root«-\n" -#~ " Fenster, um den momentanen Arbeitsbereich " -#~ "zu\n" -#~ " ändern.\n" -#~ " 0xFFFFFFFF oder \"Alles\" für alle " -#~ "Arbeitsbereiche auswählen.\n" -#~ " listWorkspaces Zeigt eine Liste aller Arbeitsbereiche.\n" -#~ " setTrayOption TRAYOPTION Legt den IceWM-Trayoption-Hinweis fest.\n" -#~ " logout Sage IceWM sich abzumelden.\n" -#~ " reboot Sage IceWM neu zu starten.\n" -#~ " shutdown Sage IceWM herunter zu fahren.\n" -#~ " cancel Sage IceWM den Logout/den Neustart/das " -#~ "Herunterfahren abzubrechen.\n" -#~ " about Sage IceWM das Fenster Über anzuzeigen.\n" -#~ " windowlist Sage IceWM die Fenster-Liste anzuzeigen.\n" -#~ " restart Sage IceWM neu zu starten.\n" -#~ " suspend Sage IceWM einzufrieren.\n" -#~ "\n" -#~ "Ausdrücke:\n" -#~ " Ausdrücke sind eine Liste an Symbolen desselben Bereichs, die durch `+` " -#~ "oder `|` verbunden sind:\n" -#~ "\n" -#~ " AUSDRUCK ::= SYMBOL | AUSDRUCK ( `+«`| `|` ) SYMBOL\n" -#~ "\n" +#: src/ymsgbox.cc:48 +msgid "_OK" +msgstr "_OK" -#~ msgid "Can't connect to ESound daemon: %s" -#~ msgstr "Kann keine Verbindung zum ESound-Daemon herstellen: %s" +#: src/wmapp.cc:560 +msgid "_OnTop" +msgstr "_Obenauf" -#~ msgid "Error <%d> while uploading `%s:%s'" -#~ msgstr "Fehler <%d> beim Hochladen von `%s:%s`" +#: src/yinputline.cc:20 +msgid "_Paste" +msgstr "_Einfügen" -#~ msgid "Sample <%d> uploaded as `%s:%s'" -#~ msgstr "Sample <%d> wurde als »%s:%s« hochgeladen" +#: src/wmprog.cc:451 +msgid "_Preferences" +msgstr "_Wünsche" -#~ msgid "Playing sample #%d: %d" -#~ msgstr "Spiele Sample #%d: %d" +#: src/wmprog.cc:347 +msgid "_Quiet sloppy focus" +msgstr "Salopper Fokus (_träge)" -#~ msgid "Usage error: " -#~ msgstr "Verwendungsfehler: " +#: src/wmwinlist.cc:445 +msgid "_Raise" +msgstr "An_heben" -#~ msgid "Out of memory for image %s" -#~ msgstr "Kein Speicher frei für das Bild %s" +#. TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout +#: src/wmtaskbar.cc:236 +msgid "_Refresh" +msgstr "_Aktualisieren" -#~ msgid "_Minimize" -#~ msgstr "Mi_nimieren" +#: src/wmdialog.cc:93 +msgid "_Restart icewm" +msgstr "_IceWM neu starten" -#~ msgid "Error at %s: '%s'" -#~ msgstr "Fehler bei %s: '%s'" +#: src/wmapp.cc:642 src/wmwinlist.cc:436 +msgid "_Restore" +msgstr "_Wiederherstellen" -#~ msgid "\"%s\" contains no scheme description" -#~ msgstr "\"%s\" enthält keine Schemabeschreibung" +#: src/wmprog.cc:426 +msgid "_Run..." +msgstr "Aus_führen..." + +#: src/acpustatus.cc:916 +msgid "_Separate" +msgstr "_Aufteilen" -#~ msgid "Please note that not all options are currently configured.\n" -#~ msgstr "" -#~ "Bitte beachten, dass nicht alle Optionen momentan konfiguriert sind.\n" +#: src/wmwinlist.cc:442 +msgid "_Show" +msgstr "_Anzeigen" -#~ msgid "\"%s\" doesn't describe a common internet scheme" -#~ msgstr "\"%s\" entspricht nicht dem Common Internet Scheme" +#: src/wmapp.cc:646 +msgid "_Size" +msgstr "_Größe" -#~ msgid "Out of memory for pixmap \"%s\"" -#~ msgstr "Kein Speicher frei zum Laden der Bilddatei \"%s\"" +#: src/wmapp.cc:539 src/wmdialog.cc:86 +msgid "_Sleep mode" +msgstr "Schlaf-_Modus" -#~ msgid "Out of memory for window options" -#~ msgstr "Kein freier Speicher für Fensteroptionen verfügbar" +#: src/wmprog.cc:345 +msgid "_Sloppy mouse focus" +msgstr "_Salopper Maus-Fokus" -#~ msgid "Error in window option: %s" -#~ msgstr "Fehlerhafte Fensteroption: %s" +#: src/amailbox.cc:965 +msgid "_Suspend" +msgstr "_Unterbrechen" -#~ msgid "" -#~ "Usage: %s FILENAME\n" -#~ "\n" -#~ "A very simple HTML browser displaying the document specified by " -#~ "FILENAME.\n" -#~ "\n" -#~ msgstr "" -#~ "Syntax: %s DATEI\n" -#~ "\n" -#~ "Ein einfacher HTML-Browser zum Betrachten der angegebenen DATEI.\n" -#~ "\n" +#: src/wmwinlist.cc:472 +msgid "_Terminate Process" +msgstr "Prozess be_enden" -#~ msgid "No such device: %s" -#~ msgstr "Kein derartiges Gerät: %s" +#: src/wmprog.cc:456 +msgid "_Themes" +msgstr "_Themes" -#~ msgid "Can't change to audio mode `%s'." -#~ msgstr "Kann nicht zum Audiomodus »%s« wechseln." +#: src/aclock.cc:204 +msgid "_UTC" +msgstr "_UTC" -#~ msgid "" -#~ "Audio mode switch detected, initial audio mode `%s' no longer in effect." -#~ msgstr "" -#~ "Wechsel des Audiomodus entdeckt. Der anfängliche Audiomodus »%s« wird " -#~ "nicht länger benutzt." +#. TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout +#: src/wmtaskbar.cc:227 src/wmwinlist.cc:462 src/wmwinlist.cc:494 +msgid "_Undo" +msgstr "_Rückgängig" -#~ msgid "Audio mode switch detected, automatic audio mode changing disabled." -#~ msgstr "" -#~ "Wechsel des Audiomodus entdeckt. Automatisches Wechseln des Audiomodus " -#~ "wurde deaktiviert." +#: src/wmapp.cc:701 src/wmdialog.cc:92 src/wmwinmenu.cc:141 +msgid "_Window list" +msgstr "_Fensterliste" -#~ msgid "Overriding previous audio mode `%s'." -#~ msgstr "Übergehe vorherigen Audiomodus »%s«." +#. TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout +#: src/wmprog.cc:430 src/wmtaskbar.cc:233 +msgid "_Windows" +msgstr "F_enster" -#~ msgid "Multiple sound interfaces given." -#~ msgstr "Es wurden mehrere verschiedene Audiointerfaces angegeben." +#: src/icesound.cc:499 +#, c-format +msgid "ao_open_live failed with %d" +msgstr "ao_open_live ist mit %d fehlgeschlagen" -#~ msgid "Received signal %d: Reloading samples..." -#~ msgstr "Signal %d erhalten: Aktualisiere die Samples..." +#: src/icesound.cc:510 +msgid "ao_play failed" +msgstr "ao_play ist fehlgeschlagen" -#~ msgid "Message Loop: select failed (errno=%d)" -#~ msgstr "Nachrichtenschleife: select fehlgeschlagen (errno=%d)" +#: src/amemstatus.cc:156 +msgid "bytes" +msgstr "Bytes" -#~ msgid "Argument required for %s switch" -#~ msgstr "Die %s-Option benötigt ein Argument" +#: src/apppstatus.cc:284 +msgid "disconnected" +msgstr "Verbindung getrennt" -#~ msgid "Loading of image \"%s\" failed" -#~ msgstr "Laden der Bilddatei »%s« fehlgeschlagen" +#: src/wmapp.cc:116 +msgid "done." +msgstr "erledigt." -#~ msgid "Imlib: Acquisition of X pixmap failed" -#~ msgstr "Imlib: Übernahme der X-Pixmap ist gescheitert" +#: src/apppstatus.cc:284 +msgid "down" +msgstr "abwärts" -#~ msgid "Imlib: Imlib image to X pixmap mapping failed" -#~ msgstr "Imlib: Abbildung des Imlib-Bildes auf eine X-Pixmap ist gescheitert" +#: src/wmabout.cc:71 +msgid "icewm - About" +msgstr "IceWM - Über" -#~ msgid "" -#~ "Using fallback mechanism to convert pixels (depth: %d; masks (red/green/" -#~ "blue): %0*x/%0*x/%0*x)" -#~ msgstr "" -#~ "Benutze den (langsamen) Ausweichalgorithmus zum Konvertieren von Pixeln " -#~ "(Farbtiefe: %d, Masken (Rot/Grün/Blau): %0*x/%0*x/%0*x)" +#: src/ylocale.cc:126 src/ylocale.cc:134 +#, c-format +msgid "iconv doesn't supply (sufficient) %s to %s converters." +msgstr "" +"iconv verfügt nicht über einen (zufriedenstellenden) %s zu %s-Konvertierer." -#~ msgid "%s:%d: %d bit visuals are not supported (yet)" -#~ msgstr "%s:%d: %d-Bit-Visuals werden (momentan) nicht unterstützt" +#: src/amemstatus.cc:152 +msgid "kB" +msgstr "kB" -#~ msgid "Multiple references for gradient '%s' in theme '%s'." -#~ msgstr "Unterschiedliche Referenzen für Gradienten '%s' in Theme '%s'." +#: src/akeyboard.cc:96 +msgid "layout:" +msgstr "Layout:" -#~ msgid "Unknown gradient name '%s' in theme '%s'." -#~ msgstr "Unbekannter Gradienten-Name '%s' in Theme '%s'." +#: src/akeyboard.cc:95 +msgid "model:" +msgstr "Modell:" -# -#~ msgid "Bad Look name" -#~ msgstr "Ungültiger Stilname (look-Option)" +#: src/akeyboard.cc:97 +msgid "options:" +msgstr "Optionen:" -#~ msgid "" -#~ "%s: unrecognized option `%s'\n" -#~ "Try `%s --help' for more information.\n" -#~ msgstr "" -#~ "%s: Unbekannte Option: »%s«\n" -#~ "Versuchen Sie »%s --help« für weitere Informationen.\n" +#: src/aapm.cc:940 +#, c-format +msgid "power:\t%s" +msgstr "Energie:\t%s" -#~ msgid "Loading image %s failed" -#~ msgstr "Laden der Bilddatei %s fehlgeschlagen" +#: src/icesm.cc:462 src/icesm.cc:622 +#, c-format +msgid "restart %s." +msgstr "Neustart %s." -#~ msgid "Bad argument %d" -#~ msgstr "Ungültiges Argument: %d" +#: src/akeyboard.cc:94 +msgid "rules:" +msgstr "Regeln:" -#~ msgid "Out of memory for image: %s" -#~ msgstr "Kein Speicher frei fürs Bild: %s" +#: src/icesh.cc:2376 src/icesh.cc:2449 +#, c-format +msgid "workspace #%d: `%s'\n" +msgstr "Arbeitsbereich #%d: `%s`\n" -#~ msgid "Could not find image: %s" -#~ msgstr "Bild nicht gefunden: %s" +#. TRANSLATORS: Please translate the string "C" into "Celsius Temperature" in your language. +#. TRANSLATORS: Please make sure the translated string could be shown in your non-utf8 locale. +#: src/acpustatus.cc:348 +msgid "°C" +msgstr "°C" -#~ msgid "Invalid path: " -#~ msgstr "Ungültiger Pfad: " +#~ msgid "" +#~ "\n" +#~ " Caller id:\t" +#~ msgstr "" +#~ "\n" +#~ " Anschlußkennung:\t" #~ msgid "" #~ " Usage: %s [OPTION]...\n" @@ -3349,9 +3111,28 @@ msgstr "Bild \"%s\" konnte nicht geladen werden" #~ " 3 Subsystem-Fehler (d. h. Verbindung zum Server nicht möglich)\n" #~ "\n" +#~ msgid "" +#~ " IceWM crashed for the second time in 10 seconds. \n" +#~ " Do you wish to:\n" +#~ "\n" +#~ "\t1: Restart IceWM?\n" +#~ "\t2: Abort this session?\n" +#~ msgstr "" +#~ " IceWM stürzte das zweite Mal in 10 sekunden ab. \n" +#~ " Möchten Sie:\n" +#~ "\n" +#~ "1: IceWM neu starten?\n" +#~ "2: Diese Sitzung abbrechen?\n" + #~ msgid " processes." #~ msgstr "Prozesse." +#~ msgid "\"%s\" contains no scheme description" +#~ msgstr "\"%s\" enthält keine Schemabeschreibung" + +#~ msgid "\"%s\" doesn't describe a common internet scheme" +#~ msgstr "\"%s\" entspricht nicht dem Common Internet Scheme" + #~ msgid "" #~ "# NOTE: All settings are commented out by default, be sure to\n" #~ "# uncomment them if you change them!\n" @@ -3368,6 +3149,16 @@ msgstr "Bild \"%s\" konnte nicht geladen werden" #~ "# Einstellungen(%s) - erzeugt von genpref\n" #~ "\n" +#~ msgid "" +#~ "%s: unrecognized option `%s'\n" +#~ "Try `%s --help' for more information.\n" +#~ msgstr "" +#~ "%s: Unbekannte Option: »%s«\n" +#~ "Versuchen Sie »%s --help« für weitere Informationen.\n" + +#~ msgid "%s:%d: %d bit visuals are not supported (yet)" +#~ msgstr "%s:%d: %d-Bit-Visuals werden (momentan) nicht unterstützt" + #~ msgid "%s:%d: Failed to copy drawable 0x%x to pixel buffer" #~ msgstr "%s:%d: Kopieren vom Fenster 0x%x in Pixelpuffer fehlgeschlagen" @@ -3377,17 +3168,79 @@ msgstr "Bild \"%s\" konnte nicht geladen werden" #~ msgid "/proc/apm - unknown format (%d)" #~ msgstr "/proc/apm - Unbekanntes Format (%d)" +#~ msgid "0x%-8lx %-14s: %-20s %dx%d%+d%+d\n" +#~ msgstr "0x%-8lx %-14s: %-20s %dx%d%+d%+d\n" + +#~ msgid "Accessories" +#~ msgstr "Zubehör" + +#~ msgid "Argument required for %s switch" +#~ msgstr "Die %s-Option benötigt ein Argument" + +#~ msgid "Audio mode switch detected, automatic audio mode changing disabled." +#~ msgstr "" +#~ "Wechsel des Audiomodus entdeckt. Automatisches Wechseln des Audiomodus " +#~ "wurde deaktiviert." + +#~ msgid "" +#~ "Audio mode switch detected, initial audio mode `%s' no longer in effect." +#~ msgstr "" +#~ "Wechsel des Audiomodus entdeckt. Der anfängliche Audiomodus »%s« wird " +#~ "nicht länger benutzt." + +# +#~ msgid "Bad Look name" +#~ msgstr "Ungültiger Stilname (look-Option)" + +#~ msgid "Bad argument %d" +#~ msgstr "Ungültiges Argument: %d" + #~ msgid "CPU Load: %3.2f %3.2f %3.2f, %d" #~ msgstr "CPU-Last:\t%3.2f %3.2f %3.2f %d" +#~ msgid "CPU: %llu %llu %llu %llu %llu %llu %llu %llu" +#~ msgstr "CPU: %llu %llu %llu %llu %llu %llu %llu %llu" + +#~ msgid "Can't change to audio mode `%s'." +#~ msgstr "Kann nicht zum Audiomodus »%s« wechseln." + +#~ msgid "Can't connect to ESound daemon: %s" +#~ msgstr "Kann keine Verbindung zum ESound-Daemon herstellen: %s" + +#, fuzzy +#~| msgid "Close" +#~ msgid "Clos_e" +#~ msgstr "Schließen" + #~ msgid "Compiled with DEBUG flag. Debugging messages will be printed." #~ msgstr "Mit DEBUG-Flag kompiliert. Debugging-Nachrichten werden angezeigt." #~ msgid "Could not find RGB pixel buffer %s" #~ msgstr "RGB-Pixelpuffer »%s« nicht gefunden" -#~ msgid "Could not find pixel map %s" -#~ msgstr "Bilddaten %s wurden nicht gefunden" +#~ msgid "Could not find image: %s" +#~ msgstr "Bild nicht gefunden: %s" + +#~ msgid "Could not find pixel map %s" +#~ msgstr "Bilddaten %s wurden nicht gefunden" + +#~ msgid "Editors" +#~ msgstr "Editoren" + +#~ msgid "Error <%d> while uploading `%s:%s'" +#~ msgstr "Fehler <%d> beim Hochladen von `%s:%s`" + +#~ msgid "Error at %s: '%s'" +#~ msgstr "Fehler bei %s: '%s'" + +#~ msgid "Error in window option: %s" +#~ msgstr "Fehlerhafte Fensteroption: %s" + +#~ msgid "GNOME window hint" +#~ msgstr "GNOME-Fensterbeschreibung" + +#~ msgid "GNOME window state" +#~ msgstr "GNOME-Fensterzustand" #~ msgid "Gnome" #~ msgstr "Gnome-Systemmenü" @@ -3398,6 +3251,12 @@ msgstr "Bild \"%s\" konnte nicht geladen werden" #~ msgid "Identifier expected" #~ msgstr "Schlüsselwort erwartet" +#~ msgid "Imlib: Acquisition of X pixmap failed" +#~ msgstr "Imlib: Übernahme der X-Pixmap ist gescheitert" + +#~ msgid "Imlib: Imlib image to X pixmap mapping failed" +#~ msgstr "Imlib: Abbildung des Imlib-Bildes auf eine X-Pixmap ist gescheitert" + #~ msgid "" #~ "Interface %s:\n" #~ " Current rate (in/out):\t%li %s/%li %s\n" @@ -3413,12 +3272,46 @@ msgstr "Bild \"%s\" konnte nicht geladen werden" #~ " Gesamttransfer (ein/aus):\t%lli %s / %lli %s\n" #~ " Onlinezeit:\t%ld:%02ld:%02ld%s%s" +#~ msgid "Invalid cursor pixmap: \"%s\" contains too much unique colors" +#~ msgstr "" +#~ "Ungültiges Cursor-Bilddatei: \"%s\" enthält zu viele einzigartige Farben" + #~ msgid "Invalid fonts in fontset definition \"%s\":" #~ msgstr "Ungültige Schriften in der Schriftfamiliendefinition »%s«:" +#~ msgid "Invalid path: " +#~ msgstr "Ungültiger Pfad: " + #~ msgid "Invalid token" #~ msgstr "Ungültiges Symbol " +#~ msgid "Kill IceWM, replace with Xterm" +#~ msgstr "IceWM töten, mit Xterm ersetzen" + +#~ msgid "Loading image %s failed" +#~ msgstr "Laden der Bilddatei %s fehlgeschlagen" + +#~ msgid "Loading of fallback font \"%s\" failed." +#~ msgstr "Rückgriff auf die Schriftart \"%s\" ist fehlgeschlagen." + +#~ msgid "Loading of image \"%s\" failed" +#~ msgstr "Laden der Bilddatei »%s« fehlgeschlagen" + +#~ msgid "Message Loop: select failed (errno=%d)" +#~ msgstr "Nachrichtenschleife: select fehlgeschlagen (errno=%d)" + +#~ msgid "Multimedia" +#~ msgstr "Multimedia" + +#~ msgid "Multiple references for gradient '%s' in theme '%s'." +#~ msgstr "Unterschiedliche Referenzen für Gradienten '%s' in Theme '%s'." + +#~ msgid "Multiple sound interfaces given." +#~ msgstr "Es wurden mehrere verschiedene Audiointerfaces angegeben." + +#~ msgid "No such device: %s" +#~ msgstr "Kein derartiges Gerät: %s" + #~ msgid "Not a hexadecimal number: %c%c (in \"%s\")" #~ msgstr "Keine hexadezimale Ziffer: %c%c (in »%s«)" @@ -3431,22 +3324,50 @@ msgstr "Bild \"%s\" konnte nicht geladen werden" #~ msgid "Out of memory for RGB pixel buffer %s" #~ msgstr "Kein freier Speicher für den RGB-Pixelpuffer »%s«" +#~ msgid "Out of memory for image %s" +#~ msgstr "Kein Speicher frei für das Bild %s" + +#~ msgid "Out of memory for image: %s" +#~ msgstr "Kein Speicher frei fürs Bild: %s" + #~ msgid "Out of memory for pixel map %s" #~ msgstr "Kein freier Speicher für die Pixmap %s verfügbar" +#~ msgid "Out of memory for pixmap \"%s\"" +#~ msgstr "Kein Speicher frei zum Laden der Bilddatei \"%s\"" + +#~ msgid "Out of memory for window options" +#~ msgstr "Kein freier Speicher für Fensteroptionen verfügbar" + #~ msgid "Out of memory: Unable to allocated %d bytes." #~ msgstr "Speichermangel: Anforderung von %d Byte ist fehlgeschlagen." +#~ msgid "Overriding previous audio mode `%s'." +#~ msgstr "Übergehe vorherigen Audiomodus »%s«." + #~ msgid "Pair of hexadecimal digits expected" #~ msgstr "Paar von hexadezimalen Ziffern erwartet" #~ msgid "Pipe creation failed (errno=%d)." #~ msgstr "Erzeugen einer Pipe ist fehlgeschlagen (errno=%d)." +#~ msgid "Playing sample #%d: %d" +#~ msgstr "Spiele Sample #%d: %d" + +#~ msgid "Please note that not all options are currently configured.\n" +#~ msgstr "" +#~ "Bitte beachten, dass nicht alle Optionen momentan konfiguriert sind.\n" + +#~ msgid "Received signal %d: Reloading samples..." +#~ msgstr "Signal %d erhalten: Aktualisiere die Samples..." + #~ msgid "Resource allocation for rotated string \"%s\" (%dx%d px) failed" #~ msgstr "" #~ "Keine Ressourcen für die rotierte Zeichenkette »%s« (%dx%d px) verfügbar" +#~ msgid "Sample <%d> uploaded as `%s:%s'" +#~ msgstr "Sample <%d> wurde als »%s:%s« hochgeladen" + #~ msgid "Separator expected" #~ msgstr "Trennzeichen erwartet" @@ -3459,9 +3380,165 @@ msgstr "Bild \"%s\" konnte nicht geladen werden" #~ msgid "TOO MANY ICE CONNECTIONS -- not supported" #~ msgstr "ZU VIELE ICE-VERBINDUNGEN -- nicht unterstützt" +#~ msgid "Task Bar" +#~ msgstr "Taskleiste" + +#~ msgid "Unable to get current font path." +#~ msgstr "Der aktuelle Fontpfad kann nicht bestimmt werden." + +#~ msgid "Unexpected format of ICEWM_FONT_PATH property" +#~ msgstr "Unerwartetes Format der ICEWM_FONT_PATH-Property" + #~ msgid "Unexpected identifier" #~ msgstr "Unerwartetes Schlüsselwort" +#~ msgid "Unknown gradient name '%s' in theme '%s'." +#~ msgstr "Unbekannter Gradienten-Name '%s' in Theme '%s'." + +#~ msgid "Usage error: " +#~ msgstr "Verwendungsfehler: " + +#~ msgid "" +#~ "Usage: %s FILENAME\n" +#~ "\n" +#~ "A very simple HTML browser displaying the document specified by " +#~ "FILENAME.\n" +#~ "\n" +#~ msgstr "" +#~ "Syntax: %s DATEI\n" +#~ "\n" +#~ "Ein einfacher HTML-Browser zum Betrachten der angegebenen DATEI.\n" +#~ "\n" + +#~ msgid "" +#~ "Usage: %s [OPTIONS] ACTIONS\n" +#~ "\n" +#~ "Options:\n" +#~ " -d, -display DISPLAY Connects to the X server specified by " +#~ "DISPLAY.\n" +#~ " Default: $DISPLAY or :0.0 when not set.\n" +#~ " -w, -window WINDOW_ID Specifies the window to manipulate. " +#~ "Special\n" +#~ " identifiers are `root' for the root window " +#~ "and\n" +#~ " `focus' for the currently focused window.\n" +#~ " -c, -class WM_CLASS Window management class of the window(s) " +#~ "to\n" +#~ " manipulate. If WM_CLASS contains a period, " +#~ "only\n" +#~ " windows with exactly the same WM_CLASS " +#~ "property\n" +#~ " are matched. If there is no period, windows " +#~ "of\n" +#~ " the same class and windows of the same " +#~ "instance\n" +#~ " (aka. `-name') are selected.\n" +#~ "\n" +#~ "Actions:\n" +#~ " setIconTitle TITLE Set the icon title.\n" +#~ " setWindowTitle TITLE Set the window title.\n" +#~ " setGeometry geometry Set the window geometry\n" +#~ " setState MASK STATE Set the GNOME window state to STATE.\n" +#~ " Only the bits selected by MASK are " +#~ "affected.\n" +#~ " STATE and MASK are expressions of the " +#~ "domain\n" +#~ " `GNOME window state'.\n" +#~ " toggleState STATE Toggle the GNOME window state bits " +#~ "specified by\n" +#~ " the STATE expression.\n" +#~ " setHints HINTS Set the GNOME window hints to HINTS.\n" +#~ " setLayer LAYER Moves the window to another GNOME window " +#~ "layer.\n" +#~ " setWorkspace WORKSPACE Moves the window to another workspace. " +#~ "Select\n" +#~ " the root window to change the current " +#~ "workspace.\n" +#~ " Select 0xFFFFFFFF or \"All\" for all " +#~ "workspaces.\n" +#~ " listWorkspaces Lists the names of all workspaces.\n" +#~ " setTrayOption TRAYOPTION Set the IceWM tray option hint.\n" +#~ " logout Tell IceWM to logout.\n" +#~ " reboot Tell IceWM to reboot.\n" +#~ " shutdown Tell IceWM to shutdown.\n" +#~ " cancel Tell IceWM to cancel the logout/reboot/" +#~ "shutdown.\n" +#~ " about Tell IceWM to show the about window.\n" +#~ " windowlist Tell IceWM to show the window list.\n" +#~ " restart Tell IceWM to restart.\n" +#~ " suspend Tell IceWM to suspend.\n" +#~ "\n" +#~ "Expressions:\n" +#~ " Expressions are list of symbols of one domain concatenated by `+' or " +#~ "`|':\n" +#~ "\n" +#~ " EXPRESSION ::= SYMBOL | EXPRESSION ( `+' | `|' ) SYMBOL\n" +#~ "\n" +#~ msgstr "" +#~ "Syntax: %s [OPTIONEN] AKTIONEN\n" +#~ "\n" +#~ "Optionen:\n" +#~ " -d, -display DISPLAY Mit dem durch DISPLAY beschriebenen X-" +#~ "Server\n" +#~ " verbinden. Vorgabe: $DISPLAY oder :0.0, " +#~ "falls nicht gesetzt.\n" +#~ " -w, -window FENSTER_ID Das zu beeinflussende Fenster. " +#~ "Besondere\n" +#~ " Bezeichner sind »root« für den Desktop und\n" +#~ " »focus« für das momentan aktive Fenster.\n" +#~ " -c, -class WM_CLASS Fenstermanagement-Klasse der/des zu\n" +#~ " manipulierenden Fenster/s. Wenn WM_CLASS " +#~ "einen\n" +#~ " Punkt enthält, dann sind dadurch nur " +#~ "Fenster\n" +#~ " betroffen, deren WM_CLASS-Eigenschaft " +#~ "exakt\n" +#~ " übereinstimmt. Ohne Punkt werden Fenster\n" +#~ " derselben Klasse und Fenster derselben " +#~ "Instanz\n" +#~ " (alias »-name« ausgewählt).\n" +#~ "\n" +#~ "Aktionen:\n" +#~ " setIconTitle BEZEICHNUNG Legt die Symbolbezeichnung fest.\n" +#~ " setWindowTitle BEZEICHNUNG Legt die Fensterbezeichnung fest.\n" +#~ " setState MASKE ZUSTAND Setzt den GNOME-Fensterzustand auf " +#~ "ZUSTAND.\n" +#~ " Nur die durch die MASKE gewählten Bits " +#~ "sind\n" +#~ " betroffen. ZUSTAND und MASKE sind " +#~ "Ausdrücke\n" +#~ " des Bereichs »GNOME-Fensterzustand«.\n" +#~ " toggleState ZUSTAND Wechselt die durch den Ausdruck ZUSTAND\n" +#~ " beschriebenen GNOME-Fensterzustandbits.\n" +#~ " setHints HINWEIS Legt den GNOME-Fensterhinweis fest.\n" +#~ " setLayer EBENE Legt das Fenster auf eine andere GNOME-" +#~ "Fensterebene.\n" +#~ " setWorkspace ARBEITSBEREICH Legt das Fenster auf einen anderen\n" +#~ " Arbeitsbereich. Wählen Sie das »root«-\n" +#~ " Fenster, um den momentanen Arbeitsbereich " +#~ "zu\n" +#~ " ändern.\n" +#~ " 0xFFFFFFFF oder \"Alles\" für alle " +#~ "Arbeitsbereiche auswählen.\n" +#~ " listWorkspaces Zeigt eine Liste aller Arbeitsbereiche.\n" +#~ " setTrayOption TRAYOPTION Legt den IceWM-Trayoption-Hinweis fest.\n" +#~ " logout Sage IceWM sich abzumelden.\n" +#~ " reboot Sage IceWM neu zu starten.\n" +#~ " shutdown Sage IceWM herunter zu fahren.\n" +#~ " cancel Sage IceWM den Logout/den Neustart/das " +#~ "Herunterfahren abzubrechen.\n" +#~ " about Sage IceWM das Fenster Über anzuzeigen.\n" +#~ " windowlist Sage IceWM die Fenster-Liste anzuzeigen.\n" +#~ " restart Sage IceWM neu zu starten.\n" +#~ " suspend Sage IceWM einzufrieren.\n" +#~ "\n" +#~ "Ausdrücke:\n" +#~ " Ausdrücke sind eine Liste an Symbolen desselben Bereichs, die durch `+` " +#~ "oder `|` verbunden sind:\n" +#~ "\n" +#~ " AUSDRUCK ::= SYMBOL | AUSDRUCK ( `+«`| `|` ) SYMBOL\n" +#~ "\n" + #~ msgid "" #~ "Usage: icewmbg [ -r | -q ]\n" #~ " -r Restart icewmbg\n" @@ -3504,6 +3581,13 @@ msgstr "Bild \"%s\" konnte nicht geladen werden" #~ "-s, --semitransparency Aktiviere die Unterstützung for " #~ "semitransparente Terminals\n" +#~ msgid "" +#~ "Using fallback mechanism to convert pixels (depth: %d; masks (red/green/" +#~ "blue): %0*x/%0*x/%0*x)" +#~ msgstr "" +#~ "Benutze den (langsamen) Ausweichalgorithmus zum Konvertieren von Pixeln " +#~ "(Farbtiefe: %d, Masken (Rot/Grün/Blau): %0*x/%0*x/%0*x)" + #~ msgid "" #~ "Window %p has no XA_ICEWM_PID property. Export the LD_PRELOAD variable to " #~ "preload the preice library." @@ -3523,6 +3607,12 @@ msgstr "Bild \"%s\" konnte nicht geladen werden" #~ msgid "_Ignore" #~ msgstr "_Übergehen" +#~ msgid "_License" +#~ msgstr "_Lizenz" + +#~ msgid "_Minimize" +#~ msgstr "Mi_nimieren" + #~ msgid "_Minimized" #~ msgstr "_Minimiert" @@ -3532,6 +3622,13 @@ msgstr "Bild \"%s\" konnte nicht geladen werden" #~ msgid "action name expected" #~ msgstr "Aktionsnamen erwartet" +#~ msgid "" +#~ "bars:\tuser = %llu, nice = %llu, sys = %llu, iowait = %llu, intr = %llu, " +#~ "softirq = %llu, steal = %llu (h = %i)\n" +#~ msgstr "" +#~ "Balken:\tBenutzer = %llu, nice = %llu, sys = %llu, iowait = %llu, intr = " +#~ "%llu, softirq = %llu, steal = %llu (h = %i)\n" + #~ msgid "cpu: %d %d %d %d" #~ msgstr "CPU: %d %d %d %d" @@ -3547,6 +3644,13 @@ msgstr "Bild \"%s\" konnte nicht geladen werden" #~ msgid "program label expected" #~ msgstr "Programmbezeichner erwartet" +#~ msgid "" +#~ "stat:\tuser = %llu, nice = %llu, sys = %llu, idle = %llu, iowait = %llu, " +#~ "intr = %llu, softirq = %llu, steal = %llu\n" +#~ msgstr "" +#~ "stat:\tBenutzer = %llu, nice = %llu, sys = %llu, idle = %llu, iowait = " +#~ "%llu, intr = %llu, softirq = %llu, entwendet = %llu\n" + #~ msgid "unknown action" #~ msgstr "Unbekannte Aktion" From 5d735df293e61fd94e114ef58e800d757f98d01c Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Fri, 27 Sep 2024 19:20:39 +0200 Subject: [PATCH 37/85] Helper to create locale folder mock Can be used while specifying -DLOCDIR=/po/playground in development builds. --- po/CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/po/CMakeLists.txt b/po/CMakeLists.txt index bd439b0a4..cb856ae17 100644 --- a/po/CMakeLists.txt +++ b/po/CMakeLists.txt @@ -75,6 +75,13 @@ if(gettext AND xgettext AND msgmerge AND msgfmt) ADD_CUSTOM_TARGET(generate-${_lang}.gmo DEPENDS ${_tempMO}) install(FILES ${_tempMO} DESTINATION "${LOCDIR}/${_lang}/LC_MESSAGES/" RENAME "${PACKAGE}.mo" OPTIONAL) add_dependencies(translations generate-${_lang}.gmo) + + # mimic the content of the installation folder, for development purposes + set(PG "${CMAKE_CURRENT_BINARY_DIR}/playground") + file(MAKE_DIRECTORY "${PG}") + file(MAKE_DIRECTORY "${PG}/${_lang}/LC_MESSAGES/") + file(CREATE_LINK ${_tempMO} "${PG}/${_lang}/LC_MESSAGES/${PACKAGE}.mo" SYMBOLIC) + endforeach() endif() From 8cbfd301d6336f2dc7bfde7fa636e9b527db07f5 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Fri, 27 Sep 2024 19:54:47 +0200 Subject: [PATCH 38/85] Fix loading from gettext if menu did not have a description --- src/fdomenu.cc | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index d0e6d9936..c2cf5bc3c 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -262,16 +262,15 @@ struct DesktopFile : public tLintRefcounted { /// Translate with built-in l10n if needed, and cache it string &GetTranslatedName() { - if (NameLoc.empty()) { + if (NameLoc.empty() && !Name.empty()) NameLoc = gettext(Name.c_str()); - } return NameLoc; } string &GetTranslatedGenericName() { - if (GenericNameLoc.empty()) { + if (GenericNameLoc.empty() && !GenericName.empty()) GenericNameLoc = gettext(GenericName.c_str()); - } + return GenericNameLoc; } @@ -822,15 +821,17 @@ void MenuNode::print(std::ostream &prt_strm) { } for (auto &m : sorted) { auto &name = m.first; - prt_strm << indent_hint << "menu \"" - << (m.second.second->deco - ? m.second.second->deco->GetTranslatedName() - : name) - << "\" " << - - ((m.second.second->deco && !m.second.second->deco->Icon.empty()) - ? m.second.second->deco->Icon - : ICON_FOLDER) + prt_strm << indent_hint << "menu \""; + if (m.second.second->deco) + prt_strm << m.second.second->deco->GetTranslatedName(); + else + prt_strm << gettext(name.c_str()); + + prt_strm << "\" " + << ((m.second.second->deco && + !m.second.second->deco->Icon.empty()) + ? m.second.second->deco->Icon + : ICON_FOLDER) << " {\n"; indent_hint += "\t"; From 5eafe9475cca1269615e29d37eb434378715d7c7 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Sat, 28 Sep 2024 10:37:34 +0200 Subject: [PATCH 39/85] Fix and streamline conversion flow - fix bad vim modeline, align with parent folder - simplified flow, making it straight with control options rather than depending obscure targets - document the flow - explicit developer options to control the behavior - drop deprecated option in POT creation (xgettext warning) --- po/CMakeLists.txt | 213 +++++++++++++++++++++++++++++----------------- 1 file changed, 135 insertions(+), 78 deletions(-) diff --git a/po/CMakeLists.txt b/po/CMakeLists.txt index cb856ae17..1b6d77fa4 100644 --- a/po/CMakeLists.txt +++ b/po/CMakeLists.txt @@ -1,11 +1,43 @@ cmake_minimum_required(VERSION 3.5) -PROJECT(ICEWM CXX) - -# yes, FindGettext.cmake exists but it's not really handy :-( -# XXX: document -DEXTRA_MSGMERGE=--verbose -DEXTRA_MSGFMT=--verbose +project(ICEWM CXX) + +# +# Custom PO file processing (POT extraction/update, PO merging, MO building). +# +# Callable custom targets (part of ALL target): +# +# The default rule set updates pot, *.po, and compiles *.(g)mo from the updated +# versions. Also some CACHED options: +# - with PO_REPLACE options, the updated files are sync'ed back to source code +# folder in the build phase. +# - with PO_REPLACE_ONCE the original PO/POT files are replaced once and then +# not again (cached) +# - with SKIP_TRANSLATIONS, the whole PO processing is turned off and MO files +# are NOT installed. This might be handy in the development process. +# +# when gettext tools are missing, no processing is performed. +# + +option(SKIP_TRANSLATIONS "[DEV] Don't perform PO/MO file creation or installation" off) +option(PO_VERBOSE "[DEV] Extra verbosity in gettext processing (extends EXTRA_MSGMERGE and EXTRA_MSGMERGE)" off) +option(PO_REPLACE "[DEV] Install updated POT/PO files in source folder" off) +option(PO_REPLACE_ONCE "[DEV] Like PO_REPLACE but turns itself off after one run" off) + +if(SKIP_TRANSLATIONS) + message(STATUS "Language file processing disabled by SKIP_TRANSLATIONS option") + return() +endif() -SET(EXTRA_MSGMERGE "--quiet") +if(PO_VERBOSE) + list(APPEND EXTRA_MSGMERGE --verbose) + list(APPEND EXTRA_MSGFMT --verbose) +else() + list(APPEND EXTRA_MSGMERGE --quiet) +endif() +# +# NOTE: FindGettext.cmake exists but it's not really handy :-( +# find_program(gettext gettext) find_program(xgettext xgettext) find_program(msgmerge msgmerge) @@ -14,81 +46,106 @@ find_program(msgfmt msgfmt) set(COPYRIGHT_HOLDER "Marko Macek ") set(BUG_ADDRESS "https://github.com/bbidulock/icewm/issues") -if(gettext AND xgettext AND msgmerge AND msgfmt) - file (STRINGS "POTFILES.in" SRCS) - # grrr, for make dependency the path needs to match the perspective from the po/ directory. - # FIXME, how to simplify? Use abs.path for now - foreach(_src ${SRCS}) - LIST(APPEND SRCSABSOLUTE "${CMAKE_SOURCE_DIR}/${_src}") - endforeach() - FILE(GLOB POS "${CMAKE_CURRENT_SOURCE_DIR}/*.po") - foreach(_src ${POS}) - get_filename_component(_src "${_src}" NAME_WE) - LIST(APPEND LANGUAGES ${_src}) - endforeach() - - SET(XGETTEXT_CMD xgettext --from-code=UTF-8 -language=CXX --add-comments=TRANSLATORS: --keyword=_ --keyword=N_ -s --package-name=${PACKAGE} --copyright-holder="${COPYRIGHT_HOLDER}" --package-version="${VERSION}" --msgid-bugs-address="${BUG_ADDRESS}" ) - SET(_potFile "${CMAKE_CURRENT_SOURCE_DIR}/${PACKAGE}.pot") - - # XXX: it "escapes" spaces in arguments no matter how they are quoted. Find a workaround! - ADD_CUSTOM_COMMAND(OUTPUT stamp-potfile - COMMAND ${XGETTEXT_CMD} -o "${_potFile}" ${SRCS} - DEPENDS ${SRCSABSOLUTE} - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - COMMENT "Extracting translatable messages to ${_potFile} -- may require config restart!") - ADD_CUSTOM_TARGET(update_pot DEPENDS stamp-potfile) - message(VERBOSE "Adding update_pot target to update ${_potFile}") - - if(EXISTS ${_potFile}) - - if(SKIP_TRANSLATIONS) - message(VERBOSE "NOTE: SKIP_TRANSLATIONS is set, building i18n files is not part of the default build!") - ADD_CUSTOM_TARGET(translations) - else() - ADD_CUSTOM_TARGET(translations ALL) - endif() - - foreach(_lang ${LANGUAGES}) - SET(_tempPO "${CMAKE_CURRENT_BINARY_DIR}/${_lang}.po") - set(_srcPO "${CMAKE_CURRENT_SOURCE_DIR}/${_lang}.po") - message(VERBOSE "Generating updated ${_tempPO} from ${_srcPO}") - ADD_CUSTOM_COMMAND(OUTPUT ${_tempPO} - COMMAND msgmerge -o "${_tempPO}" ${EXTRA_MSGMERGE} -s "${_srcPO}" "${_potFile}" - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${_lang}.po" ${_potFile} - COMMENT "Updated: ${_tempPO}") - ADD_CUSTOM_TARGET(generate-${_lang}.po DEPENDS ${_tempPO}) - - if(PO_UPDATE) - set(SRC_UPDATE COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_tempPO}" "${_srcPO}") - else() - set(SRC_UPDATE ) - endif() - - SET(_tempMO "${CMAKE_CURRENT_BINARY_DIR}/${_lang}.gmo") - ADD_CUSTOM_COMMAND(OUTPUT "${_tempMO}" - COMMAND msgfmt -o ${_tempMO} ${EXTRA_MSGFMT} ${_tempPO} - ${SRC_UPDATE} - DEPENDS ${_tempPO} - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - #COMMENT "Compiled: ${_tempMO}") - ADD_CUSTOM_TARGET(generate-${_lang}.gmo DEPENDS ${_tempMO}) - install(FILES ${_tempMO} DESTINATION "${LOCDIR}/${_lang}/LC_MESSAGES/" RENAME "${PACKAGE}.mo" OPTIONAL) - add_dependencies(translations generate-${_lang}.gmo) - - # mimic the content of the installation folder, for development purposes - set(PG "${CMAKE_CURRENT_BINARY_DIR}/playground") - file(MAKE_DIRECTORY "${PG}") - file(MAKE_DIRECTORY "${PG}/${_lang}/LC_MESSAGES/") - file(CREATE_LINK ${_tempMO} "${PG}/${_lang}/LC_MESSAGES/${PACKAGE}.mo" SYMBOLIC) - - endforeach() - - endif() +if(NOT gettext OR NOT xgettext OR NOT msgmerge OR NOT msgfmt) + message(STATUS "Some of those tools not found, skipping translations! gettext, xgettext, msgmerge, msgfmt") + return() +endif() +set(_potFilePublic "${CMAKE_CURRENT_SOURCE_DIR}/${PACKAGE}.pot") +set(_potFile "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE}.pot") +set(_potFileStamp "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE}.pot.stamp") + +# NOTE: xgettext uses the -f option (and started from project dir so that +# unwanted path information is not leaked) but we also want to track the file +# dependencies, thus building the list here explicitly. +file (STRINGS "POTFILES.in" SRCS_IN) +set(SRCS) +foreach(_src ${SRCS_IN}) + cmake_path(ABSOLUTE_PATH _src BASE_DIRECTORY ${CMAKE_SOURCE_DIR} NORMALIZE) + list(APPEND SRCS ${_src}) +endforeach() + +file(GLOB POS "${CMAKE_CURRENT_SOURCE_DIR}/*.po") +foreach(_src ${POS}) + get_filename_component(_src "${_src}" NAME_WE) + # Ignore junk + if("${_src}" MATCHES "^[a-z][a-z](_[A-Z][A-Z])?$") + list(APPEND LANGUAGES ${_src}) + endif() +endforeach() + +set(XGETTEXT_CMD xgettext -f po/POTFILES.in --from-code=UTF-8 -language=CXX --add-comments=TRANSLATORS: --keyword=_ --keyword=N_ --package-name=${PACKAGE} --copyright-holder="${COPYRIGHT_HOLDER}" --package-version="${VERSION}" --msgid-bugs-address="${BUG_ADDRESS}" -o "${_potFile}" ) + +if(PO_REPLACE OR PO_REPLACE_ONCE) + set(SRC_UPDATE COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_potFile}" "${_potFilePublic}") else() - message(STATUS "Some of those tools not found, skipping translations! gettext, xgettext, msgmerge, msgfmt") + set(SRC_UPDATE ) +endif() +add_custom_command(OUTPUT "${_potFileStamp}" + DEPENDS ${SRCS} + BYPRODUCTS "${_potFile}" + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + VERBATIM + + COMMAND ${XGETTEXT_CMD} + + ${SRC_UPDATE} + + COMMAND ${CMAKE_COMMAND} -E touch "${_potFileStamp}" + + COMMENT "Extracting translatable messages") + +add_custom_target(update_pot DEPENDS "${_potFileStamp}") +#message(VERBOSE "Adding non-default update_pot target to update ${_potFile}") + +add_custom_target(translations ALL) + +foreach(_lang ${LANGUAGES}) + set(_tempPO "${CMAKE_CURRENT_BINARY_DIR}/${_lang}.po") + set(_srcPO "${CMAKE_CURRENT_SOURCE_DIR}/${_lang}.po") + message(VERBOSE "Generating updated ${_tempPO} from ${_srcPO}") + add_custom_command(OUTPUT ${_tempPO} + COMMAND msgmerge -o "${_tempPO}" ${EXTRA_MSGMERGE} -s "${_srcPO}" "${_potFile}" + #WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${_lang}.po" "${_potFile}" update_pot + #COMMENT "Updated: ${_tempPO}" + VERBATIM) + add_custom_target(generate-${_lang}.po DEPENDS ${_tempPO} ALL) + + if(PO_REPLACE OR PO_REPLACE_ONCE) + set(SRC_UPDATE COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_tempPO}" "${_srcPO}") + message(STATUS "Shall replace: ${_srcPO}") + else() + set(SRC_UPDATE ) + endif() + + set(_tempMO "${CMAKE_CURRENT_BINARY_DIR}/${_lang}.gmo") + add_custom_command(OUTPUT "${_tempMO}" + COMMAND msgfmt -o ${_tempMO} ${EXTRA_MSGFMT} ${_tempPO} + ${SRC_UPDATE} + DEPENDS ${_tempPO} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + VERBATIM) + add_custom_target(generate-${_lang}.gmo DEPENDS ${_tempMO}) + add_dependencies(translations generate-${_lang}.gmo) + + # Install user products + install(FILES ${_tempMO} DESTINATION "${LOCDIR}/${_lang}/LC_MESSAGES/" RENAME "${PACKAGE}.mo" OPTIONAL) + + # mimic the content of the installation folder, for development purposes + set(PG "${CMAKE_CURRENT_BINARY_DIR}/playground") + file(MAKE_DIRECTORY "${PG}") + file(MAKE_DIRECTORY "${PG}/${_lang}/LC_MESSAGES/") + file(CREATE_LINK ${_tempMO} "${PG}/${_lang}/LC_MESSAGES/${PACKAGE}.mo" SYMBOLIC) + +endforeach() + +if(PO_REPLACE_ONCE) + unset(PO_REPLACE) + unset(PO_REPLACE_ONCE) + unset(PO_REPLACE CACHE) + unset(PO_REPLACE_ONCE CACHE) endif() -# vim: set noexpandtab:ts=2:shiftwidth=2: +# vim: ts=4 shiftwidth=4 et From 1aa5f24f6611a1004172e648161a07d962541d66 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Sat, 28 Sep 2024 11:16:56 +0200 Subject: [PATCH 40/85] Hint on requirement of SVG support --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f928273fd..669debb19 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -201,7 +201,7 @@ set(HINT_IMG_LOADERS # image configuration error check if(CONFIG_IMLIB2 OR CONFIG_GDK_PIXBUF_XLIB) if (NOT CONFIG_LIBRSVG AND NOT CONFIG_NANOSVG) - message(WARNING "Support for SVG icons was not enabled") + message(WARNING "Support for SVG icons was not enabled (requires either CONFIG_LIBRSVG or CONFIG_NANOSVG)") endif() elseif(CONFIG_XPM AND CONFIG_LIBPNG) if (NOT CONFIG_LIBJPEG) From 38552a7b377ab703d214e65c53960cd4b407685d Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Sat, 28 Sep 2024 12:26:23 +0200 Subject: [PATCH 41/85] Drop dependency on YLocale class and X11 libs Since no glib or X11 stuff is required anymore, can save a bit on loading time. Moving code (for LC_MESSAGE lang extraction) back to us. --- src/CMakeLists.txt | 15 +++++++++------ src/fdomenu.cc | 19 +++++++++++++------ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 669debb19..e02be5554 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -484,12 +484,15 @@ if(BUILD_TESTING) endif() IF(CONFIG_FDO_MENUS) - ADD_EXECUTABLE(icewm-menu-fdo${EXEEXT} fdomenu.cc ycollections.cc) - target_compile_options(icewm-menu-fdo${EXEEXT} PUBLIC ${gio_CFLAGS_OTHER} ${gio_unix_CFLAGS_OTHER}) - target_include_directories(icewm-menu-fdo${EXEEXT} PUBLIC ${gio_INCLUDE_DIRS} ${gio_unix_INCLUDE_DIRS}) - TARGET_LINK_LIBRARIES(icewm-menu-fdo${EXEEXT} ice ${x11_LDFLAGS} - ${gio_LDFLAGS} ${nls_LIBS}) - INSTALL(TARGETS icewm-menu-fdo${EXEEXT} DESTINATION ${BINDIR}) + set(_tgt icewm-menu-fdo${EXEEXT}) + ADD_EXECUTABLE(${_tgt} fdomenu.cc) + TARGET_LINK_LIBRARIES(${_tgt} ice) + # XXX: static linking or LTO make it actually slower + #target_compile_options(${_tgt} PUBLIC -flto) + #target_link_options(${_tgt} PUBLIC -flto) + #target_compile_options(${_tgt} PUBLIC -static) + #target_link_options(${_tgt} PUBLIC -static) + INSTALL(TARGETS ${_tgt} DESTINATION ${BINDIR}) ENDIF() add_executable(icewm-session${EXEEXT} icesm.cc) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index c2cf5bc3c..87d8bee2f 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -22,10 +22,8 @@ #include "base.h" #include "config.h" -// #include "sysdep.h" #include "appnames.h" #include "intl.h" -#include "ylocale.h" #include #include @@ -33,12 +31,10 @@ // does not matter, string from C++11 is enough // #include #include -#include #include #include #include #include -#include #include #include #include @@ -270,7 +266,6 @@ struct DesktopFile : public tLintRefcounted { string &GetTranslatedGenericName() { if (GenericNameLoc.empty() && !GenericName.empty()) GenericNameLoc = gettext(GenericName.c_str()); - return GenericNameLoc; } @@ -555,6 +550,18 @@ struct MenuNode { unordered_multimap fixup(); }; +const char* getCheckedExplicitLocale(bool lctype) +{ + auto loc = setlocale(lctype ? LC_CTYPE : LC_MESSAGES, NULL); + if (loc == NULL) + return NULL; + return (islower(*loc & 0xff) + && islower(loc[1] & 0xff) + && !isalpha(loc[2] & 0xff)) + ? loc + : NULL; +} + int main(int argc, char **argv) { // basic framework and environment initialization @@ -563,7 +570,7 @@ int main(int argc, char **argv) { #ifdef CONFIG_I18N setlocale(LC_ALL, ""); - auto msglang = YLocale::getCheckedExplicitLocale(false); + auto msglang = getCheckedExplicitLocale(false); right_to_left = msglang && std::any_of(rtls, rtls + ACOUNT(rtls), [&](const char *rtl) { return rtl[0] == msglang[0] && rtl[1] == msglang[1]; From 4fdb3ec42cd887ce04b5b0f2e1fcee9614b3032b Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Sat, 28 Sep 2024 12:52:54 +0200 Subject: [PATCH 42/85] Disable sync with stdio This is just a helper for strace analysis in terminal environment. Pipe operations like from icewm would already turn off the sync. --- src/fdomenu.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 87d8bee2f..9eaba9f45 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -567,6 +567,8 @@ int main(int argc, char **argv) { // basic framework and environment initialization ApplicationName = my_basename(argv[0]); + std::ios_base::sync_with_stdio(false); + #ifdef CONFIG_I18N setlocale(LC_ALL, ""); From 25f0ce8008700caafea232ec0d8aee35cc401ba2 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Sat, 28 Sep 2024 14:10:33 +0200 Subject: [PATCH 43/85] Include implicitly pulled headers directly --- src/fdomenu.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 9eaba9f45..a11282d01 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -41,6 +41,9 @@ #include #include +#include +#include + #include #include #include From 2dca4f5ea413798aeaabf243e1a9b3a8edc6d8e0 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Sat, 28 Sep 2024 15:17:47 +0200 Subject: [PATCH 44/85] Deadline option to abort XDG data reading and print what we got so far --- src/fdomenu.cc | 82 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 64 insertions(+), 18 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index a11282d01..68df36937 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -20,9 +20,9 @@ #define _GNU_SOURCE #endif +#include "appnames.h" #include "base.h" #include "config.h" -#include "appnames.h" #include "intl.h" #include @@ -31,6 +31,7 @@ // does not matter, string from C++11 is enough // #include #include +#include #include #include #include @@ -62,8 +63,6 @@ char const *ApplicationName; #endif // program options -bool add_sep_before = false; -bool add_sep_after = false; bool no_sep_others = false; bool no_sub_cats = false; bool generic_name = false; @@ -429,7 +428,7 @@ struct tLessOp4Localized { class FsScan { private: std::set> reclog; - function cb; + function cb; string sFileNameExtFilter; bool recursive; @@ -495,7 +494,8 @@ class FsScan { continue; } - cb(path + "/" + fname); + if (!cb(path + "/" + fname)) + break; } } }; @@ -508,7 +508,10 @@ static void help(bool to_stderr, int xit) { "-o, --output=FILE\tWrite the output to FILE\n" "-t, --terminal=NAME\tUse NAME for a terminal that has '-e'\n" "-s, --no-lone-app\tMove lone elements to parent menu\n" - "-S, --no-lone-hint\tLike -s but append the original submenu's " + "-S, --no-lone-hint\tLike -s but append the original submenu's\n" + "-d, --deadline-apps=N\tStop loading app information after N ms\n" + "-D, --deadline-all=N\tStop all loading and print what we got so " + "far\n" "title\n" "--seps \tPrint separators before and after contents\n" "--sep-before\tPrint separator before the contents\n" @@ -547,22 +550,21 @@ struct MenuNode { void sink_in(DesktopFilePtr df); void print(std::ostream &prt_strm); + bool empty() { return apps.empty() && submenues.empty(); } /** * Returns a temporary list of visited node references. */ unordered_multimap fixup(); }; -const char* getCheckedExplicitLocale(bool lctype) -{ +const char *getCheckedExplicitLocale(bool lctype) { auto loc = setlocale(lctype ? LC_CTYPE : LC_MESSAGES, NULL); if (loc == NULL) return NULL; - return (islower(*loc & 0xff) - && islower(loc[1] & 0xff) - && !isalpha(loc[2] & 0xff)) - ? loc - : NULL; + return (islower(*loc & 0xff) && islower(loc[1] & 0xff) && + !isalpha(loc[2] & 0xff)) + ? loc + : NULL; } int main(int argc, char **argv) { @@ -600,6 +602,15 @@ int main(int argc, char **argv) { sharedirs.push_back("/usr/local/share"), sharedirs.push_back("/usr/share"); + // option parameters + bool add_sep_before = false; + bool add_sep_after = false; + const char *opt_deadline_apps = nullptr; + const char *opt_deadline_all = nullptr; + + std::chrono::time_point deadline_apps, + deadline_all; + for (auto pArg = argv + 1; pArg < argv + argc; ++pArg) { if (is_version_switch(*pArg)) { cout << "icewm-menu-fdo " VERSION ", Copyright 2015-2024 Eduard " @@ -653,11 +664,36 @@ int main(int argc, char **argv) { flat_sep = value; else if (GetArgument(value, "t", "terminal", pArg, argv + argc)) terminal_option = value; + else if (GetArgument(value, "d", "deadline-apps", pArg, + argv + argc)) + opt_deadline_apps = value; + else if (GetArgument(value, "D", "deadline-all", pArg, argv + argc)) + opt_deadline_all = value; else // unknown option help(true, EXIT_FAILURE); } } + if (opt_deadline_all || opt_deadline_apps) { + auto a = opt_deadline_apps ? atoi(opt_deadline_apps) : 0; + auto b = opt_deadline_all ? atoi(opt_deadline_all) : 0; + if (!a && b) + a = b; + if (b && !a) + b = a; + if (a > b) + a = b; + + // also need to preload gettext (preheat the cache), otherwise the + // remaining runtime on printing becomes unpredictable + b += (strlen(gettext("Audio")) > 1234) + + (strlen(gettext("Zarathustra")) > 5678); + + auto now = std::chrono::steady_clock::now(); + deadline_apps = now + std::chrono::milliseconds(a); + deadline_all = now + std::chrono::milliseconds(b); + } + auto justLang = string(msglang ? msglang : ""); justLang = justLang.substr(0, justLang.find('.')); @@ -673,9 +709,15 @@ int main(int argc, char **argv) { auto desktop_loader = FsScan( [&](const string &fPath) { DBGMSG("reading: " << fPath); + if (opt_deadline_apps && + std::chrono::steady_clock::now() > deadline_apps) + return false; + auto df = DesktopFile::load_visible(fPath, justLang); if (df) root.sink_in(df); + + return true; }, ".desktop"); @@ -694,11 +736,13 @@ int main(int argc, char **argv) { auto dir_loader = FsScan( [&](const string &fPath) { - // XXX: Filter not working as intended, and probably pointless - // anyway because of the alternative checks, see below + if (opt_deadline_apps && + std::chrono::steady_clock::now() > deadline_all) + return false; + auto df = DesktopFile::load_visible(fPath, justLang /*, filter*/); if (!df) - return; + return true; // get all menu nodes of that name auto rng = menu_lookup.equal_range(df->Name); @@ -721,6 +765,8 @@ int main(int argc, char **argv) { it->second->deco = df; } } + + return true; }, ".directory", false); @@ -728,12 +774,12 @@ int main(int argc, char **argv) { dir_loader.scan(sdir + "/desktop-directories"); } - if (add_sep_before) + if (add_sep_before && !root.empty()) cout << "separator" << endl; root.print(cout); - if (add_sep_after) + if (add_sep_after && !root.empty()) cout << "separator" << endl; return EXIT_SUCCESS; From bca77460ce7f0dd2b38d84fadfe912821d80d3ca Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Sat, 28 Sep 2024 19:37:22 +0200 Subject: [PATCH 45/85] Refactor, reformat, fix typo --- src/fdomenu.cc | 680 ++++++++++++++++++++++++------------------------- 1 file changed, 338 insertions(+), 342 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 68df36937..c29246ab9 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -246,6 +246,43 @@ void replace_all(std::string &str, const std::string &from, } } +template struct auto_raii { + T m_p; + auto_raii(T xp) : m_p(xp) {} + ~auto_raii() { + if (m_p) + TFreeFunc(m_p); + } +}; + +const char *rtls[] = { + "ar", // arabic + "fa", // farsi + "he", // hebrew + "ps", // pashto + "sd", // sindhi + "ur", // urdu +}; + +const char *getCheckedExplicitLocale(bool lctype) { + auto loc = setlocale(lctype ? LC_CTYPE : LC_MESSAGES, NULL); + if (loc == NULL) + return NULL; + return (islower(*loc & 0xff) && islower(loc[1] & 0xff) && + !isalpha(loc[2] & 0xff)) + ? loc + : NULL; +} + +struct tLessOp4Localized { + std::locale loc; // default locale + const std::collate &coll = std::use_facet>(loc); + bool operator()(const std::string &a, const std::string &b) { + return coll.compare(a.data(), a.data() + a.size(), b.data(), + b.data() + b.size()) < 0; + } +} locStringComper; + auto line_matcher = std::regex("^\\s*(Terminal|Type|Name|GenericName|Exec|TryExec|Icon|" "Categories|NoDisplay)" @@ -258,6 +295,10 @@ struct DesktopFile : public tLintRefcounted { string Name, NameLoc, Exec, TryExec, Icon, GenericName, GenericNameLoc; vector Categories; + DesktopFile(string filePath, const string &langWanted); + + const string &GetCommand(); + /// Translate with built-in l10n if needed, and cache it string &GetTranslatedName() { if (NameLoc.empty() && !Name.empty()) @@ -271,118 +312,6 @@ struct DesktopFile : public tLintRefcounted { return GenericNameLoc; } - const string &GetCommand() { - - if (CommandMassaged) - return Exec; - - CommandMassaged = true; - - if (Terminal && terminal_command) { - Exec = string(terminal_command) + " -e " + Exec; - } - - // let's try whether the command line is toxic, expecting stuff from - // https://specifications.freedesktop.org/desktop-entry-spec/latest/exec-variables.html - if (string::npos == Exec.find('%')) - return Exec; - if (!TryExec.empty()) - return (Exec = TryExec); // copy over so we stick to it in case of - // later calls - - for (const auto &bad : {"%F", "%U", "%f", "%u"}) - replace_all(Exec, bad, ""); - replace_all(Exec, "%c", Name); - replace_all(Exec, "%i", Icon); - - return Exec; - } - - DesktopFile(string filePath, const string &langWanted) { - // cout << "filterlang: " << lang <= 2) - langWantShort[0] = langWanted[0], langWantShort[1] = langWanted[1]; - - std::ifstream dfile; - dfile.open(filePath); - string line; - std::smatch m; - bool reading = false; - - auto take_loc_best = [&langWanted, - &langWantShort](decltype(m[0]) &value, - decltype(m[0]) &langLong, - decltype(m[0]) &langShort, - string &out, string &outLoc) { - if (langWanted.size() > 3 && langLong == langWanted) { - // perfect hit always takes preference - outLoc = value; - } else if (langShort.matched && langShort == langWantShort) { - if (outLoc.empty()) - outLoc = value; - } else if (!langLong.matched) { - out = value; - } - }; - - while (dfile) { - line.clear(); - std::getline(dfile, line); - if (line.empty()) { - if (dfile.eof()) - break; - continue; - } - if (startsWithSz(line, "[Desktop ")) { - if (startsWithSz(line, "[Desktop Entry")) { - reading = true; - } else if (reading) // finished with desktop entry contents, - // exit - break; - } - if (!reading) - continue; - - std::regex_search(line, m, line_matcher); - if (m.empty()) - continue; - - // for(auto x: m) cout << x << " - "; cout << " = " << m.size() << - // endl; - - const auto &value = m[6], key = m[1], langLong = m[3], - langShort = m[4]; - // cerr << "val: " << value << ", key: " << key << ", langLong: " << - // langLong << ", langShort: " << langShort << endl; - - if (key == "Terminal") - Terminal = value.compare("true") == 0; - else if (key == "NoDisplay") - NoDisplay = value.compare("true") == 0; - else if (key == "Icon") - Icon = value; - else if (key == "Categories") - Tokenize(value, ";", Categories); - else if (key == "Exec") - Exec = value; - else if (key == "TryExec") - TryExec = value; - else if (key == "Type") { - if (value == "Application") - IsApp = true; - else if (value == "Directory") - IsApp = false; - } else if (key == "Name") - take_loc_best(value, langLong, langShort, Name, NameLoc); - else if (generic_name && key == "GenericName") - take_loc_best(value, langLong, langShort, GenericName, - GenericNameLoc); - } - } - static lint_ptr load_visible(const string &path, const string &lang) { auto ret = lint_ptr(); @@ -398,32 +327,113 @@ struct DesktopFile : public tLintRefcounted { using DesktopFilePtr = lint_ptr; -template struct auto_raii { - T m_p; - auto_raii(T xp) : m_p(xp) {} - ~auto_raii() { - if (m_p) - TFreeFunc(m_p); +const string &DesktopFile::GetCommand() { + + if (CommandMassaged) + return Exec; + + CommandMassaged = true; + + if (Terminal && terminal_command) { + Exec = string(terminal_command) + " -e " + Exec; } -}; -const char *rtls[] = { - "ar", // arabic - "fa", // farsi - "he", // hebrew - "ps", // pashto - "sd", // sindhi - "ur", // urdu -}; + // let's try whether the command line is toxic, expecting stuff from + // https://specifications.freedesktop.org/desktop-entry-spec/latest/exec-variables.html + if (string::npos == Exec.find('%')) + return Exec; + if (!TryExec.empty()) + return (Exec = TryExec); // copy over so we stick to it in case of + // later calls -struct tLessOp4Localized { - std::locale loc; // default locale - const std::collate &coll = std::use_facet>(loc); - bool operator()(const std::string &a, const std::string &b) { - return coll.compare(a.data(), a.data() + a.size(), b.data(), - b.data() + b.size()) < 0; + for (const auto &bad : {"%F", "%U", "%f", "%u"}) + replace_all(Exec, bad, ""); + replace_all(Exec, "%c", Name); + replace_all(Exec, "%i", Icon); + + return Exec; +} + +DesktopFile::DesktopFile(string filePath, const string &langWanted) { + // cout << "filterlang: " << lang < 3 && langLong == langWanted) { + // perfect hit always takes preference + outLoc = value; + } else if (langShort.matched && langShort == langWantShort) { + if (outLoc.empty()) + outLoc = value; + } else if (!langLong.matched) { + out = value; + } + }; + + while (dfile) { + line.clear(); + std::getline(dfile, line); + if (line.empty()) { + if (dfile.eof()) + break; + continue; + } + if (startsWithSz(line, "[Desktop ")) { + if (startsWithSz(line, "[Desktop Entry")) { + reading = true; + } else if (reading) // finished with desktop entry contents + break; + } + if (!reading) + continue; + + std::regex_search(line, m, line_matcher); + if (m.empty()) + continue; + + // for(auto x: m) cout << x << " - "; cout << " = " << m.size() << + // endl; + + const auto &value = m[6], key = m[1], langLong = m[3], langShort = m[4]; + // cerr << "val: " << value << ", key: " << key << ", langLong: " << + // langLong << ", langShort: " << langShort << endl; + + if (key == "Terminal") + Terminal = value.compare("true") == 0; + else if (key == "NoDisplay") + NoDisplay = value.compare("true") == 0; + else if (key == "Icon") + Icon = value; + else if (key == "Categories") + Tokenize(value, ";", Categories); + else if (key == "Exec") + Exec = value; + else if (key == "TryExec") + TryExec = value; + else if (key == "Type") { + if (value == "Application") + IsApp = true; + else if (value == "Directory") + IsApp = false; + } else if (key == "Name") { + take_loc_best(value, langLong, langShort, Name, NameLoc); + } else if (generic_name && key == "GenericName") { + take_loc_best(value, langLong, langShort, GenericName, + GenericNameLoc); + } } -} locStringComper; +} class FsScan { private: @@ -500,6 +510,199 @@ class FsScan { } }; +/** + * The own menu deco info is not part of this class. + * It's fetched on-demand with a supplied resolver function. + */ +struct MenuNode { + + map submenus; + DesktopFilePtr deco; + unordered_map apps; + + void sink_in(DesktopFilePtr df); + void print(std::ostream &prt_strm); + bool empty() { return apps.empty() && submenus.empty(); } + /** + * Returns a temporary list of visited node references. + */ + unordered_multimap fixup(); +}; + +void MenuNode::sink_in(DesktopFilePtr pDf) { + + auto add_sub_menues = [&](const t_menu_path &mp) { + MenuNode *cur = this; + + // work around the lack of reverse iterator, can be made easier in C++14 + // with std::rbegin() conversion + + if (!mp.size()) + return cur; + for (auto it = mp.end() - 1;; --it) { + auto key = (*it && **it) ? *it : "Other"; + cur = &cur->submenus[key]; + // cerr << "adding submenu: " << key << endl; + if (mp.begin() == it) + break; + } + return cur; + }; + + for (const auto &cat : pDf->Categories) { + // cerr << "where does it fit? " << cat << endl; + t_menu_path refval = {cat.c_str()}; + static auto comper = [](const t_menu_path &a, const t_menu_path &b) { + // cerr << "left: " << *a.begin() << " vs. right: " << *b.begin() << + // endl; + return strcmp(*a.begin(), *b.begin()) < 0; + }; + for (const auto &w : valid_paths) { + // cerr << "try paths: " << (uintptr_t)&w << endl; + + // ignore deeper paths, fallback to the main cats only + if (no_sub_cats && w.begin()->size() > 1) + continue; + + auto rng = std::equal_range(w.begin(), w.end(), refval, comper); + for (auto it = rng.first; it != rng.second; ++it) { + auto &tgt = *add_sub_menues(*it); + tgt.apps.emplace(pDf->Name, pDf); + } + } + } +} + +static string ICON_FOLDER("folder"); +string indent_hint(""); + +void MenuNode::print(std::ostream &prt_strm) { + // translated name to icon and submenu (sorted by translated) + map, tLessOp4Localized> sorted; + + for (auto &m : this->submenus) { + auto &name = m.first; + auto &deco = m.second.deco; + + // Special mode where we detect single elements, in which case the + // menu's apps are moved to ours and the menu is skipped from the + // printed set + if (no_only_child && m.second.apps.size() == 1 && + m.second.submenus.empty()) { + + auto &lone_app = m.second.apps.begin()->second; + auto &lone_app_key = m.second.apps.begin()->first; + + if (no_only_child_hint) { + // we smuggle this into translated name because it remains + // cached + const auto &nameLoc = deco ? deco->GetTranslatedName() : name; + auto &appNameLoc = lone_app->GetTranslatedName(); + + if (generic_name) { + auto &appGnameLoc = lone_app->GetTranslatedGenericName(); + if (nameLoc == appGnameLoc) + goto skip_origin_hint; + } + if (right_to_left) + appNameLoc = string("[") + nameLoc + "] " + appNameLoc; + else + appNameLoc += string(" [") + nameLoc + "]"; + + skip_origin_hint:; + } + + apps.emplace(lone_app_key, lone_app); + m.second.apps.clear(); + } else { + sorted[deco ? deco->GetTranslatedName() : name] = + make_pair(deco ? deco->Icon : ICON_FOLDER, &m.second); + } + } + for (auto &m : sorted) { + auto &name = m.first; + prt_strm << indent_hint << "menu \""; + if (m.second.second->deco) + prt_strm << m.second.second->deco->GetTranslatedName(); + else + prt_strm << gettext(name.c_str()); + + prt_strm << "\" " + << ((m.second.second->deco && + !m.second.second->deco->Icon.empty()) + ? m.second.second->deco->Icon + : ICON_FOLDER) + << " {\n"; + + indent_hint += "\t"; + m.second.second->print(prt_strm); + indent_hint.pop_back(); + + prt_strm << indent_hint << "}\n"; + } + + map sortedApps; + for (auto &p : this->apps) + sortedApps[p.second->GetTranslatedName()] = p.second; + + for (auto &p : sortedApps) { + auto &pi = p.second; + + prt_strm << indent_hint << "prog \""; + if (!generic_name) + prt_strm << pi->GetTranslatedName(); + else { + auto &gn = pi->GetTranslatedGenericName(); + if (gn.empty() || gn == pi->GetTranslatedName()) + prt_strm << pi->GetTranslatedName(); + else { + if (right_to_left) + prt_strm << " (" << gn << ")" << pi->GetTranslatedName(); + else + prt_strm << pi->GetTranslatedName() << " (" << gn << ")"; + } + } + + prt_strm << "\" " << pi->Icon << " " << pi->GetCommand() << "\n"; + } +} + +unordered_multimap MenuNode::fixup() { + + unordered_multimap ret; + + if (no_sep_others) + submenus.erase("Other"); + + // descend deep and then check whether the same app has been added somewhere + // in the parent nodes, then remove it there + vector checkStack; + std::function go_deeper; + go_deeper = [&](MenuNode *cur) { + checkStack.push_back(cur); + + for (auto it = cur->submenus.begin(); it != cur->submenus.end(); ++it) { + ret.insert(make_pair(it->first, &it->second)); + go_deeper(&it->second); + } + + for (auto &appIt : cur->apps) { + for (auto ancestorIt = checkStack.begin(); + ancestorIt != checkStack.end() - 1; ++ancestorIt) { + auto otherIt = (*ancestorIt)->apps.find(appIt.second->Name); + if (otherIt != (*ancestorIt)->apps.end() && + otherIt->second == appIt.second) { + (*ancestorIt)->apps.erase(otherIt); + } + } + } + + checkStack.pop_back(); + }; + go_deeper(this); + return ret; +} + static void help(bool to_stderr, int xit) { (to_stderr ? cerr : cout) << "USAGE: icewm-menu-fdo [OPTIONS] [FILENAME]\n" @@ -538,35 +741,6 @@ static void help(bool to_stderr, int xit) { exit(xit); } -/** - * The own menu deco info is not part of this class. - * It's fetched on-demand with a supplied resolver function. - */ -struct MenuNode { - - map submenues; - DesktopFilePtr deco; - unordered_map apps; - - void sink_in(DesktopFilePtr df); - void print(std::ostream &prt_strm); - bool empty() { return apps.empty() && submenues.empty(); } - /** - * Returns a temporary list of visited node references. - */ - unordered_multimap fixup(); -}; - -const char *getCheckedExplicitLocale(bool lctype) { - auto loc = setlocale(lctype ? LC_CTYPE : LC_MESSAGES, NULL); - if (loc == NULL) - return NULL; - return (islower(*loc & 0xff) && islower(loc[1] & 0xff) && - !isalpha(loc[2] & 0xff)) - ? loc - : NULL; -} - int main(int argc, char **argv) { // basic framework and environment initialization @@ -599,8 +773,7 @@ int main(int argc, char **argv) { if (sysshare && !*sysshare) Tokenize(sysshare, ":", sharedirs, true); else - sharedirs.push_back("/usr/local/share"), - sharedirs.push_back("/usr/share"); + sharedirs.push_back({"/usr/local/share", "/usr/share"}); // option parameters bool add_sep_before = false; @@ -785,181 +958,4 @@ int main(int argc, char **argv) { return EXIT_SUCCESS; } -void MenuNode::sink_in(DesktopFilePtr pDf) { - - auto add_sub_menues = [&](const t_menu_path &mp) { - MenuNode *cur = this; - - // work around the lack of reverse iterator, can be made easier in C++14 - // with std::rbegin() conversion - - if (!mp.size()) - return cur; - for (auto it = mp.end() - 1;; --it) { - auto key = (*it && **it) ? *it : "Other"; - cur = &cur->submenues[key]; - - // cerr << "adding submenu: " << key << endl; - // cur = &cur->submenues[key]; - if (mp.begin() == it) - break; - } - return cur; - }; - - for (const auto &cat : pDf->Categories) { - // cerr << "where does it fit? " << cat << endl; - t_menu_path refval = {cat.c_str()}; - static auto comper = [](const t_menu_path &a, const t_menu_path &b) { - // cerr << "left: " << *a.begin() << " vs. right: " << *b.begin() << - // endl; - return strcmp(*a.begin(), *b.begin()) < 0; - }; - for (const auto &w : valid_paths) { - // cerr << "try paths: " << (uintptr_t)&w << endl; - - // ignore deeper paths, fallback to the main cats only - if (no_sub_cats && w.begin()->size() > 1) - continue; - - auto rng = std::equal_range(w.begin(), w.end(), refval, comper); - for (auto it = rng.first; it != rng.second; ++it) { - auto &tgt = *add_sub_menues(*it); - tgt.apps.emplace(pDf->Name, pDf); - } - } - } -} - -static string ICON_FOLDER("folder"); -string indent_hint(""); - -void MenuNode::print(std::ostream &prt_strm) { - // translated name to icon and submenu (sorted by translated) - map, tLessOp4Localized> sorted; - - for (auto &m : this->submenues) { - auto &name = m.first; - auto &deco = m.second.deco; - - // Special mode where we detect single elements, in which case the - // menu's apps are moved to ours and the menu is skipped from the - // printed set - if (no_only_child && m.second.apps.size() == 1 && - m.second.submenues.empty()) { - - auto &lone_app = m.second.apps.begin()->second; - auto &lone_app_key = m.second.apps.begin()->first; - - if (no_only_child_hint) { - // we smuggle this into translated name because it remains - // cached - const auto &nameLoc = deco ? deco->GetTranslatedName() : name; - auto &appNameLoc = lone_app->GetTranslatedName(); - - if (generic_name) { - auto &appGnameLoc = lone_app->GetTranslatedGenericName(); - if (nameLoc == appGnameLoc) - goto skip_origin_hint; - } - if (right_to_left) - appNameLoc = string("[") + nameLoc + "] " + appNameLoc; - else - appNameLoc += string(" [") + nameLoc + "]"; - - skip_origin_hint:; - } - - apps.emplace(lone_app_key, lone_app); - m.second.apps.clear(); - } else { - sorted[deco ? deco->GetTranslatedName() : name] = - make_pair(deco ? deco->Icon : ICON_FOLDER, &m.second); - } - } - for (auto &m : sorted) { - auto &name = m.first; - prt_strm << indent_hint << "menu \""; - if (m.second.second->deco) - prt_strm << m.second.second->deco->GetTranslatedName(); - else - prt_strm << gettext(name.c_str()); - - prt_strm << "\" " - << ((m.second.second->deco && - !m.second.second->deco->Icon.empty()) - ? m.second.second->deco->Icon - : ICON_FOLDER) - << " {\n"; - - indent_hint += "\t"; - m.second.second->print(prt_strm); - indent_hint.pop_back(); - - prt_strm << indent_hint << "}\n"; - } - - map sortedApps; - for (auto &p : this->apps) - sortedApps[p.second->GetTranslatedName()] = p.second; - - for (auto &p : sortedApps) { - auto &pi = p.second; - - prt_strm << indent_hint << "prog \""; - if (!generic_name) - prt_strm << pi->GetTranslatedName(); - else { - auto &gn = pi->GetTranslatedGenericName(); - if (gn.empty() || gn == pi->GetTranslatedName()) - prt_strm << pi->GetTranslatedName(); - else { - if (right_to_left) - prt_strm << " (" << gn << ")" << pi->GetTranslatedName(); - else - prt_strm << pi->GetTranslatedName() << " (" << gn << ")"; - } - } - - prt_strm << "\" " << pi->Icon << " " << pi->GetCommand() << "\n"; - } -} - -unordered_multimap MenuNode::fixup() { - - unordered_multimap ret; - - if (no_sep_others) - submenues.erase("Other"); - - // descend deep and then check whether the same app has been added somewhere - // in the parent nodes, then remove it there - vector checkStack; - std::function go_deeper; - go_deeper = [&](MenuNode *cur) { - checkStack.push_back(cur); - - for (auto it = cur->submenues.begin(); it != cur->submenues.end(); - ++it) { - ret.insert(make_pair(it->first, &it->second)); - go_deeper(&it->second); - } - - for (auto &appIt : cur->apps) { - for (auto ancestorIt = checkStack.begin(); - ancestorIt != checkStack.end() - 1; ++ancestorIt) { - auto otherIt = (*ancestorIt)->apps.find(appIt.second->Name); - if (otherIt != (*ancestorIt)->apps.end() && - otherIt->second == appIt.second) { - (*ancestorIt)->apps.erase(otherIt); - } - } - } - - checkStack.pop_back(); - }; - go_deeper(this); - return ret; -} - // vim: set sw=4 ts=4 et: From 8bdb27943e958b558f2ec0ffb074bffe8b855f38 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Sun, 29 Sep 2024 10:23:17 +0200 Subject: [PATCH 46/85] Better fix for duplicated appendixes Actually redesign the way how they are added, now avoids any mixture which looks like duplicate. To compensate extra memory expense, changed key handling in temporary maps to access (reliable) memory by pointer. --- src/fdomenu.cc | 155 ++++++++++++++++++++++++++++++------------------- 1 file changed, 95 insertions(+), 60 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index c29246ab9..3680c1e55 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -96,6 +97,32 @@ char *terminal_option; 0 == (where).compare((where).size() - (sizeof((what)) - 1), \ (sizeof((what)) - 1), (what))) +/** + * Container helpers and adaptors + */ + +struct tLessOp4Localized { + std::locale loc; // default locale + const std::collate &coll = std::use_facet>(loc); + bool operator()(const std::string &a, const std::string &b) { + return coll.compare(a.data(), a.data() + a.size(), b.data(), + b.data() + b.size()) < 0; + } +}; + +struct tLessOp4LocalizedDeref { + std::locale loc; // default locale + const std::collate &coll = std::use_facet>(loc); + bool operator()(const std::string *a, const std::string *b) { + return coll.compare(a->data(), a->data() + a->size(), b->data(), + b->data() + b->size()) < 0; + } +}; + +template struct lessByDerefAdaptor { + bool operator()(const T *a, const T *b) { return *a < *b; } +}; + /** * Basic base implementation of a reference-counted class */ @@ -274,15 +301,6 @@ const char *getCheckedExplicitLocale(bool lctype) { : NULL; } -struct tLessOp4Localized { - std::locale loc; // default locale - const std::collate &coll = std::use_facet>(loc); - bool operator()(const std::string &a, const std::string &b) { - return coll.compare(a.data(), a.data() + a.size(), b.data(), - b.data() + b.size()) < 0; - } -} locStringComper; - auto line_matcher = std::regex("^\\s*(Terminal|Type|Name|GenericName|Exec|TryExec|Icon|" "Categories|NoDisplay)" @@ -292,21 +310,29 @@ auto line_matcher = struct DesktopFile : public tLintRefcounted { bool Terminal = false, IsApp = true, NoDisplay = false, CommandMassaged = false; - string Name, NameLoc, Exec, TryExec, Icon, GenericName, GenericNameLoc; + + private: + string Name, Exec, TryExec; + string NameLoc, GenericName, GenericNameLoc; + + public: + string Icon; vector Categories; DesktopFile(string filePath, const string &langWanted); const string &GetCommand(); + const string &GetName() { return Name; } + const string *GetNamePtr() { return &Name; } /// Translate with built-in l10n if needed, and cache it - string &GetTranslatedName() { + const string &GetTranslatedName() { if (NameLoc.empty() && !Name.empty()) NameLoc = gettext(Name.c_str()); return NameLoc; } - string &GetTranslatedGenericName() { + const string &GetTranslatedGenericName() { if (GenericNameLoc.empty() && !GenericName.empty()) GenericNameLoc = gettext(GenericName.c_str()); return GenericNameLoc; @@ -510,6 +536,36 @@ class FsScan { } }; +struct AppEntry { + DesktopFilePtr deco; + struct tSfx { + char before, after; + string sfx; + }; + list extraSfx; + void AddSfx(const string &sfx, const char *deco) { + for (const auto &s : extraSfx) + if (s.sfx == sfx) + return; + extraSfx.emplace_back(tSfx{deco[0], deco[1], sfx}); + } + void PrintWithSfx(ostream &strm, const string &sTitle) { + if (extraSfx.empty()) { + strm << sTitle; + return; + } + if (right_to_left) { + for (auto rit = extraSfx.rbegin(); rit != extraSfx.rend(); ++rit) + strm << rit->before << rit->sfx << rit->after << " "; + strm << sTitle; + } else { + strm << sTitle; + for (const auto &p : extraSfx) + strm << " " << p.before << p.sfx << p.after; + } + } +}; + /** * The own menu deco info is not part of this class. * It's fetched on-demand with a supplied resolver function. @@ -518,7 +574,7 @@ struct MenuNode { map submenus; DesktopFilePtr deco; - unordered_map apps; + map> apps; void sink_in(DesktopFilePtr df); void print(std::ostream &prt_strm); @@ -567,7 +623,7 @@ void MenuNode::sink_in(DesktopFilePtr pDf) { auto rng = std::equal_range(w.begin(), w.end(), refval, comper); for (auto it = rng.first; it != rng.second; ++it) { auto &tgt = *add_sub_menues(*it); - tgt.apps.emplace(pDf->Name, pDf); + tgt.apps.emplace(pDf->GetNamePtr(), AppEntry{pDf}); } } } @@ -577,12 +633,13 @@ static string ICON_FOLDER("folder"); string indent_hint(""); void MenuNode::print(std::ostream &prt_strm) { - // translated name to icon and submenu (sorted by translated) + // translated name to icon and submenu (sorted by translated name) map, tLessOp4Localized> sorted; for (auto &m : this->submenus) { auto &name = m.first; - auto &deco = m.second.deco; + auto &menu = m.second; + auto &menuDeco = menu.deco; // Special mode where we detect single elements, in which case the // menu's apps are moved to ours and the menu is skipped from the @@ -590,33 +647,18 @@ void MenuNode::print(std::ostream &prt_strm) { if (no_only_child && m.second.apps.size() == 1 && m.second.submenus.empty()) { - auto &lone_app = m.second.apps.begin()->second; + auto &lone_app_entry = m.second.apps.begin()->second; auto &lone_app_key = m.second.apps.begin()->first; - if (no_only_child_hint) { - // we smuggle this into translated name because it remains - // cached - const auto &nameLoc = deco ? deco->GetTranslatedName() : name; - auto &appNameLoc = lone_app->GetTranslatedName(); - - if (generic_name) { - auto &appGnameLoc = lone_app->GetTranslatedGenericName(); - if (nameLoc == appGnameLoc) - goto skip_origin_hint; - } - if (right_to_left) - appNameLoc = string("[") + nameLoc + "] " + appNameLoc; - else - appNameLoc += string(" [") + nameLoc + "]"; - - skip_origin_hint:; - } + if (no_only_child_hint) + lone_app_entry.AddSfx( + menuDeco ? menuDeco->GetTranslatedName() : name, "[]"); - apps.emplace(lone_app_key, lone_app); + apps.emplace(lone_app_key, move(lone_app_entry)); m.second.apps.clear(); } else { - sorted[deco ? deco->GetTranslatedName() : name] = - make_pair(deco ? deco->Icon : ICON_FOLDER, &m.second); + sorted[menuDeco ? menuDeco->GetTranslatedName() : name] = + make_pair(menuDeco ? menuDeco->Icon : ICON_FOLDER, &m.second); } } for (auto &m : sorted) { @@ -641,28 +683,17 @@ void MenuNode::print(std::ostream &prt_strm) { prt_strm << indent_hint << "}\n"; } - map sortedApps; + map sortedApps; for (auto &p : this->apps) - sortedApps[p.second->GetTranslatedName()] = p.second; + sortedApps[&(p.second.deco->GetTranslatedName())] = p.second; for (auto &p : sortedApps) { - auto &pi = p.second; + auto &pi = p.second.deco; prt_strm << indent_hint << "prog \""; - if (!generic_name) - prt_strm << pi->GetTranslatedName(); - else { - auto &gn = pi->GetTranslatedGenericName(); - if (gn.empty() || gn == pi->GetTranslatedName()) - prt_strm << pi->GetTranslatedName(); - else { - if (right_to_left) - prt_strm << " (" << gn << ")" << pi->GetTranslatedName(); - else - prt_strm << pi->GetTranslatedName() << " (" << gn << ")"; - } - } - + if (generic_name) + p.second.AddSfx(pi->GetTranslatedGenericName(), "()"); + p.second.PrintWithSfx(prt_strm, pi->GetTranslatedName()); prt_strm << "\" " << pi->Icon << " " << pi->GetCommand() << "\n"; } } @@ -687,12 +718,16 @@ unordered_multimap MenuNode::fixup() { } for (auto &appIt : cur->apps) { + // delete dupes in the parent menu nodes (compare by deco identity) for (auto ancestorIt = checkStack.begin(); ancestorIt != checkStack.end() - 1; ++ancestorIt) { - auto otherIt = (*ancestorIt)->apps.find(appIt.second->Name); - if (otherIt != (*ancestorIt)->apps.end() && - otherIt->second == appIt.second) { - (*ancestorIt)->apps.erase(otherIt); + + for (auto it = (**ancestorIt).apps.begin(); + it != (**ancestorIt).apps.end(); it++) { + if (it->second.deco == appIt.second.deco) { + (**ancestorIt).apps.erase(it); + break; + } } } } @@ -918,7 +953,7 @@ int main(int argc, char **argv) { return true; // get all menu nodes of that name - auto rng = menu_lookup.equal_range(df->Name); + auto rng = menu_lookup.equal_range(df->GetName()); for (auto it = rng.first; it != rng.second; ++it) { if (!it->second->deco) it->second->deco = df; From fec50af9b96e89a7b726315ece28c8325bb28ebf Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Sun, 29 Sep 2024 10:49:02 +0200 Subject: [PATCH 47/85] Bugfixes, cleanup --- src/fdomenu.cc | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 3680c1e55..53edcb569 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -26,7 +26,6 @@ #include "intl.h" #include -#include #include // does not matter, string from C++11 is enough // #include @@ -486,7 +485,6 @@ class FsScan { auto_raii dircloser(pdir); auto fddir(dirfd(pdir)); - // const gchar *szFilename(nullptr); dirent *pent; struct stat stbuf; @@ -496,14 +494,21 @@ class FsScan { string fname(pent->d_name); +#if __linux__ // Take the shortcuts where possible, no need to analyze directory // properties for descending if that's known to be a plain file // already. if (pent->d_type == DT_REG) goto process_reg_file; - if (recursive && pent->d_type == DT_DIR) + // Don't have device id here, OTOH hitting another folder on another + // drive with exactly the same inode is very very unlikely! + if (recursive && pent->d_type == DT_DIR) { + stbuf.st_ino = pent->d_ino; + stbuf.st_dev = 0; goto process_dir; + } +#endif if (fstatat(fddir, pent->d_name, &stbuf, 0)) continue; @@ -543,6 +548,15 @@ struct AppEntry { string sfx; }; list extraSfx; + + AppEntry(DesktopFilePtr a, list b = list()) + : deco(a), extraSfx(b) {} + + AppEntry(const AppEntry &orig) : deco(orig.deco), extraSfx(orig.extraSfx) {} + + AppEntry(AppEntry &&orig) + : deco(orig.deco), extraSfx(move(orig.extraSfx)) {} + void AddSfx(const string &sfx, const char *deco) { for (const auto &s : extraSfx) if (s.sfx == sfx) @@ -643,7 +657,8 @@ void MenuNode::print(std::ostream &prt_strm) { // Special mode where we detect single elements, in which case the // menu's apps are moved to ours and the menu is skipped from the - // printed set + // printed set. + if (no_only_child && m.second.apps.size() == 1 && m.second.submenus.empty()) { @@ -807,9 +822,10 @@ int main(int argc, char **argv) { auto sysshare = getenv("XDG_DATA_DIRS"); if (sysshare && !*sysshare) Tokenize(sysshare, ":", sharedirs, true); - else - sharedirs.push_back({"/usr/local/share", "/usr/share"}); - + else { + sharedirs.push_back("/usr/local/share"); + sharedirs.push_back("/usr/share"); + } // option parameters bool add_sep_before = false; bool add_sep_after = false; From 97cd26c56282c18939f6a24bc0a2be5c1299d027 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Sun, 29 Sep 2024 13:41:42 +0200 Subject: [PATCH 48/85] More sophisticated -S operation, also fixes, cleanup --- src/fdomenu.cc | 103 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 77 insertions(+), 26 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 53edcb569..a7cb61698 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -597,6 +597,9 @@ struct MenuNode { * Returns a temporary list of visited node references. */ unordered_multimap fixup(); + + // Second run, contains all deco information now + void fixup2(); }; void MenuNode::sink_in(DesktopFilePtr pDf) { @@ -637,7 +640,7 @@ void MenuNode::sink_in(DesktopFilePtr pDf) { auto rng = std::equal_range(w.begin(), w.end(), refval, comper); for (auto it = rng.first; it != rng.second; ++it) { auto &tgt = *add_sub_menues(*it); - tgt.apps.emplace(pDf->GetNamePtr(), AppEntry{pDf}); + tgt.apps.emplace(pDf->GetNamePtr(), AppEntry(pDf)); } } } @@ -655,26 +658,8 @@ void MenuNode::print(std::ostream &prt_strm) { auto &menu = m.second; auto &menuDeco = menu.deco; - // Special mode where we detect single elements, in which case the - // menu's apps are moved to ours and the menu is skipped from the - // printed set. - - if (no_only_child && m.second.apps.size() == 1 && - m.second.submenus.empty()) { - - auto &lone_app_entry = m.second.apps.begin()->second; - auto &lone_app_key = m.second.apps.begin()->first; - - if (no_only_child_hint) - lone_app_entry.AddSfx( - menuDeco ? menuDeco->GetTranslatedName() : name, "[]"); - - apps.emplace(lone_app_key, move(lone_app_entry)); - m.second.apps.clear(); - } else { - sorted[menuDeco ? menuDeco->GetTranslatedName() : name] = - make_pair(menuDeco ? menuDeco->Icon : ICON_FOLDER, &m.second); - } + sorted[menuDeco ? menuDeco->GetTranslatedName() : name] = + make_pair(menuDeco ? menuDeco->Icon : ICON_FOLDER, &m.second); } for (auto &m : sorted) { auto &name = m.first; @@ -698,17 +683,17 @@ void MenuNode::print(std::ostream &prt_strm) { prt_strm << indent_hint << "}\n"; } - map sortedApps; + map sortedApps; for (auto &p : this->apps) - sortedApps[&(p.second.deco->GetTranslatedName())] = p.second; + sortedApps[&(p.second.deco->GetTranslatedName())] = &p.second; for (auto &p : sortedApps) { - auto &pi = p.second.deco; + auto &pi = p.second->deco; prt_strm << indent_hint << "prog \""; if (generic_name) - p.second.AddSfx(pi->GetTranslatedGenericName(), "()"); - p.second.PrintWithSfx(prt_strm, pi->GetTranslatedName()); + p.second->AddSfx(pi->GetTranslatedGenericName(), "()"); + p.second->PrintWithSfx(prt_strm, pi->GetTranslatedName()); prt_strm << "\" " << pi->Icon << " " << pi->GetCommand() << "\n"; } } @@ -753,6 +738,70 @@ unordered_multimap MenuNode::fixup() { return ret; } +void MenuNode::fixup2() { + using t_iter = decltype(submenus)::iterator; + + // the only operation applied here for now + if (!no_only_child) + return; + + // Do a depth-first-scan + vector mpath; + std::function descend; + + // subcalls may modify ancenstor's app but not submenus. Menu operation can + // get last node erased by returning false. + descend = [&](const string &menu_key, MenuNode &node) -> bool { + for (auto it = node.submenus.begin(); it != node.submenus.end();) { + mpath.push_back(it); + it = + descend(it->first, it->second) ? ++it : node.submenus.erase(it); + mpath.pop_back(); + } + + // Special mode where we detect single elements, in which case the + // menu's apps are moved to ours and the menu is skipped from the + // printed set. + + if (mpath.size() > 1) { + auto &parent_apps = mpath[mpath.size() - 2]->second.apps; + + auto relocate = [&](const string *app_key, AppEntry &app_entry) { + // if there is another one with the same key -> hands off! + if (parent_apps.find(app_key) != parent_apps.end()) + return false; + + if (no_only_child_hint) + app_entry.AddSfx(node.deco ? node.deco->GetTranslatedName() + : gettext(menu_key.c_str()), + "[]"); + parent_apps.emplace(app_key, move(app_entry)); + + return true; + }; + if (node.submenus.empty() && node.apps.size() == 1 && + mpath.size() > 1) { + + if (relocate(node.apps.begin()->first, + node.apps.begin()->second)) + node.apps.clear(); + } + // only one sub-menu which contains only applications + if (node.apps.empty() && node.submenus.size() == 1 && + node.submenus.begin()->second.submenus.empty()) { + bool some_remained = false; + for (auto &it : node.submenus.begin()->second.apps) + if (!relocate(it.first, it.second)) + some_remained = true; + if (!some_remained) + node.submenus.clear(); + } + } + return !node.empty(); + }; + descend("", *this); +} + static void help(bool to_stderr, int xit) { (to_stderr ? cerr : cout) << "USAGE: icewm-menu-fdo [OPTIONS] [FILENAME]\n" @@ -1001,6 +1050,8 @@ int main(int argc, char **argv) { if (add_sep_before && !root.empty()) cout << "separator" << endl; + root.fixup2(); + root.print(cout); if (add_sep_after && !root.empty()) From c1e1ba783ed40303b6377d1b06bf429bfb265ded Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Sun, 29 Sep 2024 14:21:34 +0200 Subject: [PATCH 49/85] Restore .desktop launching function Even if not used as callback anymore, some users might depend on it. --- src/fdomenu.cc | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index a7cb61698..1ed5dcadf 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -49,6 +49,7 @@ #include #include #include +#include using namespace std; @@ -884,6 +885,8 @@ int main(int argc, char **argv) { std::chrono::time_point deadline_apps, deadline_all; + string desktop_file_to_start; + for (auto pArg = argv + 1; pArg < argv + argc; ++pArg) { if (is_version_switch(*pArg)) { cout << "icewm-menu-fdo " VERSION ", Copyright 2015-2024 Eduard " @@ -942,11 +945,32 @@ int main(int argc, char **argv) { opt_deadline_apps = value; else if (GetArgument(value, "D", "deadline-all", pArg, argv + argc)) opt_deadline_all = value; - else // unknown option - help(true, EXIT_FAILURE); + else { + if (argc == 2 && !(desktop_file_to_start = argv[1]).empty() && + endsWithSzAr(desktop_file_to_start, ".desktop")) { + // cerr << "shall invoke: " << desktop_file_to_start << + // endl; + } else // unknown option + help(true, EXIT_FAILURE); + } } } + const char *terminals[] = {terminal_option, getenv("TERMINAL"), TERM, + "urxvt", "alacritty", "roxterm", + "xterm"}; + for (auto term : terminals) + if (term && (terminal_command = path_lookup(term)) != nullptr) + break; + + if (!desktop_file_to_start.empty()) { + DesktopFile df(argv[1], ""); + auto cmd = df.GetCommand(); + if (cmd.empty()) + return EXIT_FAILURE; + return system(cmd.c_str()); + } + if (opt_deadline_all || opt_deadline_apps) { auto a = opt_deadline_apps ? atoi(opt_deadline_apps) : 0; auto b = opt_deadline_all ? atoi(opt_deadline_all) : 0; @@ -970,13 +994,6 @@ int main(int argc, char **argv) { auto justLang = string(msglang ? msglang : ""); justLang = justLang.substr(0, justLang.find('.')); - const char *terminals[] = {terminal_option, getenv("TERMINAL"), TERM, - "urxvt", "alacritty", "roxterm", - "xterm"}; - for (auto term : terminals) - if (term && (terminal_command = path_lookup(term)) != nullptr) - break; - MenuNode root; auto desktop_loader = FsScan( From 47a05a2d3f0ffd5a8088871beeaa1bbfdcf28320 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Sun, 29 Sep 2024 16:14:34 +0200 Subject: [PATCH 50/85] Simple string matching filter implemented --- src/fdomenu.cc | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 1ed5dcadf..471dc83f6 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -301,6 +301,19 @@ const char *getCheckedExplicitLocale(bool lctype) { : NULL; } +bool userFilter(const char *s, bool isSection) { + if (match_in_section_only && !isSection) + return true; + if ((!match_in_section && !match_in_section_only) && isSection) + return true; + + if (*substr_filter_nocase) + return strcasestr(s, substr_filter_nocase); + if (*substr_filter) + return strstr(s, substr_filter); + return true; +} + auto line_matcher = std::regex("^\\s*(Terminal|Type|Name|GenericName|Exec|TryExec|Icon|" "Categories|NoDisplay)" @@ -343,7 +356,8 @@ struct DesktopFile : public tLintRefcounted { auto ret = lint_ptr(); try { ret.reset(new DesktopFile(path, lang)); - if (ret->NoDisplay) + if (ret->NoDisplay || !userFilter(ret->Name.c_str(), false) || + !userFilter(ret->GetTranslatedName().c_str(), false)) ret.reset(); } catch (const std::exception &) { } @@ -640,6 +654,13 @@ void MenuNode::sink_in(DesktopFilePtr pDf) { auto rng = std::equal_range(w.begin(), w.end(), refval, comper); for (auto it = rng.first; it != rng.second; ++it) { + if ((*substr_filter || *substr_filter_nocase) && + any_of(it->begin(), it->end(), [](const char *s) { + return !userFilter(s, true); + })) { + break; + } + auto &tgt = *add_sub_menues(*it); tgt.apps.emplace(pDf->GetNamePtr(), AppEntry(pDf)); } From 495c8ead505b9f531669b875453a8ad9945a425f Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Sun, 29 Sep 2024 16:37:58 +0200 Subject: [PATCH 51/85] Icon donation from AudioVideo section to Audio / Video --- src/fdomenu.cc | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 471dc83f6..a28270aeb 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -333,6 +333,9 @@ struct DesktopFile : public tLintRefcounted { vector Categories; DesktopFile(string filePath, const string &langWanted); + DesktopFile(const string &_name, const string &_nameLoc, + const string &_icon) + : Name(_name), NameLoc(_nameLoc), Icon(_icon) {} const string &GetCommand(); const string &GetName() { return Name; } @@ -763,7 +766,18 @@ unordered_multimap MenuNode::fixup() { void MenuNode::fixup2() { using t_iter = decltype(submenus)::iterator; - // the only operation applied here for now + auto vit = submenus.find("AudioVideo"); + if (vit != submenus.end()) { + for (auto &s : {"Audio", "Video"}) { + auto donor = vit->second.deco; + auto it = submenus.find(s); + if (it != submenus.end() && !it->second.deco) + it->second.deco.reset( + new DesktopFile(it->first, "", donor->Icon)); + } + } + + // the only operation applied in the following if (!no_only_child) return; From 7bdd4139e007e9eb336d438f236118d2cadde15f Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Mon, 30 Sep 2024 08:55:39 +0200 Subject: [PATCH 52/85] Reimplemented --flat mode --- src/fdomenu.cc | 124 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 88 insertions(+), 36 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index a28270aeb..1a2b97d8b 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -76,10 +76,21 @@ bool no_only_child_hint = false; auto substr_filter = ""; auto substr_filter_nocase = ""; + +// use a more visually appealing default with TTF fonts +#ifdef CONFIG_COREFONTS auto flat_sep = " / "; +#else +auto flat_sep = " • "; +#endif + char *terminal_command; char *terminal_option; +// global defaults +static string ICON_FOLDER("folder"); +string indent_hint(""); + /* * Certain parts borrowed from apt-cacher-ng by its autor, either from older * branches (C++11 compatible) or development branch. @@ -576,6 +587,8 @@ struct AppEntry { : deco(orig.deco), extraSfx(move(orig.extraSfx)) {} void AddSfx(const string &sfx, const char *deco) { + if (sfx.empty()) + return; for (const auto &s : extraSfx) if (s.sfx == sfx) return; @@ -610,6 +623,7 @@ struct MenuNode { void sink_in(DesktopFilePtr df); void print(std::ostream &prt_strm); + void print_flat(std::ostream &prt_strm, const string &pfx_before); bool empty() { return apps.empty() && submenus.empty(); } /** * Returns a temporary list of visited node references. @@ -618,6 +632,32 @@ struct MenuNode { // Second run, contains all deco information now void fixup2(); + + private: + using t_sorted_menus = + map, tLessOp4Localized>; + t_sorted_menus GetSortedMenus() { + t_sorted_menus ret; + + for (auto &m : this->submenus) { + auto &menuDeco = m.second.deco; + auto &name = menuDeco ? menuDeco->GetTranslatedName() + : gettext(m.first.c_str()); + ret[name] = + make_pair(menuDeco ? menuDeco->Icon : ICON_FOLDER, &m.second); + } + return ret; + } + + using t_sorted_apps = + map; + t_sorted_apps GetSortedApps() { + t_sorted_apps sortedApps; + for (auto &p : this->apps) { + sortedApps[&(p.second.deco->GetTranslatedName())] = &p.second; + } + return sortedApps; + } }; void MenuNode::sink_in(DesktopFilePtr pDf) { @@ -671,34 +711,17 @@ void MenuNode::sink_in(DesktopFilePtr pDf) { } } -static string ICON_FOLDER("folder"); -string indent_hint(""); - void MenuNode::print(std::ostream &prt_strm) { // translated name to icon and submenu (sorted by translated name) - map, tLessOp4Localized> sorted; - - for (auto &m : this->submenus) { - auto &name = m.first; - auto &menu = m.second; - auto &menuDeco = menu.deco; - - sorted[menuDeco ? menuDeco->GetTranslatedName() : name] = - make_pair(menuDeco ? menuDeco->Icon : ICON_FOLDER, &m.second); - } + auto sorted = GetSortedMenus(); for (auto &m : sorted) { auto &name = m.first; - prt_strm << indent_hint << "menu \""; - if (m.second.second->deco) - prt_strm << m.second.second->deco->GetTranslatedName(); - else - prt_strm << gettext(name.c_str()); - - prt_strm << "\" " - << ((m.second.second->deco && - !m.second.second->deco->Icon.empty()) - ? m.second.second->deco->Icon - : ICON_FOLDER) + auto &deco = m.second.second->deco; + + prt_strm << indent_hint << "menu \"" + << (deco ? deco->GetTranslatedName() : gettext(name.c_str())) + << "\" " + << ((deco && !deco->Icon.empty()) ? deco->Icon : ICON_FOLDER) << " {\n"; indent_hint += "\t"; @@ -708,17 +731,39 @@ void MenuNode::print(std::ostream &prt_strm) { prt_strm << indent_hint << "}\n"; } - map sortedApps; - for (auto &p : this->apps) - sortedApps[&(p.second.deco->GetTranslatedName())] = &p.second; - + auto sortedApps = GetSortedApps(); for (auto &p : sortedApps) { auto &pi = p.second->deco; - prt_strm << indent_hint << "prog \""; + p.second->PrintWithSfx(prt_strm, pi->GetTranslatedName()); + prt_strm << "\" " << pi->Icon << " " << pi->GetCommand() << "\n"; + } +} + +void MenuNode::print_flat(std::ostream &prt_strm, const string &pfx_before) { + auto sorted = GetSortedMenus(); + for (auto &m : sorted) { + auto &name = m.first; + auto &deco = m.second.second->deco; + auto nam = (deco ? deco->GetTranslatedName() : gettext(name.c_str())); + auto pfx = right_to_left ? (string(flat_sep) + nam + pfx_before) + : (pfx_before + nam + flat_sep); + m.second.second->print_flat(prt_strm, pfx); + } + + auto sortedApps = GetSortedApps(); + for (auto &p : sortedApps) { + auto &pi = p.second->deco; if (generic_name) p.second->AddSfx(pi->GetTranslatedGenericName(), "()"); - p.second->PrintWithSfx(prt_strm, pi->GetTranslatedName()); + prt_strm << "prog \""; + if (right_to_left) { + p.second->PrintWithSfx(prt_strm, pi->GetTranslatedName()); + prt_strm << pfx_before; + } else { + prt_strm << pfx_before; + p.second->PrintWithSfx(prt_strm, pi->GetTranslatedName()); + } prt_strm << "\" " << pi->Icon << " " << pi->GetCommand() << "\n"; } } @@ -777,10 +822,6 @@ void MenuNode::fixup2() { } } - // the only operation applied in the following - if (!no_only_child) - return; - // Do a depth-first-scan vector mpath; std::function descend; @@ -795,11 +836,19 @@ void MenuNode::fixup2() { mpath.pop_back(); } + // now do content processing + if (generic_name) { + for (auto &p : node.apps) { + p.second.AddSfx(p.second.deco->GetTranslatedGenericName(), + "()"); + } + } + // Special mode where we detect single elements, in which case the // menu's apps are moved to ours and the menu is skipped from the // printed set. - if (mpath.size() > 1) { + if (no_only_child && mpath.size() > 1) { auto &parent_apps = mpath[mpath.size() - 2]->second.apps; auto relocate = [&](const string *app_key, AppEntry &app_entry) { @@ -1104,7 +1153,10 @@ int main(int argc, char **argv) { root.fixup2(); - root.print(cout); + if (flat_output) + root.print_flat(cout, ""); + else + root.print(cout); if (add_sep_after && !root.empty()) cout << "separator" << endl; From c76ece20b5cb1a22dba900d3aed54fd64c1a6c5c Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Mon, 30 Sep 2024 09:12:05 +0200 Subject: [PATCH 53/85] Fix segfault when AudioVideo did not have decoration --- src/fdomenu.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 1a2b97d8b..09c4000b2 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -812,7 +812,7 @@ void MenuNode::fixup2() { using t_iter = decltype(submenus)::iterator; auto vit = submenus.find("AudioVideo"); - if (vit != submenus.end()) { + if (vit != submenus.end() && vit->second.deco) { for (auto &s : {"Audio", "Video"}) { auto donor = vit->second.deco; auto it = submenus.find(s); From 266ad60b5559bfb80fb03d6f6a499bb907823499 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Mon, 30 Sep 2024 09:34:43 +0200 Subject: [PATCH 54/85] Relocate --match-osec check to hit translated section names too --- src/fdomenu.cc | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 09c4000b2..3521d441c 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -697,13 +697,6 @@ void MenuNode::sink_in(DesktopFilePtr pDf) { auto rng = std::equal_range(w.begin(), w.end(), refval, comper); for (auto it = rng.first; it != rng.second; ++it) { - if ((*substr_filter || *substr_filter_nocase) && - any_of(it->begin(), it->end(), [](const char *s) { - return !userFilter(s, true); - })) { - break; - } - auto &tgt = *add_sub_menues(*it); tgt.apps.emplace(pDf->GetNamePtr(), AppEntry(pDf)); } @@ -837,6 +830,7 @@ void MenuNode::fixup2() { } // now do content processing + if (generic_name) { for (auto &p : node.apps) { p.second.AddSfx(p.second.deco->GetTranslatedGenericName(), @@ -844,6 +838,13 @@ void MenuNode::fixup2() { } } + if (!(userFilter(menu_key.c_str(), true) || + (node.deco && + userFilter(node.deco->GetTranslatedName().c_str(), true)))) { + + return false; + } + // Special mode where we detect single elements, in which case the // menu's apps are moved to ours and the menu is skipped from the // printed set. @@ -1102,11 +1103,7 @@ int main(int argc, char **argv) { auto menu_lookup = root.fixup(); - /* - unordered_set filter; - for(const auto& kv: root.menu_nodes_by_name) - filter.insert(kv.first); - */ + // okay, now let's decorate the remaining menus auto dir_loader = FsScan( [&](const string &fPath) { From c6376df390fb10a84b13477e04c6f44d279fc680 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Mon, 30 Sep 2024 09:58:48 +0200 Subject: [PATCH 55/85] Added a user hint and basic precaching hack on menu timeout Also fixing wrong timeout check enabling (for all) and restored the gettext annotation on help string. --- src/fdomenu.cc | 77 ++++++++++++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 34 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 3521d441c..6a89e5911 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -890,39 +890,37 @@ void MenuNode::fixup2() { static void help(bool to_stderr, int xit) { (to_stderr ? cerr : cout) - << "USAGE: icewm-menu-fdo [OPTIONS] [FILENAME]\n" - "OPTIONS:\n" - "-g, --generic\tInclude GenericName in parentheses of progs\n" - "-o, --output=FILE\tWrite the output to FILE\n" - "-t, --terminal=NAME\tUse NAME for a terminal that has '-e'\n" - "-s, --no-lone-app\tMove lone elements to parent menu\n" - "-S, --no-lone-hint\tLike -s but append the original submenu's\n" - "-d, --deadline-apps=N\tStop loading app information after N ms\n" - "-D, --deadline-all=N\tStop all loading and print what we got so " - "far\n" - "title\n" - "--seps \tPrint separators before and after contents\n" - "--sep-before\tPrint separator before the contents\n" - "--sep-after\tPrint separator only after contents\n" - "--no-sep-others\tDon't print uncategorized apps in Other menu\n" - "--no-sub-cats\tNo additional subcategories, just one level of " - "menues\n" - "--flat\tDisplay all apps in one layer with category hints\n" - "--flat-sep STR\tCategory separator string used in flat mode " - "(default: ' / ')\n" - "--match PAT\tDisplay only apps with title containing PAT\n" - "--imatch PAT\tLike --match but ignores the letter case\n" - "--match-sec\tApply --match or --imatch to apps AND sections\n" - "--match-osec\tApply --match or --imatch only to sections\n" - "FILENAME\tAny .desktop file to launch its application Exec " - "command\n" - "This program also listens to environment variables defined by\n" - "the XDG Base Directory Specification:\n" - "XDG_DATA_HOME=" - << Elvis(getenv("XDG_DATA_HOME"), (char *)"") - << "\n" - "XDG_DATA_DIRS=" - << Elvis(getenv("XDG_DATA_DIRS"), (char *)"") << endl; + << _("USAGE: icewm-menu-fdo [OPTIONS] [FILENAME]\n" + "OPTIONS:\n" + "-g, --generic\tInclude GenericName in parentheses of progs\n" + "-o, --output=FILE\tWrite the output to FILE\n" + "-t, --terminal=NAME\tUse NAME for a terminal that has '-e'\n" + "-s, --no-lone-app\tMove lone elements to parent menu\n" + "-S, --no-lone-hint\tLike -s but append the original submenu's\n" + "-d, --deadline-apps=N\tStop loading app information after N ms\n" + "-D, --deadline-all=N\tStop all loading and print what we got so " + "far\n" + "title\n" + "--seps \tPrint separators before and after contents\n" + "--sep-before\tPrint separator before the contents\n" + "--sep-after\tPrint separator only after contents\n" + "--no-sep-others\tDon't print uncategorized apps in Other menu\n" + "--no-sub-cats\tNo additional subcategories, just one level of " + "menues\n" + "--flat\tDisplay all apps in one layer with category hints\n" + "--flat-sep STR\tCategory separator string used in flat mode " + "(default: ' / ')\n" + "--match PAT\tDisplay only apps with title containing PAT\n" + "--imatch PAT\tLike --match but ignores the letter case\n" + "--match-sec\tApply --match or --imatch to apps AND sections\n" + "--match-osec\tApply --match or --imatch only to sections\n" + "FILENAME\tAny .desktop file to launch its application Exec " + "command\n" + "This program also listens to environment variables defined by\n" + "the XDG Base Directory Specification:\n") + << "XDG_DATA_HOME=" << Elvis(getenv("XDG_DATA_HOME"), (char *)"") + << "\nXDG_DATA_DIRS=" << Elvis(getenv("XDG_DATA_DIRS"), (char *)"") + << endl; exit(xit); } @@ -1107,7 +1105,7 @@ int main(int argc, char **argv) { auto dir_loader = FsScan( [&](const string &fPath) { - if (opt_deadline_apps && + if (opt_deadline_all && std::chrono::steady_clock::now() > deadline_all) return false; @@ -1155,6 +1153,17 @@ int main(int argc, char **argv) { else root.print(cout); + if ((opt_deadline_apps && + std::chrono::steady_clock::now() > deadline_apps) || + (opt_deadline_all && std::chrono::steady_clock::now() > deadline_all)) { + cout << "prog \"" << _("System too slow, failed to load menu content!") + << "\" stop " << argv[0] + << " --match=to-be-never-matched --match-osec\n" + << "prog \"" << _("Please push HERE and retry after some seconds.") + << "\" view-refresh " << argv[0] + << " --match=to-be-never-matched --match-osec\n"; + } + if (add_sep_after && !root.empty()) cout << "separator" << endl; From bedfe981337d76bca3275bd6377b10e8b1721319 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Mon, 30 Sep 2024 10:23:27 +0200 Subject: [PATCH 56/85] Minor refactoring (DRYing) --- src/fdomenu.cc | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 6a89e5911..4ea8c95a2 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -381,6 +381,10 @@ struct DesktopFile : public tLintRefcounted { using DesktopFilePtr = lint_ptr; +inline string safeTrans(DesktopFilePtr &node, const string &altRaw) { + return node ? node->GetTranslatedName() : gettext(altRaw.c_str()); +} + const string &DesktopFile::GetCommand() { if (CommandMassaged) @@ -641,9 +645,7 @@ struct MenuNode { for (auto &m : this->submenus) { auto &menuDeco = m.second.deco; - auto &name = menuDeco ? menuDeco->GetTranslatedName() - : gettext(m.first.c_str()); - ret[name] = + ret[safeTrans(menuDeco, m.first)] = make_pair(menuDeco ? menuDeco->Icon : ICON_FOLDER, &m.second); } return ret; @@ -711,9 +713,7 @@ void MenuNode::print(std::ostream &prt_strm) { auto &name = m.first; auto &deco = m.second.second->deco; - prt_strm << indent_hint << "menu \"" - << (deco ? deco->GetTranslatedName() : gettext(name.c_str())) - << "\" " + prt_strm << indent_hint << "menu \"" << safeTrans(deco, name) << "\" " << ((deco && !deco->Icon.empty()) ? deco->Icon : ICON_FOLDER) << " {\n"; @@ -738,9 +738,9 @@ void MenuNode::print_flat(std::ostream &prt_strm, const string &pfx_before) { for (auto &m : sorted) { auto &name = m.first; auto &deco = m.second.second->deco; - auto nam = (deco ? deco->GetTranslatedName() : gettext(name.c_str())); - auto pfx = right_to_left ? (string(flat_sep) + nam + pfx_before) - : (pfx_before + nam + flat_sep); + auto pfx = right_to_left + ? (string(flat_sep) + safeTrans(deco, name) + pfx_before) + : (pfx_before + safeTrans(deco, name) + flat_sep); m.second.second->print_flat(prt_strm, pfx); } @@ -807,11 +807,11 @@ void MenuNode::fixup2() { auto vit = submenus.find("AudioVideo"); if (vit != submenus.end() && vit->second.deco) { for (auto &s : {"Audio", "Video"}) { - auto donor = vit->second.deco; auto it = submenus.find(s); - if (it != submenus.end() && !it->second.deco) + if (it != submenus.end() && !it->second.deco) { it->second.deco.reset( - new DesktopFile(it->first, "", donor->Icon)); + new DesktopFile(it->first, "", vit->second.deco->Icon)); + } } } @@ -858,9 +858,7 @@ void MenuNode::fixup2() { return false; if (no_only_child_hint) - app_entry.AddSfx(node.deco ? node.deco->GetTranslatedName() - : gettext(menu_key.c_str()), - "[]"); + app_entry.AddSfx(safeTrans(node.deco, menu_key), "[]"); parent_apps.emplace(app_key, move(app_entry)); return true; From 4990704bef2c4200712692a604d61676d7453655 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Mon, 30 Sep 2024 11:39:51 +0200 Subject: [PATCH 57/85] Minor heap usage optimization Split the Categories when it's time and not before, use a different splitter which also reduced the code size by a few KB. --- src/CMakeLists.txt | 1 + src/fdomenu.cc | 190 ++++++++++++++++++++++++++------------------- 2 files changed, 109 insertions(+), 82 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e02be5554..0b012e876 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -491,6 +491,7 @@ IF(CONFIG_FDO_MENUS) #target_compile_options(${_tgt} PUBLIC -flto) #target_link_options(${_tgt} PUBLIC -flto) #target_compile_options(${_tgt} PUBLIC -static) + #target_compile_options(${_tgt} PUBLIC -Os) #target_link_options(${_tgt} PUBLIC -static) INSTALL(TARGETS ${_tgt} DESTINATION ${BINDIR}) ENDIF() diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 4ea8c95a2..7fd37d810 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -246,30 +246,48 @@ template class lint_ptr { } }; -/*! - * \brief Simple and convenient split function, outputs resulting tokens into a - * string vector. Operates on user-provided vector, with or without purging the - * previous contents. - */ -vector &Tokenize(const string &in, const char *sep, - vector &inOutVec, bool bAppend = false, - std::string::size_type nStartOffset = 0) { - if (!bAppend) - inOutVec.clear(); - - auto pos = nStartOffset, pos2 = nStartOffset, oob = in.length(); - while (pos < oob) { - pos = in.find_first_not_of(sep, pos); - if (pos == string::npos) // no more tokens - break; - pos2 = in.find_first_of(sep, pos); - if (pos2 == string::npos) // no more terminators, EOL - pos2 = oob; - inOutVec.emplace_back(in.substr(pos, pos2 - pos)); - pos = pos2 + 1; +class tSplitWalk { + using mstring = string; + using cmstring = const string; +#define stmiss string::npos + + cmstring &s; + mutable mstring::size_type start, len, oob; + const char *m_seps; + + public: + inline tSplitWalk(cmstring &line, decltype(m_seps) separators, + unsigned begin = 0) + : s(line), start(begin), len(stmiss), oob(line.size()), + m_seps(separators) {} + inline bool Next() const { + if (len != stmiss) // not initial state, find the next position + start = start + len + 1; + + if (start >= oob) + return false; + + start = s.find_first_not_of(m_seps, start); + + if (start < oob) { + len = s.find_first_of(m_seps, start); + len = (len == stmiss) ? oob - start : len - start; + } else if (len != stmiss) // not initial state, end reached + return false; + else if (s.empty()) // initial state, no parts + return false; + else // initial state, use the whole string + { + start = 0; + len = oob; + } + + return true; } - return inOutVec; -} + inline mstring str() const { return s.substr(start, len); } + inline operator mstring() const { return str(); } + inline const char *remainder() const { return s.c_str() + start; } +}; void replace_all(std::string &str, const std::string &from, const std::string &to) { @@ -340,8 +358,7 @@ struct DesktopFile : public tLintRefcounted { string NameLoc, GenericName, GenericNameLoc; public: - string Icon; - vector Categories; + string Icon, Categories; DesktopFile(string filePath, const string &langWanted); DesktopFile(const string &_name, const string &_nameLoc, @@ -474,7 +491,7 @@ DesktopFile::DesktopFile(string filePath, const string &langWanted) { else if (key == "Icon") Icon = value; else if (key == "Categories") - Tokenize(value, ";", Categories); + Categories = value; else if (key == "Exec") Exec = value; else if (key == "TryExec") @@ -682,7 +699,9 @@ void MenuNode::sink_in(DesktopFilePtr pDf) { return cur; }; - for (const auto &cat : pDf->Categories) { + // for (const auto &cat : pDf->Categories) { + for (tSplitWalk split(pDf->Categories, ";"); split.Next();) { + auto cat = split.str(); // cerr << "where does it fit? " << cat << endl; t_menu_path refval = {cat.c_str()}; static auto comper = [](const t_menu_path &a, const t_menu_path &b) { @@ -942,18 +961,21 @@ int main(int argc, char **argv) { #endif vector sharedirs; + auto add_split = [&](const char *p) { + if (!p || !*p) + return false; + string q(p); + for (tSplitWalk w(q, ":"); w.Next();) + sharedirs.push_back(w); + return true; + }; + + // system dirs, either from environment or from static locations const char *p; - auto pUserShare = getenv("XDG_DATA_HOME"); - if (pUserShare && *pUserShare) - Tokenize(pUserShare, ":", sharedirs, true); - else if (nullptr != (p = getenv("HOME")) && *p) + if (!add_split(getenv("XDG_DATA_HOME")) && (p = getenv("HOME")) && *p) sharedirs.push_back(string(p) + "/.local/share"); - // system dirs, either from environment or from static locations - auto sysshare = getenv("XDG_DATA_DIRS"); - if (sysshare && !*sysshare) - Tokenize(sysshare, ":", sharedirs, true); - else { + if (!add_split(getenv("XDG_DATA_DIRS"))) { sharedirs.push_back("/usr/local/share"); sharedirs.push_back("/usr/share"); } @@ -1077,68 +1099,72 @@ int main(int argc, char **argv) { MenuNode root; - auto desktop_loader = FsScan( - [&](const string &fPath) { - DBGMSG("reading: " << fPath); - if (opt_deadline_apps && - std::chrono::steady_clock::now() > deadline_apps) - return false; + { + auto desktop_loader = FsScan( + [&](const string &fPath) { + DBGMSG("reading: " << fPath); + if (opt_deadline_apps && + std::chrono::steady_clock::now() > deadline_apps) + return false; - auto df = DesktopFile::load_visible(fPath, justLang); - if (df) - root.sink_in(df); + auto df = DesktopFile::load_visible(fPath, justLang); + if (df) + root.sink_in(df); - return true; - }, - ".desktop"); + return true; + }, + ".desktop"); - for (const auto &sdir : sharedirs) { - DBGMSG("checkdir: " << sdir); - desktop_loader.scan(sdir + "/applications"); + for (const auto &sdir : sharedirs) { + DBGMSG("checkdir: " << sdir); + desktop_loader.scan(sdir + "/applications"); + } } auto menu_lookup = root.fixup(); // okay, now let's decorate the remaining menus + { + auto dir_loader = FsScan( + [&](const string &fPath) { + if (opt_deadline_all && + std::chrono::steady_clock::now() > deadline_all) + return false; - auto dir_loader = FsScan( - [&](const string &fPath) { - if (opt_deadline_all && - std::chrono::steady_clock::now() > deadline_all) - return false; - - auto df = DesktopFile::load_visible(fPath, justLang /*, filter*/); - if (!df) - return true; - - // get all menu nodes of that name - auto rng = menu_lookup.equal_range(df->GetName()); - for (auto it = rng.first; it != rng.second; ++it) { - if (!it->second->deco) - it->second->deco = df; - } - // No menus of that name? Try using the plain filename, some - // .directory files use the category as file name stem but differing - // in the Name attribute - if (rng.first == rng.second) { - auto cpos = fPath.find_last_of("/"); - auto mcatName = - fPath.substr(cpos + 1, fPath.length() - cpos - 11); - rng = menu_lookup.equal_range(mcatName); - DBGMSG("altname: " << mcatName); + auto df = + DesktopFile::load_visible(fPath, justLang /*, filter*/); + if (!df) + return true; + // get all menu nodes of that name + auto rng = menu_lookup.equal_range(df->GetName()); for (auto it = rng.first; it != rng.second; ++it) { if (!it->second->deco) it->second->deco = df; } - } + // No menus of that name? Try using the plain filename, some + // .directory files use the category as file name stem but + // differing in the Name attribute + if (rng.first == rng.second) { + auto cpos = fPath.find_last_of("/"); + auto mcatName = + fPath.substr(cpos + 1, fPath.length() - cpos - 11); + rng = menu_lookup.equal_range(mcatName); + DBGMSG("altname: " << mcatName); + + for (auto it = rng.first; it != rng.second; ++it) { + if (!it->second->deco) + it->second->deco = df; + } + } - return true; - }, - ".directory", false); + return true; + }, + ".directory", false); - for (const auto &sdir : sharedirs) { - dir_loader.scan(sdir + "/desktop-directories"); + for (const auto &sdir : sharedirs) { + dir_loader.scan(sdir + "/desktop-directories"); + } } if (add_sep_before && !root.empty()) From f6089bfde94a3429d04a73e8e6cee638e1515c48 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Mon, 30 Sep 2024 11:51:24 +0200 Subject: [PATCH 58/85] Tiny runtime saving by not cleaning up the tree in the end --- src/fdomenu.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 7fd37d810..83a1410da 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -1097,7 +1097,8 @@ int main(int argc, char **argv) { auto justLang = string(msglang ? msglang : ""); justLang = justLang.substr(0, justLang.find('.')); - MenuNode root; + MenuNode *leaky = new MenuNode; + MenuNode &root = *leaky; { auto desktop_loader = FsScan( From 6a26b996084602535dcd497734f3778736d5398e Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Mon, 30 Sep 2024 12:47:47 +0200 Subject: [PATCH 59/85] Document missing options and align help text format --- src/fdomenu.cc | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 83a1410da..f02c5a115 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -909,7 +909,7 @@ static void help(bool to_stderr, int xit) { (to_stderr ? cerr : cout) << _("USAGE: icewm-menu-fdo [OPTIONS] [FILENAME]\n" "OPTIONS:\n" - "-g, --generic\tInclude GenericName in parentheses of progs\n" + "-g, --generic\t\tInclude GenericName in parentheses of progs\n" "-o, --output=FILE\tWrite the output to FILE\n" "-t, --terminal=NAME\tUse NAME for a terminal that has '-e'\n" "-s, --no-lone-app\tMove lone elements to parent menu\n" @@ -917,22 +917,24 @@ static void help(bool to_stderr, int xit) { "-d, --deadline-apps=N\tStop loading app information after N ms\n" "-D, --deadline-all=N\tStop all loading and print what we got so " "far\n" - "title\n" + "-m, --match=PAT\t\tDisplay only apps with title containing PAT\n" + "-M, --imatch=PAT\tLike --match but ignores the letter case\n" "--seps \tPrint separators before and after contents\n" "--sep-before\tPrint separator before the contents\n" "--sep-after\tPrint separator only after contents\n" "--no-sep-others\tDon't print uncategorized apps in Other menu\n" "--no-sub-cats\tNo additional subcategories, just one level of " "menues\n" - "--flat\tDisplay all apps in one layer with category hints\n" - "--flat-sep STR\tCategory separator string used in flat mode " + "--flat\t\tDisplay all apps in one layer with category hints\n" + "--flat-sep=STR\tCategory separator string used in flat mode " "(default: ' / ')\n" - "--match PAT\tDisplay only apps with title containing PAT\n" - "--imatch PAT\tLike --match but ignores the letter case\n" "--match-sec\tApply --match or --imatch to apps AND sections\n" "--match-osec\tApply --match or --imatch only to sections\n" - "FILENAME\tAny .desktop file to launch its application Exec " - "command\n" + "-C, --copying\tPrint copyright information\n" + "-V, --version\tPrint version information\n" + "-h, --help\tPrints this usage screen and exits.\n" + "\nFILENAME\tAny .desktop file to launch its application Exec " + "command.\n\n" "This program also listens to environment variables defined by\n" "the XDG Base Directory Specification:\n") << "XDG_DATA_HOME=" << Elvis(getenv("XDG_DATA_HOME"), (char *)"") From ee0a02992f527ffb0b4ae80e7d9430fca3aff000 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Mon, 30 Sep 2024 12:48:07 +0200 Subject: [PATCH 60/85] Document new options --- man/icewm-menu-fdo.pod | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/man/icewm-menu-fdo.pod b/man/icewm-menu-fdo.pod index 10a167ce6..8aa7498cb 100644 --- a/man/icewm-menu-fdo.pod +++ b/man/icewm-menu-fdo.pod @@ -66,14 +66,32 @@ Use I to start a terminal emulator that supports the '-e' option. =item B<-s>, B<--no-lone-app> Attempt to detect a single application with no other content in lower -submenus and move this one to the parent submenu. Limitations: this -looks only one level below, multiple moving is not supported yet. +submenus and move this one to the parent submenu. This also detects +menus with just one submenu inside, attempting to move it's application +items to the parent menu where possible. =item B<-S>, B<--no-lone-hint> Decorate app entries moved by the B<-s> option with a hint about the original menu where it would be displayed otherwise. Implies B<-s>. +=item B<-d TIMEOUT>, B<--deadline-apps=TIMEOUT> + +Specifies a certain timeout value in milliseconds, so that the reading +of *.desktop files (for applications) is aborted by that time (or soon +after). This can help to avoid extended blocking of the caller. +Also see B<-D> for the subsequent operation. + +=item B<-D TIMEOUT>, B<--deadline-all=TIMEOUT> + +Specifies a total timeout in milliseconds after which the application +has to terminate, regardless of the final menu construction and +decoration reading (applied after *.desktop file reading) was finished +or not. This would cause a printing of menu contents which were +calculated so far, therefore the timeout should be set a certain time +before the actual hard deadline by which the program should be +terminated. The output may lack translations and icons. + =item B<--flat> Display apps from all categories in one level with the title containing From c42cb9f3bcf15b66ef998d5dd0c24f79fa3e0889 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Mon, 30 Sep 2024 12:54:59 +0200 Subject: [PATCH 61/85] In timeout, don't waste time with nice-to-have optimizations --- src/fdomenu.cc | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index f02c5a115..412f9bf12 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -955,7 +955,8 @@ int main(int argc, char **argv) { auto msglang = getCheckedExplicitLocale(false); right_to_left = - msglang && std::any_of(rtls, rtls + ACOUNT(rtls), [&](const char *rtl) { + msglang && *msglang && + std::any_of(rtls, rtls + ACOUNT(rtls), [&](const char *rtl) { return rtl[0] == msglang[0] && rtl[1] == msglang[1]; }); bindtextdomain(PACKAGE, LOCDIR); @@ -1100,15 +1101,17 @@ int main(int argc, char **argv) { justLang = justLang.substr(0, justLang.find('.')); MenuNode *leaky = new MenuNode; - MenuNode &root = *leaky; + auto &root = *leaky; + bool in_timeout = false; { auto desktop_loader = FsScan( [&](const string &fPath) { DBGMSG("reading: " << fPath); if (opt_deadline_apps && - std::chrono::steady_clock::now() > deadline_apps) + std::chrono::steady_clock::now() > deadline_apps) { return false; + } auto df = DesktopFile::load_visible(fPath, justLang); if (df) @@ -1131,8 +1134,10 @@ int main(int argc, char **argv) { auto dir_loader = FsScan( [&](const string &fPath) { if (opt_deadline_all && - std::chrono::steady_clock::now() > deadline_all) + std::chrono::steady_clock::now() > deadline_all) { + in_timeout = true; return false; + } auto df = DesktopFile::load_visible(fPath, justLang /*, filter*/); @@ -1173,17 +1178,17 @@ int main(int argc, char **argv) { if (add_sep_before && !root.empty()) cout << "separator" << endl; - root.fixup2(); + if (!in_timeout) + root.fixup2(); if (flat_output) root.print_flat(cout, ""); else root.print(cout); - if ((opt_deadline_apps && - std::chrono::steady_clock::now() > deadline_apps) || - (opt_deadline_all && std::chrono::steady_clock::now() > deadline_all)) { - cout << "prog \"" << _("System too slow, failed to load menu content!") + if (in_timeout || (opt_deadline_apps && + std::chrono::steady_clock::now() > deadline_apps)) { + cout << "prog \"" << _("System too slow! Failed to load menu content!") << "\" stop " << argv[0] << " --match=to-be-never-matched --match-osec\n" << "prog \"" << _("Please push HERE and retry after some seconds.") From 698af1a0988d2bb2b261efd3a14dddfc3d8a00e3 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Mon, 30 Sep 2024 13:05:50 +0200 Subject: [PATCH 62/85] Disable --no-sep-others again The option is not implemented, not wanting it anyway. And should not change the meaning from what it did before to more invasive deletion of content. --- man/icewm-menu-fdo.pod | 4 ---- src/fdomenu.cc | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/man/icewm-menu-fdo.pod b/man/icewm-menu-fdo.pod index 8aa7498cb..f303fb229 100644 --- a/man/icewm-menu-fdo.pod +++ b/man/icewm-menu-fdo.pod @@ -47,10 +47,6 @@ Print a leading separator. Print a trailing separator. -=item B<--no-sep-others> - -Don't print the C category, only official categories. - =item B<--no-sub-cats> Don't nest subcategories in submenus. diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 412f9bf12..4f03cda1c 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -784,8 +784,8 @@ unordered_multimap MenuNode::fixup() { unordered_multimap ret; - if (no_sep_others) - submenus.erase("Other"); + //if (no_sep_others) + // submenus.erase("Other"); // descend deep and then check whether the same app has been added somewhere // in the parent nodes, then remove it there @@ -922,7 +922,7 @@ static void help(bool to_stderr, int xit) { "--seps \tPrint separators before and after contents\n" "--sep-before\tPrint separator before the contents\n" "--sep-after\tPrint separator only after contents\n" - "--no-sep-others\tDon't print uncategorized apps in Other menu\n" + "--no-sep-others\tLegacy, has no effect\n" "--no-sub-cats\tNo additional subcategories, just one level of " "menues\n" "--flat\t\tDisplay all apps in one layer with category hints\n" From ef3c60099cdf4813784c471b4af0f3b1076f9f2e Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Mon, 30 Sep 2024 13:07:39 +0200 Subject: [PATCH 63/85] Configured timeout defaults to "sane" values Empirically found on an old single-core-magneto-HDD laptop. Also use -S mode for more compact structure where not many applications are installed. --- lib/menu.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/menu.in b/lib/menu.in index 9ec8bbc2c..a03eaa2f1 100644 --- a/lib/menu.in +++ b/lib/menu.in @@ -10,6 +10,6 @@ prog NEdit nedit nedit prog Firefox firefox firefox prog Hexchat xchat hexchat prog Gimp gimp gimp -includeprog icewm-menu-fdo --sep-before --no-sep-others +includeprog icewm-menu-fdo --seps -d1400 -D1650 -S menufile Programs folder programs menufile Tool_bar folder toolbar From 29a0ed9c05008c1db87fb43afccb563f7844b82b Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Mon, 30 Sep 2024 16:22:38 +0200 Subject: [PATCH 64/85] Dodge the GenericName which just repeats Name content --- src/fdomenu.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 4f03cda1c..0c22a0ad8 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -622,12 +622,14 @@ struct AppEntry { } if (right_to_left) { for (auto rit = extraSfx.rbegin(); rit != extraSfx.rend(); ++rit) - strm << rit->before << rit->sfx << rit->after << " "; + if (sTitle != rit->sfx) + strm << rit->before << rit->sfx << rit->after << " "; strm << sTitle; } else { strm << sTitle; for (const auto &p : extraSfx) - strm << " " << p.before << p.sfx << p.after; + if (sTitle != p.sfx) + strm << " " << p.before << p.sfx << p.after; } } }; @@ -784,8 +786,8 @@ unordered_multimap MenuNode::fixup() { unordered_multimap ret; - //if (no_sep_others) - // submenus.erase("Other"); + // if (no_sep_others) + // submenus.erase("Other"); // descend deep and then check whether the same app has been added somewhere // in the parent nodes, then remove it there From df327c8aeca7a663a9215f35e275f5f05ee23e4f Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Mon, 30 Sep 2024 23:55:53 +0200 Subject: [PATCH 65/85] Support more OS with the d_ent shortcut Also cleaning commments, simplifying code, fixing findings from clang++. --- src/fdomenu.cc | 51 +++++++++++++++----------------------------------- 1 file changed, 15 insertions(+), 36 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 0c22a0ad8..e9e30d029 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -27,9 +27,8 @@ #include #include -// does not matter, string from C++11 is enough -// #include #include +#include // For std::move #include #include #include @@ -417,9 +416,10 @@ const string &DesktopFile::GetCommand() { // https://specifications.freedesktop.org/desktop-entry-spec/latest/exec-variables.html if (string::npos == Exec.find('%')) return Exec; + // TryExec should contain the pure command which we prefer. Copy this over + // so that we stick to it if (!TryExec.empty()) - return (Exec = TryExec); // copy over so we stick to it in case of - // later calls + return (Exec = TryExec); for (const auto &bad : {"%F", "%U", "%f", "%u"}) replace_all(Exec, bad, ""); @@ -430,10 +430,6 @@ const string &DesktopFile::GetCommand() { } DesktopFile::DesktopFile(string filePath, const string &langWanted) { - // cout << "filterlang: " << lang < 3 && langLong == langWanted) { // perfect hit always takes preference outLoc = value; - } else if (langShort.matched && langShort == langWantShort) { + } else if (langShort.matched && 0 == langWanted.compare(0, 2, langShort)) { if (outLoc.empty()) outLoc = value; } else if (!langLong.matched) { @@ -544,7 +540,8 @@ class FsScan { string fname(pent->d_name); -#if __linux__ +#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ + defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) // Take the shortcuts where possible, no need to analyze directory // properties for descending if that's known to be a plain file // already. @@ -605,7 +602,7 @@ struct AppEntry { AppEntry(const AppEntry &orig) : deco(orig.deco), extraSfx(orig.extraSfx) {} AppEntry(AppEntry &&orig) - : deco(orig.deco), extraSfx(move(orig.extraSfx)) {} + : deco(orig.deco), extraSfx(std::move(orig.extraSfx)) {} void AddSfx(const string &sfx, const char *deco) { if (sfx.empty()) @@ -685,35 +682,21 @@ void MenuNode::sink_in(DesktopFilePtr pDf) { auto add_sub_menues = [&](const t_menu_path &mp) { MenuNode *cur = this; - - // work around the lack of reverse iterator, can be made easier in C++14 - // with std::rbegin() conversion - - if (!mp.size()) - return cur; - for (auto it = mp.end() - 1;; --it) { + for (auto it = mp.end() - 1; it >= mp.begin(); --it) { auto key = (*it && **it) ? *it : "Other"; cur = &cur->submenus[key]; - // cerr << "adding submenu: " << key << endl; - if (mp.begin() == it) - break; } return cur; }; - // for (const auto &cat : pDf->Categories) { for (tSplitWalk split(pDf->Categories, ";"); split.Next();) { auto cat = split.str(); - // cerr << "where does it fit? " << cat << endl; t_menu_path refval = {cat.c_str()}; static auto comper = [](const t_menu_path &a, const t_menu_path &b) { - // cerr << "left: " << *a.begin() << " vs. right: " << *b.begin() << // endl; return strcmp(*a.begin(), *b.begin()) < 0; }; for (const auto &w : valid_paths) { - // cerr << "try paths: " << (uintptr_t)&w << endl; - // ignore deeper paths, fallback to the main cats only if (no_sub_cats && w.begin()->size() > 1) continue; @@ -786,9 +769,6 @@ unordered_multimap MenuNode::fixup() { unordered_multimap ret; - // if (no_sep_others) - // submenus.erase("Other"); - // descend deep and then check whether the same app has been added somewhere // in the parent nodes, then remove it there vector checkStack; @@ -880,7 +860,7 @@ void MenuNode::fixup2() { if (no_only_child_hint) app_entry.AddSfx(safeTrans(node.deco, menu_key), "[]"); - parent_apps.emplace(app_key, move(app_entry)); + parent_apps.emplace(app_key, std::move(app_entry)); return true; }; @@ -1056,8 +1036,7 @@ int main(int argc, char **argv) { else { if (argc == 2 && !(desktop_file_to_start = argv[1]).empty() && endsWithSzAr(desktop_file_to_start, ".desktop")) { - // cerr << "shall invoke: " << desktop_file_to_start << - // endl; + DBGMSG("shall invoke: " << desktop_file_to_start); } else // unknown option help(true, EXIT_FAILURE); } @@ -1129,7 +1108,7 @@ int main(int argc, char **argv) { } } - auto menu_lookup = root.fixup(); + auto section_entries = root.fixup(); // okay, now let's decorate the remaining menus { @@ -1147,7 +1126,7 @@ int main(int argc, char **argv) { return true; // get all menu nodes of that name - auto rng = menu_lookup.equal_range(df->GetName()); + auto rng = section_entries.equal_range(df->GetName()); for (auto it = rng.first; it != rng.second; ++it) { if (!it->second->deco) it->second->deco = df; @@ -1159,7 +1138,7 @@ int main(int argc, char **argv) { auto cpos = fPath.find_last_of("/"); auto mcatName = fPath.substr(cpos + 1, fPath.length() - cpos - 11); - rng = menu_lookup.equal_range(mcatName); + rng = section_entries.equal_range(mcatName); DBGMSG("altname: " << mcatName); for (auto it = rng.first; it != rng.second; ++it) { From 3425159bb67364f73f39d05801acb89913c51e94 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Tue, 1 Oct 2024 10:36:52 +0200 Subject: [PATCH 66/85] Optional source comment, more hidding, various fixes - no duplicated GenericName suffixes in --flat mode - move semantics on path strings - don't display apps marked with OnlyShowIn (i.e. not for us) --- src/fdomenu.cc | 94 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 57 insertions(+), 37 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index e9e30d029..e9d7ac153 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -25,11 +25,10 @@ #include "config.h" #include "intl.h" -#include -#include #include -#include // For std::move #include +#include +#include #include #include #include @@ -37,9 +36,10 @@ #include #include #include +#include #include #include -#include +#include // For std::move #include #include @@ -72,6 +72,7 @@ bool match_in_section = false; bool match_in_section_only = false; bool no_only_child = false; bool no_only_child_hint = false; +bool add_comments = false; auto substr_filter = ""; auto substr_filter_nocase = ""; @@ -86,9 +87,11 @@ auto flat_sep = " • "; char *terminal_command; char *terminal_option; -// global defaults +// global defaults and helpers static string ICON_FOLDER("folder"); string indent_hint(""); +// use this to dump optional comment data, deque is pointer-stable +deque comment_pool; /* * Certain parts borrowed from apt-cacher-ng by its autor, either from older @@ -344,7 +347,7 @@ bool userFilter(const char *s, bool isSection) { auto line_matcher = std::regex("^\\s*(Terminal|Type|Name|GenericName|Exec|TryExec|Icon|" - "Categories|NoDisplay)" + "Categories|NoDisplay|OnlyShowIn)" "(\\[((\\w\\w)(_\\w\\w)?)\\])?\\s*=\\s*(.*){0,1}?\\s*$", std::regex_constants::ECMAScript); @@ -358,6 +361,7 @@ struct DesktopFile : public tLintRefcounted { public: string Icon, Categories; + const string *comment = nullptr; DesktopFile(string filePath, const string &langWanted); DesktopFile(const string &_name, const string &_nameLoc, @@ -381,18 +385,30 @@ struct DesktopFile : public tLintRefcounted { return GenericNameLoc; } - static lint_ptr load_visible(const string &path, + static lint_ptr load_visible(string &&path, const string &lang) { auto ret = lint_ptr(); try { ret.reset(new DesktopFile(path, lang)); if (ret->NoDisplay || !userFilter(ret->Name.c_str(), false) || - !userFilter(ret->GetTranslatedName().c_str(), false)) + !userFilter(ret->GetTranslatedName().c_str(), false)) { ret.reset(); + } else { + if (add_comments) { + comment_pool.push_back(std::move(path)); + ret->comment = (&comment_pool.back()); + } + } } catch (const std::exception &) { } return ret; } + + ostream &print_comment(ostream &strm) { + if (comment) + strm << endl << indent_hint << "# " << *comment << endl; + return strm; + } }; using DesktopFilePtr = lint_ptr; @@ -437,20 +453,20 @@ DesktopFile::DesktopFile(string filePath, const string &langWanted) { std::smatch m; bool reading = false; - auto take_loc_best = [&langWanted]( - decltype(m[0]) &value, decltype(m[0]) &langLong, - decltype(m[0]) &langShort, string &out, - string &outLoc) { - if (langWanted.size() > 3 && langLong == langWanted) { - // perfect hit always takes preference - outLoc = value; - } else if (langShort.matched && 0 == langWanted.compare(0, 2, langShort)) { - if (outLoc.empty()) + auto take_loc_best = + [&langWanted](decltype(m[0]) &value, decltype(m[0]) &langLong, + decltype(m[0]) &langShort, string &out, string &outLoc) { + if (langWanted.size() > 3 && langLong == langWanted) { + // perfect hit always takes preference outLoc = value; - } else if (!langLong.matched) { - out = value; - } - }; + } else if (langShort.matched && + 0 == langWanted.compare(0, 2, langShort)) { + if (outLoc.empty()) + outLoc = value; + } else if (!langLong.matched) { + out = value; + } + }; while (dfile) { line.clear(); @@ -484,6 +500,8 @@ DesktopFile::DesktopFile(string filePath, const string &langWanted) { Terminal = value.compare("true") == 0; else if (key == "NoDisplay") NoDisplay = value.compare("true") == 0; + else if (key == "OnlyShowIn") + NoDisplay = true; else if (key == "Icon") Icon = value; else if (key == "Categories") @@ -509,7 +527,7 @@ DesktopFile::DesktopFile(string filePath, const string &langWanted) { class FsScan { private: std::set> reclog; - function cb; + function cb; string sFileNameExtFilter; bool recursive; @@ -612,10 +630,10 @@ struct AppEntry { return; extraSfx.emplace_back(tSfx{deco[0], deco[1], sfx}); } - void PrintWithSfx(ostream &strm, const string &sTitle) { + ostream &PrintWithSfx(ostream &strm, const string &sTitle) { if (extraSfx.empty()) { strm << sTitle; - return; + return strm; } if (right_to_left) { for (auto rit = extraSfx.rbegin(); rit != extraSfx.rend(); ++rit) @@ -628,6 +646,7 @@ struct AppEntry { if (sTitle != p.sfx) strm << " " << p.before << p.sfx << p.after; } + return strm; } }; @@ -731,9 +750,9 @@ void MenuNode::print(std::ostream &prt_strm) { auto sortedApps = GetSortedApps(); for (auto &p : sortedApps) { auto &pi = p.second->deco; - prt_strm << indent_hint << "prog \""; - p.second->PrintWithSfx(prt_strm, pi->GetTranslatedName()); - prt_strm << "\" " << pi->Icon << " " << pi->GetCommand() << "\n"; + pi->print_comment(prt_strm) << indent_hint << "prog \""; + p.second->PrintWithSfx(prt_strm, pi->GetTranslatedName()) + << "\" " << pi->Icon << " " << pi->GetCommand() << "\n"; } } @@ -751,12 +770,11 @@ void MenuNode::print_flat(std::ostream &prt_strm, const string &pfx_before) { auto sortedApps = GetSortedApps(); for (auto &p : sortedApps) { auto &pi = p.second->deco; - if (generic_name) - p.second->AddSfx(pi->GetTranslatedGenericName(), "()"); - prt_strm << "prog \""; + + pi->print_comment(prt_strm) << "prog \""; if (right_to_left) { - p.second->PrintWithSfx(prt_strm, pi->GetTranslatedName()); - prt_strm << pfx_before; + p.second->PrintWithSfx(prt_strm, pi->GetTranslatedName()) + << pfx_before; } else { prt_strm << pfx_before; p.second->PrintWithSfx(prt_strm, pi->GetTranslatedName()); @@ -912,6 +930,7 @@ static void help(bool to_stderr, int xit) { "(default: ' / ')\n" "--match-sec\tApply --match or --imatch to apps AND sections\n" "--match-osec\tApply --match or --imatch only to sections\n" + "--orig-comment\tPrint source .desktop file as comment\n" "-C, --copying\tPrint copyright information\n" "-V, --version\tPrint version information\n" "-h, --help\tPrints this usage screen and exits.\n" @@ -995,6 +1014,8 @@ int main(int argc, char **argv) { no_sep_others = true; else if (is_long_switch(*pArg, "no-sub-cats")) no_sub_cats = true; + else if (is_long_switch(*pArg, "orig-comment")) + add_comments = true; else if (is_long_switch(*pArg, "flat")) flat_output = no_sep_others = true; else if (is_long_switch(*pArg, "match-sec")) @@ -1087,14 +1108,14 @@ int main(int argc, char **argv) { { auto desktop_loader = FsScan( - [&](const string &fPath) { + [&](string &&fPath) { DBGMSG("reading: " << fPath); if (opt_deadline_apps && std::chrono::steady_clock::now() > deadline_apps) { return false; } - auto df = DesktopFile::load_visible(fPath, justLang); + auto df = DesktopFile::load_visible(std::move(fPath), justLang); if (df) root.sink_in(df); @@ -1113,15 +1134,14 @@ int main(int argc, char **argv) { // okay, now let's decorate the remaining menus { auto dir_loader = FsScan( - [&](const string &fPath) { + [&](string &&fPath) { if (opt_deadline_all && std::chrono::steady_clock::now() > deadline_all) { in_timeout = true; return false; } - auto df = - DesktopFile::load_visible(fPath, justLang /*, filter*/); + auto df = DesktopFile::load_visible(std::move(fPath), justLang); if (!df) return true; From 67085e06bc827cdbfe0d25a1f25c0bae4dfba8d8 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Tue, 1 Oct 2024 11:39:12 +0200 Subject: [PATCH 67/85] Minor performance tuning with different containers --- src/fdomenu.cc | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index e9d7ac153..cafa32b4c 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -789,7 +789,7 @@ unordered_multimap MenuNode::fixup() { // descend deep and then check whether the same app has been added somewhere // in the parent nodes, then remove it there - vector checkStack; + deque checkStack; std::function go_deeper; go_deeper = [&](MenuNode *cur) { checkStack.push_back(cur); @@ -835,7 +835,7 @@ void MenuNode::fixup2() { } // Do a depth-first-scan - vector mpath; + deque mpath; std::function descend; // subcalls may modify ancenstor's app but not submenus. Menu operation can @@ -964,7 +964,7 @@ int main(int argc, char **argv) { textdomain(PACKAGE); #endif - vector sharedirs; + deque sharedirs; auto add_split = [&](const char *p) { if (!p || !*p) return false; @@ -975,14 +975,13 @@ int main(int argc, char **argv) { }; // system dirs, either from environment or from static locations - const char *p; + const char *p = nullptr; if (!add_split(getenv("XDG_DATA_HOME")) && (p = getenv("HOME")) && *p) sharedirs.push_back(string(p) + "/.local/share"); - if (!add_split(getenv("XDG_DATA_DIRS"))) { - sharedirs.push_back("/usr/local/share"); - sharedirs.push_back("/usr/share"); - } + if (!add_split(getenv("XDG_DATA_DIRS"))) + sharedirs.insert(sharedirs.end(), {"/usr/local/share", "/usr/share"}); + // option parameters bool add_sep_before = false; bool add_sep_after = false; From bfc13f1958dad8f3687b23507a2ad2ee8e27b6ef Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Tue, 1 Oct 2024 12:22:33 +0200 Subject: [PATCH 68/85] Save a few CPU cycles --- src/fdomenu.cc | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index cafa32b4c..31bd0477a 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -37,8 +37,6 @@ #include #include #include -#include -#include #include // For std::move #include @@ -667,7 +665,7 @@ struct MenuNode { /** * Returns a temporary list of visited node references. */ - unordered_multimap fixup(); + multimap fixup(); // Second run, contains all deco information now void fixup2(); @@ -699,32 +697,32 @@ struct MenuNode { void MenuNode::sink_in(DesktopFilePtr pDf) { + static const auto lessFirstStr = [](const t_menu_path &a, + const t_menu_path &b) { + return strcmp(*a.begin(), *b.begin()) < 0; + }; + auto add_sub_menues = [&](const t_menu_path &mp) { MenuNode *cur = this; - for (auto it = mp.end() - 1; it >= mp.begin(); --it) { - auto key = (*it && **it) ? *it : "Other"; - cur = &cur->submenus[key]; - } + for (auto it = mp.end() - 1; it >= mp.begin(); --it) + cur = &cur->submenus[(*it && **it) ? *it : "Other"]; return cur; }; for (tSplitWalk split(pDf->Categories, ";"); split.Next();) { auto cat = split.str(); t_menu_path refval = {cat.c_str()}; - static auto comper = [](const t_menu_path &a, const t_menu_path &b) { - // endl; - return strcmp(*a.begin(), *b.begin()) < 0; - }; - for (const auto &w : valid_paths) { - // ignore deeper paths, fallback to the main cats only - if (no_sub_cats && w.begin()->size() > 1) - continue; - auto rng = std::equal_range(w.begin(), w.end(), refval, comper); - for (auto it = rng.first; it != rng.second; ++it) { - auto &tgt = *add_sub_menues(*it); - tgt.apps.emplace(pDf->GetNamePtr(), AppEntry(pDf)); - } + // maybe start main cats only + for (auto w = no_sub_cats ? (valid_paths.end() - 1) + : valid_paths.begin(); + w != valid_paths.end(); ++w) { + + auto rng = + std::equal_range(w->begin(), w->end(), refval, lessFirstStr); + for (auto it = rng.first; it != rng.second; ++it) + (*add_sub_menues(*it)) + .apps.emplace(pDf->GetNamePtr(), AppEntry(pDf)); } } } @@ -783,9 +781,9 @@ void MenuNode::print_flat(std::ostream &prt_strm, const string &pfx_before) { } } -unordered_multimap MenuNode::fixup() { +multimap MenuNode::fixup() { - unordered_multimap ret; + multimap ret; // descend deep and then check whether the same app has been added somewhere // in the parent nodes, then remove it there From e54e27a731d384f20c7fbd84b41b478ec0d50bd0 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Tue, 1 Oct 2024 12:22:56 +0200 Subject: [PATCH 69/85] Update XDG format reference version Also extend examples. --- man/icewm-menu-fdo.pod | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/man/icewm-menu-fdo.pod b/man/icewm-menu-fdo.pod index f303fb229..05bf9cdd5 100644 --- a/man/icewm-menu-fdo.pod +++ b/man/icewm-menu-fdo.pod @@ -49,7 +49,10 @@ Print a trailing separator. =item B<--no-sub-cats> -Don't nest subcategories in submenus. +Don't nest subcategories in submenus. The correctness of the +pigeonholing depends on correct application description which shall +always specify a main category. Incorrectly tagged descriptions will be +sorted into the C menu. =item B<-o>, B<--output=FILE> @@ -105,7 +108,8 @@ within their title. =item B<-M filter>, B<--imatch=filter> -Like C<--match> but applied with any letter case. +Like C<--match> but applied with any letter case. Might deliver +incorrect results with some locale settings. =item B<--match-sec> @@ -138,10 +142,17 @@ executable in a B entry in a L. =head2 EXAMPLES The following line in a L file will dynamically generate -a comprehensive set of menus for easy access to F<.desktop> files. +a comprehensive set of menus for easy access to F<.desktop> files, added +in a submenu called C. menuprog "Desktop Apps" folder icewm-menu-fdo +It can also be embedded directly into the loading menu like in the +following example. There could be a separator line added before or after +(or both) in case where the program could generate useful content. + + includeprog icewm-menu-fdo --seps + =head2 ENVIRONMENT B or B are considered as suggested by XDG @@ -154,9 +165,9 @@ found and a default is used instead. =head2 CONFORMING TO B complies roughly to the XDG F<.desktop> file and menu -specification, see L, Version 1.2alpha, -2015-03-06 and L, Version 1.1-draft, 31 -March 2011. +specification, see L (Date: 2020-04-27, +Version: Version 1.5) and L (Date: 20 August +2016, Version: Version 1.1). =head2 CAVEATS @@ -164,6 +175,10 @@ The B program is only built when the L package is configured with the B<--enable-menus-fdo> option and only works with B<--enable-i18n> option. +Integration of XDG menu files is somewhat of varying quality, heavily +depending on the correctness of metadata like translations and sections +(menu category) hints. + =head2 SEE ALSO L, From 88cb0722f70233aee1f871460d2b89e87bbd46de Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Tue, 1 Oct 2024 14:21:14 +0200 Subject: [PATCH 70/85] Fixed merging of some submenu entries into correct parent --- src/fdomenu.cc | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 31bd0477a..50b973bd4 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -819,7 +819,6 @@ multimap MenuNode::fixup() { } void MenuNode::fixup2() { - using t_iter = decltype(submenus)::iterator; auto vit = submenus.find("AudioVideo"); if (vit != submenus.end() && vit->second.deco) { @@ -833,6 +832,7 @@ void MenuNode::fixup2() { } // Do a depth-first-scan + using t_iter = decltype(submenus)::iterator; deque mpath; std::function descend; @@ -867,15 +867,16 @@ void MenuNode::fixup2() { // printed set. if (no_only_child && mpath.size() > 1) { - auto &parent_apps = mpath[mpath.size() - 2]->second.apps; - auto relocate = [&](const string *app_key, AppEntry &app_entry) { + auto relocate = [&](const string *app_key, AppEntry &app_entry, + decltype(MenuNode::apps) &parent_apps, + const string &origin) { // if there is another one with the same key -> hands off! if (parent_apps.find(app_key) != parent_apps.end()) return false; if (no_only_child_hint) - app_entry.AddSfx(safeTrans(node.deco, menu_key), "[]"); + app_entry.AddSfx(safeTrans(node.deco, origin), "[]"); parent_apps.emplace(app_key, std::move(app_entry)); return true; @@ -884,16 +885,21 @@ void MenuNode::fixup2() { mpath.size() > 1) { if (relocate(node.apps.begin()->first, - node.apps.begin()->second)) + node.apps.begin()->second, + mpath[mpath.size() - 2]->second.apps, menu_key)) { node.apps.clear(); + } } // only one sub-menu which contains only applications if (node.apps.empty() && node.submenus.size() == 1 && node.submenus.begin()->second.submenus.empty()) { bool some_remained = false; - for (auto &it : node.submenus.begin()->second.apps) - if (!relocate(it.first, it.second)) - some_remained = true; + for (auto &it : node.submenus.begin()->second.apps) { + some_remained |= + !relocate(it.first, it.second, + mpath[mpath.size() - 1]->second.apps, + node.submenus.begin()->first); + } if (!some_remained) node.submenus.clear(); } From a679bc192a66c751ce5e756eaafce2033478774e Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Wed, 2 Oct 2024 12:10:50 +0200 Subject: [PATCH 71/85] Stop using std::regex Now over 7 times faster with halfe of the code size (optimized build). --- src/fdomenu.cc | 132 +++++++++++++++++++++++++++---------------------- 1 file changed, 74 insertions(+), 58 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 50b973bd4..6a099a18e 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include // For std::move @@ -96,6 +95,8 @@ deque comment_pool; * branches (C++11 compatible) or development branch. */ +#define SPACECHARS " \f\n\r\t\v" + #define startsWith(where, what) (0 == (where).compare(0, (what).size(), (what))) #define startsWithSz(where, what) \ (0 == (where).compare(0, sizeof((what)) - 1, (what))) @@ -343,12 +344,6 @@ bool userFilter(const char *s, bool isSection) { return true; } -auto line_matcher = - std::regex("^\\s*(Terminal|Type|Name|GenericName|Exec|TryExec|Icon|" - "Categories|NoDisplay|OnlyShowIn)" - "(\\[((\\w\\w)(_\\w\\w)?)\\])?\\s*=\\s*(.*){0,1}?\\s*$", - std::regex_constants::ECMAScript); - struct DesktopFile : public tLintRefcounted { bool Terminal = false, IsApp = true, NoDisplay = false, CommandMassaged = false; @@ -448,23 +443,51 @@ DesktopFile::DesktopFile(string filePath, const string &langWanted) { std::ifstream dfile; dfile.open(filePath); string line; - std::smatch m; bool reading = false; - auto take_loc_best = - [&langWanted](decltype(m[0]) &value, decltype(m[0]) &langLong, - decltype(m[0]) &langShort, string &out, string &outLoc) { - if (langWanted.size() > 3 && langLong == langWanted) { - // perfect hit always takes preference - outLoc = value; - } else if (langShort.matched && - 0 == langWanted.compare(0, 2, langShort)) { - if (outLoc.empty()) - outLoc = value; - } else if (!langLong.matched) { - out = value; - } - }; + auto get_value = [&](size_t start) -> string { + auto p = line.find('=', start); + if (p == string::npos) + p = start; + auto v = line.find_first_not_of(SPACECHARS, p + 1); + if (v == string::npos) + v = p + 1; + auto e = line.find_last_not_of(SPACECHARS, v); + e = (e == string::npos) ? e + 1 : string::npos; + return line.substr(v, e - v); + }; + + auto take_loc_best = [&](size_t start, string &out, string &outLoc) { + auto peq = line.find('=', start); + if (peq == string::npos) + return; // no value assigned at all? + + auto v = line.find_first_not_of(SPACECHARS, peq + 1); + if (v == string::npos) + v = peq + 1; + auto e = line.find_last_not_of(SPACECHARS, v); + e = (e == string::npos) ? e + 1 : string::npos; + auto l = line.find('[', start); + + // neutral version + if (l >= peq || l == string::npos) { + out = line.substr(v, e - v); + return; + } + + // translated version but not looked for localized + if (langWanted.size() < 2) + return; + + // get localized + l++; + + // exact match always overrides, the short is considered optional + if (0 == line.compare(l, langWanted.size(), langWanted)) + outLoc = line.substr(v, e - v); + else if (outLoc.empty() && 0 == line.compare(l, 2, langWanted, 0, 2)) + outLoc = line.substr(v, e - v); + }; while (dfile) { line.clear(); @@ -482,43 +505,35 @@ DesktopFile::DesktopFile(string filePath, const string &langWanted) { } if (!reading) continue; - - std::regex_search(line, m, line_matcher); - if (m.empty()) - continue; - - // for(auto x: m) cout << x << " - "; cout << " = " << m.size() << - // endl; - - const auto &value = m[6], key = m[1], langLong = m[3], langShort = m[4]; - // cerr << "val: " << value << ", key: " << key << ", langLong: " << - // langLong << ", langShort: " << langShort << endl; - - if (key == "Terminal") - Terminal = value.compare("true") == 0; - else if (key == "NoDisplay") - NoDisplay = value.compare("true") == 0; - else if (key == "OnlyShowIn") - NoDisplay = true; - else if (key == "Icon") - Icon = value; - else if (key == "Categories") - Categories = value; - else if (key == "Exec") - Exec = value; - else if (key == "TryExec") - TryExec = value; - else if (key == "Type") { - if (value == "Application") + int kl = -1; +#define DFCHECK(x) (kl = sizeof(x) - 1, strncmp(line.c_str(), x, kl) == 0) +#define DFVALUE get_value(kl) + if (DFCHECK("Terminal")) + Terminal = DFVALUE.compare("true") == 0; + else if (DFCHECK("TryExec")) + TryExec = DFVALUE; + else if (DFCHECK("Type")) { + auto v = DFVALUE; + if (v == "Application") IsApp = true; - else if (value == "Directory") + else if (v == "Directory") IsApp = false; - } else if (key == "Name") { - take_loc_best(value, langLong, langShort, Name, NameLoc); - } else if (generic_name && key == "GenericName") { - take_loc_best(value, langLong, langShort, GenericName, - GenericNameLoc); - } + } else if (DFCHECK("NoDisplay")) + NoDisplay = DFVALUE.compare("true") == 0; + else if (DFCHECK("Name")) + take_loc_best(kl, Name, NameLoc); + else if (DFCHECK("OnlyShowIn")) + NoDisplay = true; + else if (DFCHECK("Icon")) + Icon = DFVALUE; + else if (DFCHECK("GenericName")) { + if (generic_name) + take_loc_best(kl, GenericName, GenericNameLoc); + continue; + } else if (DFCHECK("Categories")) + Categories = DFVALUE; + else if (DFCHECK("Exec")) + Exec = DFVALUE; } } @@ -662,6 +677,7 @@ struct MenuNode { void print(std::ostream &prt_strm); void print_flat(std::ostream &prt_strm, const string &pfx_before); bool empty() { return apps.empty() && submenus.empty(); } + /** * Returns a temporary list of visited node references. */ @@ -1075,7 +1091,7 @@ int main(int argc, char **argv) { break; if (!desktop_file_to_start.empty()) { - DesktopFile df(argv[1], ""); + DesktopFile df(argv[1], Elvis(msglang, "")); auto cmd = df.GetCommand(); if (cmd.empty()) return EXIT_FAILURE; From f0d5e545b851f2557cfc748f84ad55733bcf7e8f Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Wed, 2 Oct 2024 12:14:20 +0200 Subject: [PATCH 72/85] Don't evaluate TryExec It is pointless, the existence check is done by icewm anyway. And skipping the arguments from Exec breaks some applications which add extra parameters to active UI/window mode. --- src/fdomenu.cc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 6a099a18e..8dee025b7 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -425,10 +425,6 @@ const string &DesktopFile::GetCommand() { // https://specifications.freedesktop.org/desktop-entry-spec/latest/exec-variables.html if (string::npos == Exec.find('%')) return Exec; - // TryExec should contain the pure command which we prefer. Copy this over - // so that we stick to it - if (!TryExec.empty()) - return (Exec = TryExec); for (const auto &bad : {"%F", "%U", "%f", "%u"}) replace_all(Exec, bad, ""); @@ -510,8 +506,8 @@ DesktopFile::DesktopFile(string filePath, const string &langWanted) { #define DFVALUE get_value(kl) if (DFCHECK("Terminal")) Terminal = DFVALUE.compare("true") == 0; - else if (DFCHECK("TryExec")) - TryExec = DFVALUE; +// else if (DFCHECK("TryExec")) +// TryExec = DFVALUE; else if (DFCHECK("Type")) { auto v = DFVALUE; if (v == "Application") From f8b0720a958c670e490b35e53a48ed8b09969459 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Wed, 2 Oct 2024 12:23:03 +0200 Subject: [PATCH 73/85] Local formating of prog title No more usecases for pass-through stream, and it's slightly faster. --- src/fdomenu.cc | 53 +++++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 8dee025b7..569ecb287 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -506,8 +506,8 @@ DesktopFile::DesktopFile(string filePath, const string &langWanted) { #define DFVALUE get_value(kl) if (DFCHECK("Terminal")) Terminal = DFVALUE.compare("true") == 0; -// else if (DFCHECK("TryExec")) -// TryExec = DFVALUE; + // else if (DFCHECK("TryExec")) + // TryExec = DFVALUE; else if (DFCHECK("Type")) { auto v = DFVALUE; if (v == "Application") @@ -639,23 +639,30 @@ struct AppEntry { return; extraSfx.emplace_back(tSfx{deco[0], deco[1], sfx}); } - ostream &PrintWithSfx(ostream &strm, const string &sTitle) { - if (extraSfx.empty()) { - strm << sTitle; - return strm; - } + string TransWithSfx() { + string ret; + const auto &sTitle = deco->GetTranslatedName(); if (right_to_left) { for (auto rit = extraSfx.rbegin(); rit != extraSfx.rend(); ++rit) - if (sTitle != rit->sfx) - strm << rit->before << rit->sfx << rit->after << " "; - strm << sTitle; + if (sTitle != rit->sfx) { + ret += rit->before; + ret += rit->sfx; + ret += rit->after; + ret += " "; + } + + ret += sTitle; } else { - strm << sTitle; + ret = sTitle; for (const auto &p : extraSfx) - if (sTitle != p.sfx) - strm << " " << p.before << p.sfx << p.after; + if (sTitle != p.sfx) { + ret += " "; + ret += p.before; + ret += p.sfx; + ret += p.after; + } } - return strm; + return ret; } }; @@ -760,9 +767,9 @@ void MenuNode::print(std::ostream &prt_strm) { auto sortedApps = GetSortedApps(); for (auto &p : sortedApps) { auto &pi = p.second->deco; - pi->print_comment(prt_strm) << indent_hint << "prog \""; - p.second->PrintWithSfx(prt_strm, pi->GetTranslatedName()) - << "\" " << pi->Icon << " " << pi->GetCommand() << "\n"; + pi->print_comment(prt_strm) + << indent_hint << "prog \"" << p.second->TransWithSfx() << "\" " + << pi->Icon << " " << pi->GetCommand() << "\n"; } } @@ -782,13 +789,11 @@ void MenuNode::print_flat(std::ostream &prt_strm, const string &pfx_before) { auto &pi = p.second->deco; pi->print_comment(prt_strm) << "prog \""; - if (right_to_left) { - p.second->PrintWithSfx(prt_strm, pi->GetTranslatedName()) - << pfx_before; - } else { - prt_strm << pfx_before; - p.second->PrintWithSfx(prt_strm, pi->GetTranslatedName()); - } + if (right_to_left) + prt_strm << p.second->TransWithSfx() << pfx_before; + else + prt_strm << pfx_before << p.second->TransWithSfx(); + prt_strm << "\" " << pi->Icon << " " << pi->GetCommand() << "\n"; } } From 0a2f4dcbd40e17e11aa73385fb1235e73735eab2 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Wed, 2 Oct 2024 13:06:55 +0200 Subject: [PATCH 74/85] Option to clamp rogue menu title's length --- lib/menu.in | 2 +- man/icewm-menu-fdo.pod | 7 +++++++ src/fdomenu.cc | 17 +++++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/menu.in b/lib/menu.in index a03eaa2f1..2b6db8d16 100644 --- a/lib/menu.in +++ b/lib/menu.in @@ -10,6 +10,6 @@ prog NEdit nedit nedit prog Firefox firefox firefox prog Hexchat xchat hexchat prog Gimp gimp gimp -includeprog icewm-menu-fdo --seps -d1400 -D1650 -S +includeprog icewm-menu-fdo --seps -d1400 -D1650 -S --limit-max-len=42 menufile Programs folder programs menufile Tool_bar folder toolbar diff --git a/man/icewm-menu-fdo.pod b/man/icewm-menu-fdo.pod index 05bf9cdd5..39a24de12 100644 --- a/man/icewm-menu-fdo.pod +++ b/man/icewm-menu-fdo.pod @@ -91,6 +91,13 @@ calculated so far, therefore the timeout should be set a certain time before the actual hard deadline by which the program should be terminated. The output may lack translations and icons. +=item B<-L MAX>, B<--limit-max-len=MAX> + +Cut the calculated program titles (after translation and adding +hints, see C<-C> and C<-g>) at C characters, followed by an +ellipsis. This can help to restrict the width of the menus in cases +where some entry length might get out of hand. + =item B<--flat> Display apps from all categories in one level with the title containing diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 569ecb287..eeb7493d4 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -74,10 +74,14 @@ bool add_comments = false; auto substr_filter = ""; auto substr_filter_nocase = ""; +unsigned prog_name_cut = 0; + // use a more visually appealing default with TTF fonts #ifdef CONFIG_COREFONTS +#define ellipsis "..." auto flat_sep = " / "; #else +#define ellipsis "\xe2\x80\xa6" auto flat_sep = " • "; #endif @@ -108,6 +112,10 @@ deque comment_pool; ((where).size() >= (sizeof((what)) - 1) && \ 0 == (where).compare((where).size() - (sizeof((what)) - 1), \ (sizeof((what)) - 1), (what))) +inline void trimBack(string &s, const char *junk = SPACECHARS) { + auto pos = s.find_last_not_of(junk); + s.erase(pos + 1); +} /** * Container helpers and adaptors @@ -662,6 +670,11 @@ struct AppEntry { ret += p.after; } } + if (prog_name_cut > 0 && ret.size() > prog_name_cut) { + ret.erase(prog_name_cut); + trimBack(ret); + ret += ellipsis; + } return ret; } }; @@ -940,6 +953,7 @@ static void help(bool to_stderr, int xit) { "far\n" "-m, --match=PAT\t\tDisplay only apps with title containing PAT\n" "-M, --imatch=PAT\tLike --match but ignores the letter case\n" + "-L, --limit-max-len=N\tCrop app titles at length N, add ...\n" "--seps \tPrint separators before and after contents\n" "--sep-before\tPrint separator before the contents\n" "--sep-after\tPrint separator only after contents\n" @@ -1069,6 +1083,9 @@ int main(int argc, char **argv) { flat_sep = value; else if (GetArgument(value, "t", "terminal", pArg, argv + argc)) terminal_option = value; + else if (GetArgument(value, "L", "limit-max-len", pArg, + argv + argc)) + prog_name_cut = atoi(value); else if (GetArgument(value, "d", "deadline-apps", pArg, argv + argc)) opt_deadline_apps = value; From 2597cc47381cbf7e9be697ba17e076cfad529c66 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Wed, 2 Oct 2024 13:53:17 +0200 Subject: [PATCH 75/85] Make true/false checks case-insensitive Some applications ignore letter case of the spec and use True for true. --- src/fdomenu.cc | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index eeb7493d4..a2c640794 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -464,29 +464,25 @@ DesktopFile::DesktopFile(string filePath, const string &langWanted) { auto take_loc_best = [&](size_t start, string &out, string &outLoc) { auto peq = line.find('=', start); if (peq == string::npos) - return; // no value assigned at all? - + return; // w00t, no value assigned at all? + // calc value start and end auto v = line.find_first_not_of(SPACECHARS, peq + 1); if (v == string::npos) v = peq + 1; auto e = line.find_last_not_of(SPACECHARS, v); e = (e == string::npos) ? e + 1 : string::npos; + // identify language filter before value assignment auto l = line.find('[', start); - - // neutral version + // i18n neutral version if (l >= peq || l == string::npos) { out = line.substr(v, e - v); return; } - - // translated version but not looked for localized + // translation found but not looking for localized version here? if (langWanted.size() < 2) return; - - // get localized l++; - - // exact match always overrides, the short is considered optional + // the exact match always overrides, the short is considered optional if (0 == line.compare(l, langWanted.size(), langWanted)) outLoc = line.substr(v, e - v); else if (outLoc.empty() && 0 == line.compare(l, 2, langWanted, 0, 2)) @@ -512,10 +508,9 @@ DesktopFile::DesktopFile(string filePath, const string &langWanted) { int kl = -1; #define DFCHECK(x) (kl = sizeof(x) - 1, strncmp(line.c_str(), x, kl) == 0) #define DFVALUE get_value(kl) +#define DFTRUE(x) (0 == strcasecmp("true", x.c_str())) if (DFCHECK("Terminal")) - Terminal = DFVALUE.compare("true") == 0; - // else if (DFCHECK("TryExec")) - // TryExec = DFVALUE; + Terminal = DFTRUE(DFVALUE); else if (DFCHECK("Type")) { auto v = DFVALUE; if (v == "Application") @@ -523,18 +518,16 @@ DesktopFile::DesktopFile(string filePath, const string &langWanted) { else if (v == "Directory") IsApp = false; } else if (DFCHECK("NoDisplay")) - NoDisplay = DFVALUE.compare("true") == 0; + NoDisplay = DFTRUE(DFVALUE); else if (DFCHECK("Name")) take_loc_best(kl, Name, NameLoc); else if (DFCHECK("OnlyShowIn")) NoDisplay = true; else if (DFCHECK("Icon")) Icon = DFVALUE; - else if (DFCHECK("GenericName")) { - if (generic_name) - take_loc_best(kl, GenericName, GenericNameLoc); - continue; - } else if (DFCHECK("Categories")) + else if (DFCHECK("GenericName") && generic_name) + take_loc_best(kl, GenericName, GenericNameLoc); + else if (DFCHECK("Categories")) Categories = DFVALUE; else if (DFCHECK("Exec")) Exec = DFVALUE; From ecb2a2ff695ccd4c722b5aa93a777520dd6d45e4 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Thu, 3 Oct 2024 00:46:04 +0200 Subject: [PATCH 76/85] Overhaul content processing No dummy main categories, resolve incomplete references. Following the spec more closely, identifying apppriate categories. Don't consider application base library type as category. --- contrib/conv_cat.py | 97 ++++++++++------------ src/fdomenu.cc | 96 +++++++++++++++++----- src/fdospecgen.h | 190 +++++++++++++------------------------------- 3 files changed, 173 insertions(+), 210 deletions(-) diff --git a/contrib/conv_cat.py b/contrib/conv_cat.py index 732619393..5428ac305 100644 --- a/contrib/conv_cat.py +++ b/contrib/conv_cat.py @@ -8,12 +8,11 @@ debug = True -edges = collections.defaultdict(lambda: set()) paths = collections.defaultdict(lambda: list()) hints = dict() # a few special ones, those from the spec are added from table input -main_cats = {"Accessibility", "Screensavers", "WINE", "Other"} +main_cats = set() # "Accessibility", "Screensavers", "WINE"} def add_edges(key :str, multicand :list): @@ -32,6 +31,8 @@ def add_edges(key :str, multicand :list): main_cats.add(row[0].strip()) hints[row[0]] = row[1] +if debug: + print(f"main cats: {main_cats}", file=sys.stderr) with open('Additional_Categories.csv', newline='') as csvfile: rdr = csv.reader(csvfile, dialect='unix') @@ -40,55 +41,42 @@ def add_edges(key :str, multicand :list): assert(len(row) == 3) if " " in row[0]: # the header continue - multicand = list(map(lambda s: s.strip(), re.split(r'\sor\s', row[2]))) - add_edges(row[0], multicand) + # we don't care about "based on foo library", that is not a real section + if "Application based on" in row[1]: + continue hints[row[0]] = row[1] + for m in re.split(r'\s+or\s+', row[2]): + m = m.strip() + paths[row[0]].append(list(m.split(';'))) + +# let's fixup references which are not leading to some main category directly +resolved = False +while not resolved: + resolved = True + for k, v in paths.items(): + for w in v: + cat = w[0] + if not cat or cat in main_cats: + continue + if cat not in paths: + print(f"Warning, cannot resolve {cat}", file=sys.stderr) + continue + for more in paths[cat]: + w[:0] = more + resolved = False +print(f"{paths}", file=sys.stderr) -#print(edges, file=sys.stderr) +groupedByLength = collections.defaultdict(lambda: list()) +for k, v in paths.items(): + for l in v: + groupedByLength[1+len(l)].append(l + [k]) +groupedByLength[1] = list(map(lambda x: [x], main_cats)) -def xxx(): - """ - Probably BS, trying to expand the graph, but fails on equally named nodes. - :return: - """ - global edges - keyz = list(edges.keys()) - for k in keyz: - temp = list(edges[k]) - newset = set() - for vv in temp: - xp = vv.split(';') - if len(xp) == 1: - continue - #print(f"multi cand? {k} <-> {vv}") - newset.add(xp[-1]) - chain = list(xp) - chain.append(k) - print(f"chain? {chain}", file=sys.stderr) - while len(chain) > 1: - add_edges(chain[-1], [chain[-2]]) - chain.pop(-1) - edges[k] = newset - - -for k, v in edges.items(): - for vv in v: - #print(f"XX: {vv}") - xp = [k] + list(reversed(vv.strip().split(';'))) - if not xp[-1]: - xp[-1] = "Other" - if xp[-1] not in main_cats: - xp = xp + ["Other"] - if debug: print(f"{len(xp)} -> {xp}", file=sys.stderr) - paths[len(xp)].append(xp) - -paths[1] = list(map(lambda x: [x], main_cats)) - -if debug: print(paths, file=sys.stderr) - -keysByLen = list(reversed(sorted(paths.keys()))) +print(f"{groupedByLength}", file=sys.stderr) + +#keysByLen = list(reversed(sorted(paths.keys()))) print(f"""/** * WARNING: this file is autogenerated! Any change might be overwritten! @@ -107,23 +95,22 @@ def xxx(): using t_menu_path_table = std::initializer_list; using t_menu_path_table_list = std::initializer_list; -#define MENU_DEPTH_MAX {keysByLen[0]} - constexpr t_menu_path_table_list valid_paths = {{""") -for k in keysByLen: +for k in reversed(sorted(groupedByLength.keys())): print(f"\n\t// menu locations of depth {k}\n\t{{") - byFirst = sorted(paths[k], key=lambda l: l[0]) - for v in byFirst: + ways = groupedByLength[k] + for v in sorted(ways, key=lambda x: x[-1]): print("\t\t{") - for t in v: + for t in reversed(v): print("// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: " + hints.get(t, t)) - print("\t\t\tN_(\"" + t + "\"),") + if t: + print("\t\t\tN_(\"" + t + "\"),") + else: + print("\t\t\t\"" + t + "\",") print("\t\t},") print("\t},") print(f"""}}; -#define SIZE_OF_MENU_TABLE {len(keysByLen)} - #endif // FDO_GEN_MENU_STRUCTURE_H""") diff --git a/src/fdomenu.cc b/src/fdomenu.cc index a2c640794..b24ae250b 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -37,6 +37,7 @@ #include #include #include // For std::move +#include #include #include @@ -89,10 +90,11 @@ char *terminal_command; char *terminal_option; // global defaults and helpers -static string ICON_FOLDER("folder"); +static const string ICON_FOLDER("folder"), OTH("Other"); string indent_hint(""); // use this to dump optional comment data, deque is pointer-stable deque comment_pool; +set valid_main_cats; /* * Certain parts borrowed from apt-cacher-ng by its autor, either from older @@ -143,6 +145,10 @@ template struct lessByDerefAdaptor { bool operator()(const T *a, const T *b) { return *a < *b; } }; +template const T &iback(const initializer_list &q) { + return *(q.end() - 1); +} + /** * Basic base implementation of a reference-counted class */ @@ -720,34 +726,83 @@ struct MenuNode { } }; +const auto lessFirstStr = [](const t_menu_path &a, const t_menu_path &b) { + return strcmp(*a.begin(), *b.begin()) < 0; +}; + void MenuNode::sink_in(DesktopFilePtr pDf) { - static const auto lessFirstStr = [](const t_menu_path &a, - const t_menu_path &b) { - return strcmp(*a.begin(), *b.begin()) < 0; + // XXX: use plain pointers, with length, or string_view? Probably alost + // worthless because SSO applies in the vast majority of cases + static vector main_cats, sub_cats; + main_cats.clear(); + sub_cats.clear(); + + for (tSplitWalk split(pDf->Categories, ";"); split.Next();) { + string k(split); + auto hit = valid_main_cats.find(k); + if (hit != valid_main_cats.end()) { + DBGMSG("mcat: " << k); + main_cats.push_back(std::move(k)); + } else { + DBGMSG("scat: " << k); + sub_cats.push_back(std::move(k)); + } + } + bool added_somewhere = false; + auto install = [&pDf, &added_somewhere](MenuNode *cur) { + if (!cur) + return; + added_somewhere = true; + cur->apps.emplace(pDf->GetNamePtr(), AppEntry(pDf)); }; - auto add_sub_menues = [&](const t_menu_path &mp) { - MenuNode *cur = this; - for (auto it = mp.end() - 1; it >= mp.begin(); --it) - cur = &cur->submenus[(*it && **it) ? *it : "Other"]; + auto add_sub_menues = [&](const t_menu_path &mp, MenuNode *cur, + int roffset = -1) { + auto itLast = mp.end() + roffset; + for (auto it = itLast; it >= mp.begin(); --it) + cur = &cur->submenus[*it]; return cur; }; - for (tSplitWalk split(pDf->Categories, ";"); split.Next();) { - auto cat = split.str(); - t_menu_path refval = {cat.c_str()}; - - // maybe start main cats only - for (auto w = no_sub_cats ? (valid_paths.end() - 1) - : valid_paths.begin(); - w != valid_paths.end(); ++w) { + for (const auto &sk : sub_cats) { + t_menu_path refval = {sk.c_str()}; + for (auto w = valid_paths.begin(); w != valid_paths.end(); ++w) { auto rng = std::equal_range(w->begin(), w->end(), refval, lessFirstStr); - for (auto it = rng.first; it != rng.second; ++it) - (*add_sub_menues(*it)) - .apps.emplace(pDf->GetNamePtr(), AppEntry(pDf)); + for (auto iPath = rng.first; iPath != rng.second; ++iPath) { + string mk = iback(*iPath); + if (no_sub_cats) { + if (!mk.empty()) + install(&submenus[mk]); + } else if (!mk.empty()) { + // easy case, path to the exact main category is known + install(add_sub_menues(*iPath, this, -1)); + } else { + // apply to all cats as per spec + if (main_cats.empty()) + install(add_sub_menues(*iPath, &submenus[OTH], -2)); + else { + + for (const auto &any_mk : main_cats) { + install( + add_sub_menues(*iPath, &submenus[any_mk], -2)); + } + } + } + } + } + } + + // catch-all + if (!added_somewhere) { + + if (main_cats.empty()) + install(&submenus[OTH]); + else { + for (const auto &mk : main_cats) + install(&submenus[mk]); } } } @@ -1129,6 +1184,9 @@ int main(int argc, char **argv) { deadline_all = now + std::chrono::milliseconds(b); } + for (const auto &p : *(valid_paths.end() - 1)) + valid_main_cats.insert(*p.begin()); + auto justLang = string(msglang ? msglang : ""); justLang = justLang.substr(0, justLang.find('.')); diff --git a/src/fdospecgen.h b/src/fdospecgen.h index 9f8df034a..9a4315dcb 100644 --- a/src/fdospecgen.h +++ b/src/fdospecgen.h @@ -15,8 +15,6 @@ using t_menu_path = std::initializer_list; using t_menu_path_table = std::initializer_list; using t_menu_path_table_list = std::initializer_list; -#define MENU_DEPTH_MAX 4 - constexpr t_menu_path_table_list valid_paths = { // menu locations of depth 4 @@ -28,8 +26,8 @@ constexpr t_menu_path_table_list valid_paths = { N_("Settings"), // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tool to manage hardware components, like sound cards, video cards or printers N_("HardwareSettings"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other - N_("Other"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Settings applications + N_("Settings"), }, }, @@ -44,20 +42,12 @@ constexpr t_menu_path_table_list valid_paths = { N_("Utility"), }, { -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on DDE libraries - N_("DDE"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on Qt libraries - N_("Qt"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other - N_("Other"), - }, - { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A dictionary N_("Dictionary"), // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A text tool utility N_("TextTools"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other - N_("Other"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Small utility application, "Accessories" + N_("Utility"), }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A file manager @@ -68,22 +58,6 @@ constexpr t_menu_path_table_list valid_paths = { N_("System"), }, { -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on GNOME libraries - N_("GNOME"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on GTK+ libraries - N_("GTK"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other - N_("Other"), - }, - { -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on KDE libraries - N_("KDE"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: QT - N_("QT"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other - N_("Other"), - }, - { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An app related to MIDI N_("Midi"), // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An audio application @@ -179,14 +153,6 @@ constexpr t_menu_path_table_list valid_paths = { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for viewing, creating, or processing graphics N_("Graphics"), }, - { -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on XFCE libraries - N_("XFCE"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on GTK+ libraries - N_("GTK"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other - N_("Other"), - }, }, // menu locations of depth 2 @@ -224,8 +190,8 @@ constexpr t_menu_path_table_list valid_paths = { { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application handles adult or explicit material N_("Adult"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other - N_("Other"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: + "", }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Adventure style game @@ -236,8 +202,8 @@ constexpr t_menu_path_table_list valid_paths = { { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A simple amusement N_("Amusement"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other - N_("Other"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: + "", }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Arcade style game @@ -290,14 +256,14 @@ constexpr t_menu_path_table_list valid_paths = { { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to edit audio/video files N_("AudioVideoEditing"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A video application - N_("Video"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An audio application + N_("Audio"), }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to edit audio/video files N_("AudioVideoEditing"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An audio application - N_("Audio"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A video application + N_("Video"), }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to edit audio/video files @@ -336,12 +302,6 @@ constexpr t_menu_path_table_list valid_paths = { N_("Development"), }, { -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on COSMIC libraries - N_("COSMIC"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other - N_("Other"), - }, - { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A calculator N_("Calculator"), // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Small utility application, "Accessories" @@ -404,8 +364,8 @@ constexpr t_menu_path_table_list valid_paths = { { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application that only works inside a terminal (text-based or command line application) N_("ConsoleOnly"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other - N_("Other"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: + "", }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside:   @@ -428,8 +388,8 @@ constexpr t_menu_path_table_list valid_paths = { { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Important application, core to the desktop such as a file manager or a help browser N_("Core"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other - N_("Other"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: + "", }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Data visualization software @@ -446,8 +406,8 @@ constexpr t_menu_path_table_list valid_paths = { { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to manage a database N_("Database"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for presenting, creating, or processing multimedia (audio/video) - N_("AudioVideo"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An office type application + N_("Office"), }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to manage a database @@ -458,8 +418,8 @@ constexpr t_menu_path_table_list valid_paths = { { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to manage a database N_("Database"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An office type application - N_("Office"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for presenting, creating, or processing multimedia (audio/video) + N_("AudioVideo"), }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tool to debug applications @@ -494,8 +454,8 @@ constexpr t_menu_path_table_list valid_paths = { { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Help or documentation N_("Documentation"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other - N_("Other"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: + "", }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Economy software @@ -524,20 +484,20 @@ constexpr t_menu_path_table_list valid_paths = { { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Electronics software, e.g. a circuit designer N_("Electronics"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other - N_("Other"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: + "", }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Email application N_("Email"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Network application such as a web browser - N_("Network"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An office type application + N_("Office"), }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Email application N_("Email"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An office type application - N_("Office"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Network application such as a web browser + N_("Network"), }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Emulator of another platform, such as a DOS emulator @@ -554,8 +514,8 @@ constexpr t_menu_path_table_list valid_paths = { { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Engineering software, e.g. CAD programs N_("Engineering"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other - N_("Other"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: + "", }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: RSS, podcast and other subscription based contents @@ -566,14 +526,14 @@ constexpr t_menu_path_table_list valid_paths = { { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A file tool utility N_("FileTools"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: System application, "System Tools" such as say a log viewer or network monitor - N_("System"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Small utility application, "Accessories" + N_("Utility"), }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A file tool utility N_("FileTools"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Small utility application, "Accessories" - N_("Utility"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: System application, "System Tools" such as say a log viewer or network monitor + N_("System"), }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Tools like FTP or P2P programs @@ -600,12 +560,6 @@ constexpr t_menu_path_table_list valid_paths = { N_("Office"), }, { -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on GTK+ libraries - N_("GTK"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other - N_("Other"), - }, - { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A GUI designer application N_("GUIDesigner"), // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An application for development @@ -650,14 +604,14 @@ constexpr t_menu_path_table_list valid_paths = { { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: HAM radio software N_("HamRadio"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An audio application - N_("Audio"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Network application such as a web browser + N_("Network"), }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: HAM radio software N_("HamRadio"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Network application such as a web browser - N_("Network"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An audio application + N_("Audio"), }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tool to manage hardware components, like sound cards, video cards or printers @@ -720,12 +674,6 @@ constexpr t_menu_path_table_list valid_paths = { N_("Network"), }, { -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on Java GUI libraries, such as AWT or Swing - N_("Java"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other - N_("Other"), - }, - { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A game for kids N_("KidsGame"), // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A game @@ -816,12 +764,6 @@ constexpr t_menu_path_table_list valid_paths = { N_("Network"), }, { -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on Motif libraries - N_("Motif"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other - N_("Other"), - }, - { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Musical software N_("Music"), // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application for presenting, creating, or processing multimedia (audio/video) @@ -884,14 +826,14 @@ constexpr t_menu_path_table_list valid_paths = { { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to play audio/video files N_("Player"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A video application - N_("Video"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An audio application + N_("Audio"), }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to play audio/video files N_("Player"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An audio application - N_("Audio"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A video application + N_("Video"), }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to play audio/video files @@ -914,14 +856,14 @@ constexpr t_menu_path_table_list valid_paths = { { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Project management application N_("ProjectManagement"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An application for development - N_("Development"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An office type application + N_("Office"), }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Project management application N_("ProjectManagement"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An office type application - N_("Office"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An application for development + N_("Development"), }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Desktop Publishing applications and Color Management tools @@ -936,22 +878,16 @@ constexpr t_menu_path_table_list valid_paths = { N_("Office"), }, { -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application based on Qt libraries - N_("Qt"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other - N_("Other"), - }, - { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to record audio/video files N_("Recorder"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A video application - N_("Video"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An audio application + N_("Audio"), }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to record audio/video files N_("Recorder"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An audio application - N_("Audio"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A video application + N_("Video"), }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Application to record audio/video files @@ -1130,14 +1066,14 @@ constexpr t_menu_path_table_list valid_paths = { { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tool for web developers N_("WebDevelopment"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An application for development - N_("Development"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Network application such as a web browser + N_("Network"), }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A tool for web developers N_("WebDevelopment"), -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Network application such as a web browser - N_("Network"), +// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An application for development + N_("Development"), }, { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A word processor @@ -1150,10 +1086,6 @@ constexpr t_menu_path_table_list valid_paths = { // menu locations of depth 1 { { -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Accessibility - N_("Accessibility"), - }, - { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: An audio application N_("Audio"), }, @@ -1186,18 +1118,10 @@ constexpr t_menu_path_table_list valid_paths = { N_("Office"), }, { -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Other - N_("Other"), - }, - { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Scientific software N_("Science"), }, { -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Screensavers - N_("Screensavers"), - }, - { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: Settings applications N_("Settings"), }, @@ -1213,13 +1137,7 @@ constexpr t_menu_path_table_list valid_paths = { // TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: A video application N_("Video"), }, - { -// TRANSLATORS: This is a SHORT category menu name from freedesktop.org. Please add compact punctuation if needed but no double-quotes! Hint for the content inside: WINE - N_("WINE"), - }, }, }; -#define SIZE_OF_MENU_TABLE 4 - #endif // FDO_GEN_MENU_STRUCTURE_H From 37e5381792668c0cda6702d8d425608f86e9cc07 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Thu, 3 Oct 2024 17:44:33 +0200 Subject: [PATCH 77/85] Resolve shadowing of apps which are having the same translated name --- src/fdomenu.cc | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index b24ae250b..79db1bae6 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -702,25 +702,36 @@ struct MenuNode { void fixup2(); private: + // XXX: this is actually a lame approach, a simple vector would be enough + // for sorting, and cheaper. Unfortunatelly std::sort breaks here because of + // STL's namespace reference idiocy on swap calls, i.e. + // https://stackoverflow.com/questions/52998768/how-do-i-make-stdsort-not-have-name-collision-between-stdswap-and-my-namespa + // + // OTOH the tree based sorting is not that expensive either for the small + // amount of element which we have here. + // + using t_sorted_menus = - map, tLessOp4Localized>; + multimap, tLessOp4Localized>; t_sorted_menus GetSortedMenus() { t_sorted_menus ret; for (auto &m : this->submenus) { auto &menuDeco = m.second.deco; - ret[safeTrans(menuDeco, m.first)] = - make_pair(menuDeco ? menuDeco->Icon : ICON_FOLDER, &m.second); + ret.emplace( + safeTrans(menuDeco, m.first), + make_pair(menuDeco ? menuDeco->Icon : ICON_FOLDER, &m.second)); } return ret; } using t_sorted_apps = - map; + multimap; t_sorted_apps GetSortedApps() { t_sorted_apps sortedApps; for (auto &p : this->apps) { - sortedApps[&(p.second.deco->GetTranslatedName())] = &p.second; + sortedApps.emplace(&(p.second.deco->GetTranslatedName()), + &p.second); } return sortedApps; } @@ -814,7 +825,7 @@ void MenuNode::print(std::ostream &prt_strm) { auto &name = m.first; auto &deco = m.second.second->deco; - prt_strm << indent_hint << "menu \"" << safeTrans(deco, name) << "\" " + prt_strm << indent_hint << "menu \"" << name << "\" " << ((deco && !deco->Icon.empty()) ? deco->Icon : ICON_FOLDER) << " {\n"; @@ -838,10 +849,8 @@ void MenuNode::print_flat(std::ostream &prt_strm, const string &pfx_before) { auto sorted = GetSortedMenus(); for (auto &m : sorted) { auto &name = m.first; - auto &deco = m.second.second->deco; - auto pfx = right_to_left - ? (string(flat_sep) + safeTrans(deco, name) + pfx_before) - : (pfx_before + safeTrans(deco, name) + flat_sep); + auto pfx = right_to_left ? (string(flat_sep) + name + pfx_before) + : (pfx_before + name + flat_sep); m.second.second->print_flat(prt_strm, pfx); } From 386114bebdddb988ea5318a5313414b8102e899d Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Fri, 4 Oct 2024 09:39:23 +0200 Subject: [PATCH 78/85] Convert translated sorting to internal bubble sort --- src/fdomenu.cc | 100 ++++++++++++++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 39 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 79db1bae6..f79109d49 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -131,6 +131,7 @@ struct tLessOp4Localized { b.data() + b.size()) < 0; } }; +tLessOp4Localized *loc_comper; struct tLessOp4LocalizedDeref { std::locale loc; // default locale @@ -702,36 +703,59 @@ struct MenuNode { void fixup2(); private: - // XXX: this is actually a lame approach, a simple vector would be enough - // for sorting, and cheaper. Unfortunatelly std::sort breaks here because of - // STL's namespace reference idiocy on swap calls, i.e. - // https://stackoverflow.com/questions/52998768/how-do-i-make-stdsort-not-have-name-collision-between-stdswap-and-my-namespa - // - // OTOH the tree based sorting is not that expensive either for the small - // amount of element which we have here. - // - - using t_sorted_menus = - multimap, tLessOp4Localized>; + struct t_menu_item { + string translated; + MenuNode *pNode; + }; + using t_sorted_menus = vector; + t_sorted_menus GetSortedMenus() { t_sorted_menus ret; - - for (auto &m : this->submenus) { - auto &menuDeco = m.second.deco; - ret.emplace( - safeTrans(menuDeco, m.first), - make_pair(menuDeco ? menuDeco->Icon : ICON_FOLDER, &m.second)); + int n = submenus.size(); + ret.reserve(n); + + for (auto &m : this->submenus) + ret.push_back( + t_menu_item{safeTrans(m.second.deco, m.first), &m.second}); + + // plain bubble sort is totally sufficient for in-place sorting on small + // ranges like here + for (int i = 0; i < n - 1; i++) { + for (int j = 0; j < n - i - 1; j++) { + if (loc_comper->operator()(ret[j + 1].translated, + ret[j].translated)) { + std::swap(ret[j], ret[j + 1]); + } + } } + return ret; } - using t_sorted_apps = - multimap; + struct t_app_item { + const string *pTrName; + AppEntry *pAppEntry; + }; + using t_sorted_apps = vector; + t_sorted_apps GetSortedApps() { t_sorted_apps sortedApps; - for (auto &p : this->apps) { - sortedApps.emplace(&(p.second.deco->GetTranslatedName()), - &p.second); + int n = apps.size(); + sortedApps.reserve(n); + + for (auto &it : apps) + sortedApps.emplace_back( + t_app_item{&it.second.deco->GetTranslatedName(), &it.second}); + + // plain bubble sort is totally sufficient for in-place sorting on small + // ranges like here + for (int i = 0; i < n - 1; i++) { + for (int j = 0; j < n - i - 1; j++) { + if (loc_comper->operator()(*sortedApps[j + 1].pTrName, + *sortedApps[j].pTrName)) { + std::swap(sortedApps[j], sortedApps[j + 1]); + } + } } return sortedApps; } @@ -742,9 +766,8 @@ const auto lessFirstStr = [](const t_menu_path &a, const t_menu_path &b) { }; void MenuNode::sink_in(DesktopFilePtr pDf) { - - // XXX: use plain pointers, with length, or string_view? Probably alost - // worthless because SSO applies in the vast majority of cases + // XXX: that is okay for small strings here (because SSO) but might still + // switch to string_views static vector main_cats, sub_cats; main_cats.clear(); sub_cats.clear(); @@ -795,7 +818,6 @@ void MenuNode::sink_in(DesktopFilePtr pDf) { if (main_cats.empty()) install(add_sub_menues(*iPath, &submenus[OTH], -2)); else { - for (const auto &any_mk : main_cats) { install( add_sub_menues(*iPath, &submenus[any_mk], -2)); @@ -822,15 +844,14 @@ void MenuNode::print(std::ostream &prt_strm) { // translated name to icon and submenu (sorted by translated name) auto sorted = GetSortedMenus(); for (auto &m : sorted) { - auto &name = m.first; - auto &deco = m.second.second->deco; + auto &deco = m.pNode->deco; - prt_strm << indent_hint << "menu \"" << name << "\" " + prt_strm << indent_hint << "menu \"" << m.translated << "\" " << ((deco && !deco->Icon.empty()) ? deco->Icon : ICON_FOLDER) << " {\n"; indent_hint += "\t"; - m.second.second->print(prt_strm); + m.pNode->print(prt_strm); indent_hint.pop_back(); prt_strm << indent_hint << "}\n"; @@ -838,9 +859,9 @@ void MenuNode::print(std::ostream &prt_strm) { auto sortedApps = GetSortedApps(); for (auto &p : sortedApps) { - auto &pi = p.second->deco; + auto &pi = p.pAppEntry->deco; pi->print_comment(prt_strm) - << indent_hint << "prog \"" << p.second->TransWithSfx() << "\" " + << indent_hint << "prog \"" << p.pAppEntry->TransWithSfx() << "\" " << pi->Icon << " " << pi->GetCommand() << "\n"; } } @@ -848,21 +869,21 @@ void MenuNode::print(std::ostream &prt_strm) { void MenuNode::print_flat(std::ostream &prt_strm, const string &pfx_before) { auto sorted = GetSortedMenus(); for (auto &m : sorted) { - auto &name = m.first; - auto pfx = right_to_left ? (string(flat_sep) + name + pfx_before) - : (pfx_before + name + flat_sep); - m.second.second->print_flat(prt_strm, pfx); + auto pfx = right_to_left + ? (string(flat_sep) + m.translated + pfx_before) + : (pfx_before + m.translated + flat_sep); + m.pNode->print_flat(prt_strm, pfx); } auto sortedApps = GetSortedApps(); for (auto &p : sortedApps) { - auto &pi = p.second->deco; + auto &pi = p.pAppEntry->deco; pi->print_comment(prt_strm) << "prog \""; if (right_to_left) - prt_strm << p.second->TransWithSfx() << pfx_before; + prt_strm << p.pAppEntry->TransWithSfx() << pfx_before; else - prt_strm << pfx_before << p.second->TransWithSfx(); + prt_strm << pfx_before << p.pAppEntry->TransWithSfx(); prt_strm << "\" " << pi->Icon << " " << pi->GetCommand() << "\n"; } @@ -1055,6 +1076,7 @@ int main(int argc, char **argv) { bindtextdomain(PACKAGE, LOCDIR); textdomain(PACKAGE); #endif + loc_comper = new tLessOp4Localized(); deque sharedirs; auto add_split = [&](const char *p) { From 7a4707c42c7bc2a39e4768f749d81794d093cd14 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Fri, 4 Oct 2024 10:46:55 +0200 Subject: [PATCH 79/85] Wide char aware string cropping --- src/fdomenu.cc | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index f79109d49..ce56942b0 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -39,6 +39,8 @@ #include // For std::move #include +#include + #include #include @@ -671,10 +673,18 @@ struct AppEntry { } } if (prog_name_cut > 0 && ret.size() > prog_name_cut) { - ret.erase(prog_name_cut); - trimBack(ret); - ret += ellipsis; + auto u16_conv = + wstring_convert, char16_t>{} + .from_bytes(ret); + if (u16_conv.size() > prog_name_cut) { + u16_conv.erase(prog_name_cut); + ret = wstring_convert, char16_t>{} + .to_bytes(u16_conv); + trimBack(ret); + ret += ellipsis; + } } + return ret; } }; From 482bda0c6a5b61774e1a5529e59f6e90bc3f26bc Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Fri, 4 Oct 2024 11:38:16 +0200 Subject: [PATCH 80/85] Drop unused fields, ignore comments earlier --- src/fdomenu.cc | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index ce56942b0..9d54e6349 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -362,11 +362,11 @@ bool userFilter(const char *s, bool isSection) { } struct DesktopFile : public tLintRefcounted { - bool Terminal = false, IsApp = true, NoDisplay = false, - CommandMassaged = false; + bool IsTerminal = false, NoDisplay = false; private: - string Name, Exec, TryExec; + bool CommandMassaged = false; + string Name, Exec; string NameLoc, GenericName, GenericNameLoc; public: @@ -402,6 +402,7 @@ struct DesktopFile : public tLintRefcounted { ret.reset(new DesktopFile(path, lang)); if (ret->NoDisplay || !userFilter(ret->Name.c_str(), false) || !userFilter(ret->GetTranslatedName().c_str(), false)) { + ret.reset(); } else { if (add_comments) { @@ -434,7 +435,7 @@ const string &DesktopFile::GetCommand() { CommandMassaged = true; - if (Terminal && terminal_command) { + if (IsTerminal && terminal_command) { Exec = string(terminal_command) + " -e " + Exec; } @@ -510,25 +511,22 @@ DesktopFile::DesktopFile(string filePath, const string &langWanted) { if (startsWithSz(line, "[Desktop Entry")) { reading = true; } else if (reading) // finished with desktop entry contents - break; + return; } - if (!reading) + if (!reading || line[0] == '#') continue; + int kl = -1; #define DFCHECK(x) (kl = sizeof(x) - 1, strncmp(line.c_str(), x, kl) == 0) #define DFVALUE get_value(kl) #define DFTRUE(x) (0 == strcasecmp("true", x.c_str())) if (DFCHECK("Terminal")) - Terminal = DFTRUE(DFVALUE); - else if (DFCHECK("Type")) { - auto v = DFVALUE; - if (v == "Application") - IsApp = true; - else if (v == "Directory") - IsApp = false; - } else if (DFCHECK("NoDisplay")) + IsTerminal = DFTRUE(DFVALUE); + else if (DFCHECK("NoDisplay")) { NoDisplay = DFTRUE(DFVALUE); - else if (DFCHECK("Name")) + if (NoDisplay) + return; + } else if (DFCHECK("Name")) take_loc_best(kl, Name, NameLoc); else if (DFCHECK("OnlyShowIn")) NoDisplay = true; From f428d3b1d62b00a73ec5688908e4de8152bbb736 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Fri, 4 Oct 2024 12:48:58 +0200 Subject: [PATCH 81/85] More similar standard level selection (to autoconf with recent compilers) --- src/CMakeLists.txt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0b012e876..98db31a73 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,8 +4,14 @@ cmake_minimum_required(VERSION 3.13) PROJECT(ICEWM CXX) -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_STANDARD_REQUIRED on) +set(CMAKE_CXX_STANDARD 14) +# Do not fail (because we are still C++11 compliant), try to continue anyway +# with -std=c++11. +set(CMAKE_CXX_STANDARD_REQUIRED off) +# Actually try to use C++20 as well where possible, to uncover potential issues. +if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.12") + set(CMAKE_CXX_STANDARD 20) +endif() INCLUDE(CheckIncludeFiles) INCLUDE(CheckLibraryExists) From 5db76ec6408f5cd7292539956f4e1bd20f99bd60 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Fri, 4 Oct 2024 12:54:52 +0200 Subject: [PATCH 82/85] Fix C++14 issue with constness of functors --- src/fdomenu.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 9d54e6349..98aab6045 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -145,7 +145,7 @@ struct tLessOp4LocalizedDeref { }; template struct lessByDerefAdaptor { - bool operator()(const T *a, const T *b) { return *a < *b; } + bool operator()(const T *a, const T *b) const { return *a < *b; } }; template const T &iback(const initializer_list &q) { From 295c80c2fb54231c4ec06b3903a04bccd5016ca4 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Fri, 4 Oct 2024 13:44:46 +0200 Subject: [PATCH 83/85] Use system installation of nanosvg package, where possible --- src/CMakeLists.txt | 59 ++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 98db31a73..cca7af811 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,14 +4,11 @@ cmake_minimum_required(VERSION 3.13) PROJECT(ICEWM CXX) -set(CMAKE_CXX_STANDARD 14) # Do not fail (because we are still C++11 compliant), try to continue anyway # with -std=c++11. set(CMAKE_CXX_STANDARD_REQUIRED off) # Actually try to use C++20 as well where possible, to uncover potential issues. -if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.12") - set(CMAKE_CXX_STANDARD 20) -endif() +set(CMAKE_CXX_STANDARD 20) INCLUDE(CheckIncludeFiles) INCLUDE(CheckLibraryExists) @@ -133,11 +130,13 @@ if(ENABLE_NLS OR CONFIG_I18N) if(CONFIG_LIBICONV) LIST(APPEND nls_LIBS iconv) endif() -# XXX: once cmake 3.20 became standard, replace this block with dependency on -# Intl::Intl interface target. - include(FindIntl) - if(Intl_FOUND) - list(APPEND nls_LIBS ${Intl_LIBRARIES}) + find_package(Intl) + if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") + list(APPEND nls_LIBS Intl::Intl) + else() + if(Intl_FOUND) + list(APPEND nls_LIBS ${Intl_LIBRARIES}) + endif() endif() endif() @@ -252,21 +251,31 @@ endif() if (CONFIG_NANOSVG) set(hub https://raw.githubusercontent.com/memononen/nanosvg/master/src) - foreach(nano nanosvg.h nanosvgrast.h) - message(STATUS "Checking for src/${nano}") - set(src ${CMAKE_SOURCE_DIR}/src/${nano}) - if (NOT EXISTS ${src}) - set(url ${hub}/${nano}) - file(DOWNLOAD ${url} ${src} INACTIVITY_TIMEOUT 3 STATUS down) - list(GET down 0 stat) - list(GET down 1 mesg) - if(NOT ${stat} EQUAL 0 OR NOT EXISTS ${src}) - message(WARNING "Cannot download ${url} to ${src}: ${mesg}") - set(CONFIG_NANOSVG off) - break() - endif() + find_package(NanoSVG) + if (NanoSVG_FOUND) + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/nanosvg.h OR EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/nanosvgrast.h) + message(WARNING "nanosvg headers installed on the system but shadowed by src/nano*.h headers") + else() + message(STATUS "Using nanosvg headers from the system") + LIST(APPEND icewm_img_libs NanoSVG::nanosvg NanoSVG::nanosvgrast) endif() - endforeach() + else() + foreach(nano src/nanosvg.h src/nanosvgrast.h) + message(STATUS "Checking for src/${nano}") + set(src ${CMAKE_SOURCE_DIR}/src/${nano}) + if (NOT EXISTS ${src}) + set(url ${hub}/${nano}) + file(DOWNLOAD ${url} ${src} INACTIVITY_TIMEOUT 3 STATUS down) + list(GET down 0 stat) + list(GET down 1 mesg) + if(NOT ${stat} EQUAL 0 OR NOT EXISTS ${src}) + message(WARNING "Cannot download ${url} to ${src}: ${mesg}") + set(CONFIG_NANOSVG off) + break() + endif() + endif() + endforeach() + endif() endif() # cursor configuration error check @@ -440,7 +449,11 @@ list(REMOVE_DUPLICATES icewm_pc_flags) do_auto_inc_headers(ICE_COMMON_SRCS) add_library(ice STATIC ${ICE_COMMON_SRCS}) target_compile_options(ice PUBLIC ${icewm_pc_flags}) +# even if not linking against some libs directly, require their include paths to be considered target_include_directories(ice PUBLIC ${Intl_INCLUDE_DIRS}) +if(TARGET NanoSVG::nanosvg) + target_link_libraries(ice NanoSVG::nanosvg) +endif() SET(ITK_SRCS ymenu.cc ylabel.cc yscrollview.cc ymenuitem.cc yscrollbar.cc ybutton.cc ylistbox.cc yinputline.cc From 62ae9f4f351533abc53de5e60039bec9f3967b18 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Fri, 4 Oct 2024 16:21:43 +0200 Subject: [PATCH 84/85] Stop using smart pointers The deco objects have a pretty ordinary lifecycle. --- src/fdomenu.cc | 175 ++++++++----------------------------------------- 1 file changed, 26 insertions(+), 149 deletions(-) diff --git a/src/fdomenu.cc b/src/fdomenu.cc index 98aab6045..6879c99e8 100644 --- a/src/fdomenu.cc +++ b/src/fdomenu.cc @@ -133,17 +133,9 @@ struct tLessOp4Localized { b.data() + b.size()) < 0; } }; +// initialize the global instance AFTER i18n setup tLessOp4Localized *loc_comper; -struct tLessOp4LocalizedDeref { - std::locale loc; // default locale - const std::collate &coll = std::use_facet>(loc); - bool operator()(const std::string *a, const std::string *b) { - return coll.compare(a->data(), a->data() + a->size(), b->data(), - b->data() + b->size()) < 0; - } -}; - template struct lessByDerefAdaptor { bool operator()(const T *a, const T *b) const { return *a < *b; } }; @@ -152,118 +144,6 @@ template const T &iback(const initializer_list &q) { return *(q.end() - 1); } -/** - * Basic base implementation of a reference-counted class - */ -struct tLintRefcounted { - private: - size_t m_nRefCount = 0; - - public: - inline void __inc_ref() noexcept { m_nRefCount++; } - inline void __dec_ref() { - if (--m_nRefCount == 0) - delete this; - } - virtual ~tLintRefcounted() {} - inline size_t __ref_cnt() { return m_nRefCount; } -}; - -/** - * Lightweight intrusive smart pointer with ordinary reference counting - */ -template class lint_ptr { - T *m_ptr = nullptr; - - public: - explicit lint_ptr() {} - /** - * @brief lint_ptr Captures the pointer and ensures that it's released when - * the refcount goes to zero, unless initialyTakeRef is set to false. If - * initialyTakeRef is false, the operation is asymmetric, i.e. one extra - * __dec_ref operation will happen in the end. - * - * @param rawPtr - * @param initialyTakeRef - */ - explicit lint_ptr(T *rawPtr, bool initialyTakeRef = true) : m_ptr(rawPtr) { - if (rawPtr && initialyTakeRef) - rawPtr->__inc_ref(); - } - T *construct() { - reset(new T); - return m_ptr; - } - lint_ptr(const ::lint_ptr &orig) : m_ptr(orig.m_ptr) { - if (!m_ptr) - return; - m_ptr->__inc_ref(); - } - lint_ptr(::lint_ptr &&orig) { - if (this == &orig) - return; - m_ptr = orig.m_ptr; - orig.m_ptr = nullptr; - } - inline ~lint_ptr() { - if (!m_ptr) - return; - m_ptr->__dec_ref(); - } - T *get() const { return m_ptr; } - bool operator==(const T *raw) const { return get() == raw; } - inline void reset(T *rawPtr) noexcept { - if (rawPtr == m_ptr) // heh? - return; - reset(); - m_ptr = rawPtr; - if (rawPtr) - rawPtr->__inc_ref(); - } - inline void swap(lint_ptr &other) { std::swap(m_ptr, other.m_ptr); } - inline void reset() noexcept { - if (m_ptr) - m_ptr->__dec_ref(); - m_ptr = nullptr; - } - lint_ptr &operator=(const lint_ptr &other) { - if (m_ptr == other.m_ptr) - return *this; - reset(other.m_ptr); - return *this; - } - lint_ptr &operator=(lint_ptr &&other) { - if (m_ptr == other.m_ptr) - return *this; - - m_ptr = other.m_ptr; - other.m_ptr = nullptr; - return *this; - } - // pointer-like access options - explicit inline operator bool() const noexcept { return m_ptr; } - inline T &operator*() const noexcept { return *m_ptr; } - inline T *operator->() const noexcept { return m_ptr; } - // pointer-like access options - inline bool operator<(const lint_ptr &vs) const noexcept { - return m_ptr < vs.m_ptr; - } - // pointer-like access options - inline bool operator==(const lint_ptr &vs) const noexcept { - return m_ptr == vs.m_ptr; - } - /** - * @brief release returns the pointer and makes this invalid while keeping - * the refcount - * @return Raw pointer - */ - T *release() noexcept { - auto ret = m_ptr; - m_ptr = nullptr; - return ret; - } -}; - class tSplitWalk { using mstring = string; using cmstring = const string; @@ -299,7 +179,6 @@ class tSplitWalk { start = 0; len = oob; } - return true; } inline mstring str() const { return s.substr(start, len); } @@ -309,12 +188,10 @@ class tSplitWalk { void replace_all(std::string &str, const std::string &from, const std::string &to) { - if (from.empty()) { + if (from.empty()) return; - } - - size_t start_pos = 0; - while ((start_pos = str.find(from, start_pos)) != std::string::npos) { + for (size_t start_pos = 0; + string::npos != (start_pos = str.find(from, start_pos));) { str.replace(start_pos, from.length(), to); start_pos += to.length(); } @@ -361,7 +238,11 @@ bool userFilter(const char *s, bool isSection) { return true; } -struct DesktopFile : public tLintRefcounted { +class DesktopFile; +using DesktopFilePtr = DesktopFile *; + +class DesktopFile { + bool IsTerminal = false, NoDisplay = false; private: @@ -395,24 +276,23 @@ struct DesktopFile : public tLintRefcounted { return GenericNameLoc; } - static lint_ptr load_visible(string &&path, - const string &lang) { - auto ret = lint_ptr(); + static DesktopFilePtr load_visible(string &&path, const string &lang) { try { - ret.reset(new DesktopFile(path, lang)); + auto ret = new DesktopFile(path, lang); if (ret->NoDisplay || !userFilter(ret->Name.c_str(), false) || !userFilter(ret->GetTranslatedName().c_str(), false)) { - - ret.reset(); + // matched conditions to hide the desktop entry? + ret = nullptr; } else { if (add_comments) { comment_pool.push_back(std::move(path)); ret->comment = (&comment_pool.back()); } } + return ret; } catch (const std::exception &) { + return DesktopFilePtr(); } - return ret; } ostream &print_comment(ostream &strm) { @@ -422,8 +302,6 @@ struct DesktopFile : public tLintRefcounted { } }; -using DesktopFilePtr = lint_ptr; - inline string safeTrans(DesktopFilePtr &node, const string &altRaw) { return node ? node->GetTranslatedName() : gettext(altRaw.c_str()); } @@ -836,15 +714,15 @@ void MenuNode::sink_in(DesktopFilePtr pDf) { } } - // catch-all - if (!added_somewhere) { + // catch-all? + if (added_somewhere) + return; - if (main_cats.empty()) - install(&submenus[OTH]); - else { - for (const auto &mk : main_cats) - install(&submenus[mk]); - } + if (main_cats.empty()) + install(&submenus[OTH]); + else { + for (const auto &mk : main_cats) + install(&submenus[mk]); } } @@ -941,8 +819,8 @@ void MenuNode::fixup2() { for (auto &s : {"Audio", "Video"}) { auto it = submenus.find(s); if (it != submenus.end() && !it->second.deco) { - it->second.deco.reset( - new DesktopFile(it->first, "", vit->second.deco->Icon)); + it->second.deco = + new DesktopFile(it->first, "", vit->second.deco->Icon); } } } @@ -1329,5 +1207,4 @@ int main(int argc, char **argv) { return EXIT_SUCCESS; } - -// vim: set sw=4 ts=4 et: +// vim: set sw=4 ts=4 et: \ No newline at end of file From 7e0bd21d66b4c4473dabcc89ba322446499eb592 Mon Sep 17 00:00:00 2001 From: Eduard Bloch Date: Fri, 4 Oct 2024 17:14:27 +0200 Subject: [PATCH 85/85] Work around GCC11 issue Found by the CI. --- src/strtest.cc | 2 +- src/yicon.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strtest.cc b/src/strtest.cc index 149f6742d..81083ec76 100644 --- a/src/strtest.cc +++ b/src/strtest.cc @@ -16,7 +16,7 @@ static const char source[] = __FILE__; #define equal(p, s) (mstring(p) == mstring(s)) -#define expect(u, s) if (++testsrun, (u) == mstring(s) && equal(u, s)) \ +#define expect(u, s) if (++testsrun, mstring(s).equals(u) && equal(u, s)) \ ++passed; else test_failed(u, s, __LINE__) // XXX: those argument ordering and purpose := strange. diff --git a/src/yicon.cc b/src/yicon.cc index 185284a79..9229b3b8e 100644 --- a/src/yicon.cc +++ b/src/yicon.cc @@ -27,7 +27,7 @@ YIcon::YIcon(upath filename) : loadedH(false), fCached(false), fPath(filename.expand()) { // don't attempt to load if icon is disabled - if (fPath == "none" || fPath == "-") + if (fPath.equals("none") || fPath.equals("-")) loadedS = loadedL = loadedH = true; }