aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--nls/C/Translation.m1
-rw-r--r--nls/fluxbox-nls.hh1
-rw-r--r--src/FbTk/FbString.cc49
-rw-r--r--src/FbTk/FbString.hh20
-rw-r--r--src/MenuCreator.cc132
-rw-r--r--src/MenuCreator.hh23
7 files changed, 210 insertions, 26 deletions
diff --git a/ChangeLog b/ChangeLog
index d6d5a94..2fa3821 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,16 @@
1 (Format: Year/Month/Day) 1 (Format: Year/Month/Day)
2Changes for 1.0rc2: 2Changes for 1.0rc2:
3*06/06/25: 3*06/06/25:
4 * Menu aware of text encodings (Simon)
5 - new menu file options:
6 [encoding] {CODESET}
7 ...
8 [endencoding]
9 - All distributions are encouraged to use these inside any
10 auto-generated menu files, so that they are independent of user
11 encoding.
12 - Encoding defaults to user's current encoding
13 MenuCreator.hh/cc FbTk/FbString.hh/cc nls/fluxbox-nls.hh C/Translation.m
4 * Fix crash when unable to convert between local and utf-8 encodings (Simon) 14 * Fix crash when unable to convert between local and utf-8 encodings (Simon)
5 FbTk/FbString.cc 15 FbTk/FbString.cc
6 * Fix DetachClient key command so new window is visible (Mark) 16 * Fix DetachClient key command so new window is visible (Mark)
diff --git a/nls/C/Translation.m b/nls/C/Translation.m
index 82ba442..999ad55 100644
--- a/nls/C/Translation.m
+++ b/nls/C/Translation.m
@@ -134,6 +134,7 @@ $set 10 #Menu
1347 Placement 1347 Placement
1358 Reload Config 1358 Reload Config
1369 Restart 1369 Restart
13710 Warning: unbalanced [encoding] tags
137 138
138$set 11 #Remember 139$set 11 #Remember
139 140
diff --git a/nls/fluxbox-nls.hh b/nls/fluxbox-nls.hh
index 4308105..0173d60 100644
--- a/nls/fluxbox-nls.hh
+++ b/nls/fluxbox-nls.hh
@@ -131,6 +131,7 @@ enum {
131 MenuPlacement = 7, 131 MenuPlacement = 7,
132 MenuReconfigure = 8, 132 MenuReconfigure = 8,
133 MenuRestart = 9, 133 MenuRestart = 9,
134 MenuErrorEndEncoding = 10,
134 135
135 RememberSet = 11, 136 RememberSet = 11,
136 RememberDecorations = 1, 137 RememberDecorations = 1,
diff --git a/src/FbTk/FbString.cc b/src/FbTk/FbString.cc
index 93f6aa7..3ed1c70 100644
--- a/src/FbTk/FbString.cc
+++ b/src/FbTk/FbString.cc
@@ -54,6 +54,8 @@ static iconv_t *iconv_convs = 0;
54static int iconv_convs[CONVSIZE]; 54static int iconv_convs[CONVSIZE];
55#endif // HAVE_ICONV 55#endif // HAVE_ICONV
56 56
57static std::string locale_codeset;
58
57/// Initialise all of the iconv conversion descriptors 59/// Initialise all of the iconv conversion descriptors
58void init() { 60void init() {
59 setlocale(LC_CTYPE, ""); 61 setlocale(LC_CTYPE, "");
@@ -65,9 +67,9 @@ void init() {
65 iconv_convs = new iconv_t[CONVSIZE]; 67 iconv_convs = new iconv_t[CONVSIZE];
66 68
67#ifdef CODESET 69#ifdef CODESET
68 std::string locale_codeset = nl_langinfo(CODESET); 70 locale_codeset = nl_langinfo(CODESET);
69#else // openbsd doesnt have this (yet?) 71#else // openbsd doesnt have this (yet?)
70 std::string locale_codeset = ""; 72 locale_codeset = "";
71 std::string locale = setlocale(LC_CTYPE, NULL); 73 std::string locale = setlocale(LC_CTYPE, NULL);
72 size_t pos = locale.find('.'); 74 size_t pos = locale.find('.');
73 if (pos != std::string::npos) 75 if (pos != std::string::npos)
@@ -229,4 +231,47 @@ bool haveUTF8() {
229 231
230}; // end namespace StringUtil 232}; // end namespace StringUtil
231 233
234StringConvertor::StringConvertor(EncodingTarget target): m_iconv((iconv_t)(-1)) {
235#ifdef HAVE_ICONV
236 if (target == ToLocaleStr)
237 m_destencoding = FbStringUtil::locale_codeset;
238 else
239 m_destencoding = "UTF-8";
240#endif
241}
242
243StringConvertor::~StringConvertor() {
244#ifdef HAVE_ICONV
245 if (m_iconv != ((iconv_t)-1))
246 iconv_close(m_iconv);
247#endif
248}
249
250bool StringConvertor::setSource(const std::string &encoding) {
251#ifdef HAVE_ICONV
252 std::string tempenc = encoding;
253 if (encoding == "")
254 tempenc = FbStringUtil::locale_codeset;
255
256 iconv_t newiconv = iconv_open(m_destencoding.c_str(), tempenc.c_str());
257 if (newiconv == ((iconv_t)(-1)))
258 return false;
259 else {
260 iconv_close(m_iconv);
261 m_iconv = newiconv;
262 return true;
263 }
264#else
265 return false;
266#endif
267}
268
269std::string StringConvertor::recode(const std::string &src) {
270#ifdef HAVE_ICONV
271 return FbStringUtil::recode(m_iconv, src);
272#else
273 return src;
274#endif
275}
276
232}; // end namespace FbTk 277}; // end namespace FbTk
diff --git a/src/FbTk/FbString.hh b/src/FbTk/FbString.hh
index 011d47a..cfa44d9 100644
--- a/src/FbTk/FbString.hh
+++ b/src/FbTk/FbString.hh
@@ -52,6 +52,26 @@ std::string FbStrToLocale(const FbString &src);
52bool haveUTF8(); 52bool haveUTF8();
53 53
54} // namespace FbStringUtil 54} // namespace FbStringUtil
55
56class StringConvertor {
57public:
58
59 enum EncodingTarget { ToFbString, ToLocaleStr };
60
61 StringConvertor(EncodingTarget target);
62 ~StringConvertor();
63
64 bool setSource(const std::string &encoding);
65 void reset() { m_iconv = ((iconv_t)(-1)); }
66
67 std::string recode(const std::string &src);
68
69private:
70 iconv_t m_iconv;
71
72 std::string m_destencoding;
73};
74
55} // namespace FbTk 75} // namespace FbTk
56 76
57#endif // FBTK_FBSTRING_HH 77#endif // FBTK_FBSTRING_HH
diff --git a/src/MenuCreator.cc b/src/MenuCreator.cc
index 2aa73ba..e33db19 100644
--- a/src/MenuCreator.cc
+++ b/src/MenuCreator.cc
@@ -55,6 +55,11 @@
55#include <iostream> 55#include <iostream>
56using namespace std; 56using namespace std;
57 57
58std::list<std::string> MenuCreator::encoding_stack;
59std::list<size_t> MenuCreator::stacksize_stack;
60
61FbTk::StringConvertor MenuCreator::m_stringconvertor(FbTk::StringConvertor::ToFbString);
62
58static void createStyleMenu(FbTk::Menu &parent, const std::string &label, 63static void createStyleMenu(FbTk::Menu &parent, const std::string &label,
59 const std::string &directory) { 64 const std::string &directory) {
60 // perform shell style ~ home directory expansion 65 // perform shell style ~ home directory expansion
@@ -131,8 +136,9 @@ class ParseItem {
131public: 136public:
132 explicit ParseItem(FbTk::Menu *menu):m_menu(menu) {} 137 explicit ParseItem(FbTk::Menu *menu):m_menu(menu) {}
133 138
134 inline void load(Parser &p) { 139 inline void load(Parser &p, FbTk::StringConvertor &m_labelconvertor) {
135 p>>m_key>>m_label>>m_cmd>>m_icon; 140 p>>m_key>>m_label>>m_cmd>>m_icon;
141 m_label.second = m_labelconvertor.recode(m_label.second);
136 } 142 }
137 inline const std::string &icon() const { return m_icon.second; } 143 inline const std::string &icon() const { return m_icon.second; }
138 inline const std::string &command() const { return m_cmd.second; } 144 inline const std::string &command() const { return m_cmd.second; }
@@ -158,20 +164,20 @@ public:
158 } 164 }
159}; 165};
160 166
161static void translateMenuItem(Parser &parse, ParseItem &item); 167static void translateMenuItem(Parser &parse, ParseItem &item, FbTk::StringConvertor &labelconvertor);
162 168
163 169
164static void parseMenu(Parser &pars, FbTk::Menu &menu) { 170static void parseMenu(Parser &pars, FbTk::Menu &menu, FbTk::StringConvertor &label_convertor) {
165 ParseItem pitem(&menu); 171 ParseItem pitem(&menu);
166 while (!pars.eof()) { 172 while (!pars.eof()) {
167 pitem.load(pars); 173 pitem.load(pars, label_convertor);
168 if (pitem.key() == "end") 174 if (pitem.key() == "end")
169 return; 175 return;
170 translateMenuItem(pars, pitem); 176 translateMenuItem(pars, pitem, label_convertor);
171 } 177 }
172} 178}
173 179
174static void translateMenuItem(Parser &parse, ParseItem &pitem) { 180static void translateMenuItem(Parser &parse, ParseItem &pitem, FbTk::StringConvertor &labelconvertor) {
175 if (pitem.menu() == 0) 181 if (pitem.menu() == 0)
176 throw string("translateMenuItem: We must have a menu in ParseItem!"); 182 throw string("translateMenuItem: We must have a menu in ParseItem!");
177 183
@@ -256,14 +262,12 @@ static void translateMenuItem(Parser &parse, ParseItem &pitem) {
256 (filelist[file_index][0] != '.') && 262 (filelist[file_index][0] != '.') &&
257 (thisfile[thisfile.length() - 1] != '~')) { 263 (thisfile[thisfile.length() - 1] != '~')) {
258 MenuCreator::createFromFile(thisfile, menu, false); 264 MenuCreator::createFromFile(thisfile, menu, false);
259 Fluxbox::instance()->saveMenuFilename(thisfile.c_str());
260 } 265 }
261 } 266 }
262 267
263 } else { 268 } else {
264 // inject this file into the current menu 269 // inject this file into the current menu
265 MenuCreator::createFromFile(newfile, menu, false); 270 MenuCreator::createFromFile(newfile, menu, false);
266 Fluxbox::instance()->saveMenuFilename(newfile.c_str());
267 } 271 }
268 272
269 safe_counter--; 273 safe_counter--;
@@ -280,7 +284,7 @@ static void translateMenuItem(Parser &parse, ParseItem &pitem) {
280 else 284 else
281 submenu->setLabel(str_label); 285 submenu->setLabel(str_label);
282 286
283 parseMenu(parse, *submenu); 287 parseMenu(parse, *submenu, labelconvertor);
284 submenu->updateMenu(); 288 submenu->updateMenu();
285 menu.insert(str_label, submenu); 289 menu.insert(str_label, submenu);
286 // save to screen list so we can delete it later 290 // save to screen list so we can delete it later
@@ -310,6 +314,10 @@ static void translateMenuItem(Parser &parse, ParseItem &pitem) {
310 } 314 }
311 } else if (str_key == "separator") { 315 } else if (str_key == "separator") {
312 menu.insert(new FbTk::MenuSeparator()); 316 menu.insert(new FbTk::MenuSeparator());
317 } else if (str_key == "encoding") {
318 MenuCreator::startEncoding(str_cmd);
319 } else if (str_key == "endencoding") {
320 MenuCreator::endEncoding();
313 } 321 }
314 else { // ok, if we didn't find any special menu item we try with command parser 322 else { // ok, if we didn't find any special menu item we try with command parser
315 // we need to attach command with arguments so command parser can parse it 323 // we need to attach command with arguments so command parser can parse it
@@ -337,11 +345,11 @@ static void translateMenuItem(Parser &parse, ParseItem &pitem) {
337} 345}
338 346
339 347
340static void parseWindowMenu(Parser &parse, FbTk::Menu &menu) { 348static void parseWindowMenu(Parser &parse, FbTk::Menu &menu, FbTk::StringConvertor &labelconvertor) {
341 349
342 ParseItem pitem(&menu); 350 ParseItem pitem(&menu);
343 while (!parse.eof()) { 351 while (!parse.eof()) {
344 pitem.load(parse); 352 pitem.load(parse, labelconvertor);
345 if (MenuCreator::createWindowMenuItem(pitem.key(), pitem.label(), menu)) 353 if (MenuCreator::createWindowMenuItem(pitem.key(), pitem.label(), menu))
346 continue; 354 continue;
347 355
@@ -349,12 +357,12 @@ static void parseWindowMenu(Parser &parse, FbTk::Menu &menu) {
349 return; 357 return;
350 } else if (pitem.key() == "submenu") { 358 } else if (pitem.key() == "submenu") {
351 FbTk::Menu *submenu = MenuCreator::createMenu(pitem.label(), menu.screenNumber()); 359 FbTk::Menu *submenu = MenuCreator::createMenu(pitem.label(), menu.screenNumber());
352 parseWindowMenu(parse, *submenu); 360 parseWindowMenu(parse, *submenu, labelconvertor);
353 submenu->updateMenu(); 361 submenu->updateMenu();
354 menu.insert(pitem.label(), submenu); 362 menu.insert(pitem.label(), submenu);
355 363
356 } else { // try non window menu specific stuff 364 } else { // try non window menu specific stuff
357 translateMenuItem(parse, pitem); 365 translateMenuItem(parse, pitem, labelconvertor);
358 } 366 }
359 } 367 }
360} 368}
@@ -373,11 +381,11 @@ FbTk::Menu *MenuCreator::createMenu(const std::string &label, int screen_number)
373 return menu; 381 return menu;
374} 382}
375 383
376bool getStart(FbMenuParser &parser, std::string &label) { 384bool getStart(FbMenuParser &parser, std::string &label, FbTk::StringConvertor &labelconvertor) {
377 ParseItem pitem(0); 385 ParseItem pitem(0);
378 while (!parser.eof()) { 386 while (!parser.eof()) {
379 // get first begin line 387 // get first begin line
380 pitem.load(parser); 388 pitem.load(parser, labelconvertor);
381 if (pitem.key() == "begin") { 389 if (pitem.key() == "begin") {
382 break; 390 break;
383 } 391 }
@@ -391,19 +399,22 @@ bool getStart(FbMenuParser &parser, std::string &label) {
391 399
392FbTk::Menu *MenuCreator::createFromFile(const std::string &filename, int screen_number, bool require_begin) { 400FbTk::Menu *MenuCreator::createFromFile(const std::string &filename, int screen_number, bool require_begin) {
393 std::string real_filename = FbTk::StringUtil::expandFilename(filename); 401 std::string real_filename = FbTk::StringUtil::expandFilename(filename);
402 Fluxbox::instance()->saveMenuFilename(real_filename.c_str());
403
394 FbMenuParser parser(real_filename); 404 FbMenuParser parser(real_filename);
395 if (!parser.isLoaded()) 405 if (!parser.isLoaded())
396 return 0; 406 return 0;
397 407
398 Fluxbox::instance()->saveMenuFilename(real_filename.c_str());
399
400 std::string label; 408 std::string label;
401 if (require_begin && !getStart(parser, label)) 409 if (require_begin && !getStart(parser, label, m_stringconvertor))
402 return 0; 410 return 0;
403 411
404 FbTk::Menu *menu = createMenu(label, screen_number); 412 FbTk::Menu *menu = createMenu(label, screen_number);
405 if (menu != 0) 413 if (menu != 0) {
406 parseMenu(parser, *menu); 414 startFile();
415 parseMenu(parser, *menu, m_stringconvertor);
416 endFile();
417 }
407 418
408 return menu; 419 return menu;
409} 420}
@@ -418,10 +429,13 @@ bool MenuCreator::createFromFile(const std::string &filename,
418 return false; 429 return false;
419 430
420 std::string label; 431 std::string label;
421 if (require_begin && !getStart(parser, label)) 432 if (require_begin && !getStart(parser, label, m_stringconvertor))
422 return false; 433 return false;
423 434
424 parseMenu(parser, inject_into); 435 startFile();
436 parseMenu(parser, inject_into, m_stringconvertor);
437 endFile();
438
425 return true; 439 return true;
426} 440}
427 441
@@ -436,10 +450,13 @@ bool MenuCreator::createWindowMenuFromFile(const std::string &filename,
436 450
437 std::string label; 451 std::string label;
438 452
439 if (require_begin && !getStart(parser, label)) 453 if (require_begin && !getStart(parser, label, m_stringconvertor))
440 return false; 454 return false;
441 455
442 parseWindowMenu(parser, inject_into); 456 startFile();
457 parseWindowMenu(parser, inject_into, m_stringconvertor);
458 endFile();
459
443 return true; 460 return true;
444} 461}
445 462
@@ -580,3 +597,70 @@ bool MenuCreator::createWindowMenuItem(const std::string &type,
580 597
581 return true; 598 return true;
582} 599}
600
601/* push our encoding-stacksize onto the stack */
602void MenuCreator::startFile() {
603 if (encoding_stack.empty())
604 m_stringconvertor.setSource("");
605 stacksize_stack.push_back(encoding_stack.size());
606}
607
608/**
609 * Pop necessary encodings from the stack
610 * (and endEncoding the final one) to our matching encoding-stacksize.
611 */
612void MenuCreator::endFile() {
613 size_t target_size = stacksize_stack.back();
614 size_t curr_size = encoding_stack.size();
615
616 if (target_size != curr_size) {
617 _FB_USES_NLS;
618 cerr<<_FB_CONSOLETEXT(Menu, ErrorEndEncoding, "Warning: unbalanced [encoding] tags", "User menu file had unbalanced [encoding] tags")<<endl;
619 }
620
621 for (; curr_size > (target_size+1); --curr_size)
622 encoding_stack.pop_back();
623
624 if (curr_size == (target_size+1))
625 endEncoding();
626
627 stacksize_stack.pop_back();
628}
629
630/**
631 * Push the encoding onto the stack, and make it active.
632 */
633void MenuCreator::startEncoding(const std::string &encoding) {
634 // we push it regardless of whether it's valid, since we
635 // need to stay balanced with the endEncodings.
636 encoding_stack.push_back(encoding);
637
638 // this won't change if it doesn't succeed
639 m_stringconvertor.setSource(encoding);
640}
641
642/**
643 * Pop the encoding from the stack, unless we are at our stacksize limit.
644 * Restore the previous (valid) encoding.
645 */
646void MenuCreator::endEncoding() {
647 size_t min_size = stacksize_stack.back();
648 if (encoding_stack.size() <= min_size) {
649 // TODO: nls
650 _FB_USES_NLS;
651 cerr<<_FB_CONSOLETEXT(Menu, ErrorEndEncoding, "Warning: unbalanced [encoding] tags", "User menu file had unbalanced [encoding] tags")<<endl;
652 return;
653 }
654
655 encoding_stack.pop_back();
656 m_stringconvertor.reset();
657
658 std::list<std::string>::reverse_iterator it = encoding_stack.rbegin();
659 std::list<std::string>::reverse_iterator it_end = encoding_stack.rend();
660 while (it != it_end && !m_stringconvertor.setSource(*it))
661 ++it;
662
663 if (it == it_end)
664 m_stringconvertor.setSource("");
665}
666
diff --git a/src/MenuCreator.hh b/src/MenuCreator.hh
index 66e7408..927b564 100644
--- a/src/MenuCreator.hh
+++ b/src/MenuCreator.hh
@@ -23,7 +23,10 @@
23#ifndef MENUCREATOR_HH 23#ifndef MENUCREATOR_HH
24#define MENUCREATOR_HH 24#define MENUCREATOR_HH
25 25
26#include "FbTk/FbString.hh"
27
26#include <string> 28#include <string>
29#include <list>
27 30
28namespace FbTk { 31namespace FbTk {
29class Menu; 32class Menu;
@@ -44,6 +47,26 @@ public:
44 static bool createWindowMenuItem(const std::string &type, const std::string &label, 47 static bool createWindowMenuItem(const std::string &type, const std::string &label,
45 FbTk::Menu &inject_into); 48 FbTk::Menu &inject_into);
46 49
50 /**
51 * Encoding-related helpers (encoding, aka codeset)
52 */
53
54 // Files are guaranteed to be "balanced", unlike user-created [encoding] tags.
55 static void startFile();
56 static void endFile();
57
58 static void startEncoding(const std::string &encoding);
59 static void endEncoding();
60
61private:
62 // stack of encodings
63 static std::list<std::string> encoding_stack;
64 // stack of ints, representing stack size as each file is entered
65 // (a file should never end more encodings than it starts)
66 static std::list<size_t> stacksize_stack;
67
68 static FbTk::StringConvertor m_stringconvertor;
69
47}; 70};
48 71
49#endif // MENUCREATOR_HH 72#endif // MENUCREATOR_HH