1 // FbDesk.cc
2 // Copyright (c) 2002 - 2006 Henrik Kinnunen (fluxgen at users.sourceforge.net)
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a
5 // copy of this software and associated documentation files (the "Software"),
6 // to deal in the Software without restriction, including without limitation
7 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 // and/or sell copies of the Software, and to permit persons to whom the
9 // Software is furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 // DEALINGS IN THE SOFTWARE.
21 
22 // $Id$
23 
24 #include "FbDesk.hh"
25 
26 #include "InputField.hh"
27 #include "IntResMenuItem.hh"
28 
29 #include "FbTk/App.hh"
30 #include "FbTk/Font.hh"
31 #include "FbTk/EventManager.hh"
32 #include "FbTk/SimpleCommand.hh"
33 #include "FbTk/StringUtil.hh"
34 #include "FbTk/XrmDatabaseHelper.hh"
35 #include "FbTk/MenuSeparator.hh"
36 
37 #include <iostream>
38 #include <fstream>
39 #include <algorithm>
40 #include <unistd.h>
41 #include <cstdio>
42 
43 using namespace std;
44 using namespace FbTk;
45 
46 
47 namespace FbDesk {
48 
FbDesk(const char * config_filename)49 FbDesk::FbDesk(const char *config_filename):
50     m_font("fixed"),
51     m_selected_icon(0),
52     m_last_icon(0),
53     m_config_filename(config_filename ? config_filename : ""),
54     m_button_pos_x(32),
55     m_button_pos_y(32),
56     m_menutheme(0), // menu theme on screen 0
57     m_imagectrl(0), // image control on screen 0
58     m_iconmenu(m_menutheme, m_imagectrl),
59     m_inputfield(0, m_menutheme.frameFont(), m_menutheme.frameTextGC().gc(),
60                  m_menutheme.frameTexture().color()),
61     m_textcolor("black", 0),
62     m_resmanager(0, false),
63     m_themefile(m_resmanager, "", "session.styleFile", "Session.StyleFile"),
64     m_doubleclick_interval(m_resmanager, 200, "fbdesk.doubleClickInterval", "FbDesk.DoubleClickInterval"),
65     m_iconfile(m_resmanager, "~/.fluxbox/fbdesk.icons", "fbdesk.iconFile", "FbDesk.IconFile"),
66     m_fontname(m_resmanager, "fixed", "fbdesk.font", "FbDesk.Font"),
67     m_textcolorname(m_resmanager, "black", "fbdesk.textColor", "FbDesk.TextColor"),
68     m_textbackgroundname(m_resmanager, "white", "fbdesk.textBackground", "FbDesk.TextBackground"),
69     m_grid_snap_x(m_resmanager, 5, "fbdesk.snapX", "FbDesk.SnapX"),
70     m_grid_snap_y(m_resmanager, 5, "fbdesk.snapY", "FbDesk.SnapY"),
71     m_textplacement(m_resmanager, Icon::TEXTPLACE_BOTTOM, "fbdesk.textPlacement", "FbDesk.TextPlacement"),
72     m_text_alpha(m_resmanager, 0, "fbdesk.textAlpha", "FbDesk.TextAlpha"),
73     m_icon_alpha(m_resmanager, 255, "fbdesk.iconAlpha", "FbDesk.IconAlpha"),
74     m_lock_positions(m_resmanager, false, "fbdesk.lockPositions", "FbDesk.LockPositions"),
75     m_icon_config(m_menutheme.screenNum()) {
76 
77     m_icon_config.setFont(m_font);
78     reloadConfig();
79     setupIconMenu();
80 
81     Screen *scr = ScreenOfDisplay(FbTk::App::instance()->display(), 0);
82     m_screen_width = WidthOfScreen(scr);
83     m_screen_height = HeightOfScreen(scr);
84 
85 
86 }
87 
~FbDesk()88 FbDesk::~FbDesk() {
89     // save icon data
90     saveIcons(*m_iconfile);
91     // save to default resource file
92     m_resmanager.save( 0 );
93 
94     // delete all icons
95     deleteIcons();
96 }
97 
98 
loadTheme()99 void FbDesk::loadTheme() {
100     cerr<<"loading style: " << *m_themefile <<endl;
101 
102     if (!FbTk::ThemeManager::instance().load(*m_themefile, ""))
103         cerr<<"Failed to load style: "<< *m_themefile<<endl;
104 
105     // update for new theme
106     m_iconmenu.reconfigure();
107 }
108 
109 /**
110    Destroy old icons and reload icons data and recreate icons
111 */
loadIcons(const std::string & config_filename)112 bool FbDesk::loadIcons(const std::string &config_filename) {
113     ifstream iconfile(StringUtil::expandFilename(config_filename).c_str());
114 
115     if (!m_iconlist.empty()) {
116         // delete old icons
117         deleteIcons();
118     }
119 
120     vector<int> iconpos;
121 
122     while (iconfile && !iconfile.eof()) {
123         string line;
124         getline(iconfile, line);
125         if (line.compare(0, strlen("[Desktop Entry]"),
126                          "[Desktop Entry]" )) {
127             continue;
128         }
129 
130         int icon_x = 0, icon_y = 0; // position of icon
131         string command;       // command for icon
132         string label;         // icon label
133         string icon_filename; // icon filename
134 
135         while (!iconfile.eof()) {
136             line = "";
137             getline(iconfile, line); // get next line
138 
139             //remove any whitespace in the begining
140             FbTk::StringUtil::removeFirstWhitespace(line);
141 
142             // get first position after option
143             size_t first_pos = line.find_first_of("=");
144 
145             string option;
146             if (first_pos != string::npos)
147                 option = line.substr(0, first_pos);
148             else
149                 option = line;
150 
151             if (option.size() == 0)
152                 continue;
153 
154             // get option value
155             string option_value;
156             if (first_pos != string::npos && first_pos != line.size() - 1) {
157                 option_value = static_cast<const char *>(line.c_str() + first_pos + 1);
158             }
159 
160             FbTk::StringUtil::removeFirstWhitespace(option);
161             FbTk::StringUtil::removeTrailingWhitespace(option);
162 
163             if (option == "Name") {
164                 label = option_value;
165             } else if (option == "Exec") {
166                 command = option_value;
167             } else if (option == "Icon") {
168                 icon_filename = option_value;
169             } else if (option == "Pos") {
170                 sscanf(option_value.c_str(), "%d %d", &icon_x, &icon_y);
171             } else if (option == "[end]") {
172                 if (command.size() == 0 && icon_filename.size() == 0
173                     && label.size() == 0) {
174                     cerr<<"Warning: All options for icon are empty. Icon not added."<<endl;
175                     continue;
176                 }
177 
178                 // create new icon from current settings
179                 Icon *i = new Icon(StringUtil::expandFilename(icon_filename).c_str(),
180                                    command, label);
181                 // add to event manager
182                 FbTk::EventManager::instance()->add(*this, i->iconWindow());
183                 FbTk::EventManager::instance()->add(*this, i->labelWindow());
184                 // save position
185                 iconpos.push_back(icon_x);
186                 iconpos.push_back(icon_y);
187                 // add it to list
188                 m_iconlist.push_back(i);
189                 // clear options
190                 icon_filename = label = command = "";
191                 icon_x = icon_y = 0;
192             } // end if
193 
194         } // end while
195 
196     } // end while
197 
198     // show all icons
199     IconList::iterator icon_it = m_iconlist.begin();
200     IconList::iterator icon_it_end = m_iconlist.end();
201     for (int i = 0; icon_it != icon_it_end; ++icon_it, i += 2) {
202         (*icon_it)->show();
203         (*icon_it)->move(iconpos[i], iconpos[i+1]);
204     }
205 
206     // create at lest one icon
207     if (m_iconlist.empty()) {
208         cerr<<"Warning: Empty icon file, creating one icon."<<endl;
209         createIcon();
210     }
211 
212     return true;
213 }
214 
handleEvent(XEvent & event)215 void FbDesk::handleEvent(XEvent &event) {
216     switch (event.type) {
217     case ClientMessage:
218         clientMessageEvent(event.xclient);
219         break;
220     default:
221         break;
222     }
223 }
224 
buttonPressEvent(XButtonEvent & event)225 void FbDesk::buttonPressEvent(XButtonEvent &event) {
226     m_selected_icon = findIcon(event.window);
227     if (!m_selected_icon)
228         return;
229     m_selected_icon->raise();
230     // save last mouse position
231     m_button_pos_x = event.x_root;
232     m_button_pos_y = event.y_root;
233 
234 }
235 
buttonReleaseEvent(XButtonEvent & event)236 void FbDesk::buttonReleaseEvent(XButtonEvent &event) {
237     static int button_time = 0;
238     if (m_selected_icon == 0)
239         return;
240 
241     m_last_icon = m_selected_icon;
242 
243     if (event.button == 3) {
244         // show menu
245         m_iconmenu.raise();
246         m_iconmenu.move(event.x_root, event.y_root);
247         m_iconmenu.show();
248 
249     } else if (event.button == 1) {
250         // did we doubleclick?
251         if (event.time - button_time <= *m_doubleclick_interval) {
252             execute(m_selected_icon->command());
253         }
254 
255         // don't show the icon over another window and make sure it's visible
256         m_selected_icon->lower();
257         int new_x = -1, new_y = -1;
258         if (m_selected_icon->x() < 0)
259             new_x = 0;
260         if (m_selected_icon->x() >= m_screen_width)
261             new_x = m_screen_width - m_selected_icon->width();
262 
263         if (m_selected_icon->y() < 0)
264             new_y = 0;
265         if (m_selected_icon->y() >= m_screen_height)
266             new_y = m_screen_height - m_selected_icon->height();
267 
268         if (new_x >= 0)
269             m_selected_icon->move(new_x, m_selected_icon->y());
270         if (new_y >= 0)
271             m_selected_icon->move(m_selected_icon->x(), new_y);
272         // update label background
273         m_selected_icon->redrawLabel();
274     }
275 
276     m_selected_icon = 0; // unselect icon
277 
278     button_time = event.time; // save last timestamp
279     saveIcons(*m_iconfile);
280 }
281 
exposeEvent(XExposeEvent & event)282 void FbDesk::exposeEvent(XExposeEvent &event) {
283     Icon *exposed_icon = findIcon( event.window );
284     if (exposed_icon != 0)
285         exposed_icon->update();
286 }
287 
motionNotifyEvent(XMotionEvent & event)288 void FbDesk::motionNotifyEvent(XMotionEvent &event) {
289 
290     // need a selected icon first, and not locked position
291     if (*m_lock_positions || m_selected_icon == 0)
292         return;
293 
294     Display *disp = FbTk::App::instance()->display();
295     Screen *scr = ScreenOfDisplay(disp, 0);
296 
297     // calculate new position, using inside pos and last mouse pos
298 
299     // snap to grid
300     if (*m_grid_snap_x == 0)
301         *m_grid_snap_x = 1;
302 
303     if (*m_grid_snap_y == 0)
304         *m_grid_snap_y = 1;
305 
306     event.x_root /= *m_grid_snap_x;
307     event.x_root *= *m_grid_snap_x;
308 
309     event.y_root /= *m_grid_snap_y;
310     event.y_root *= *m_grid_snap_y;
311 
312     int new_x = m_selected_icon->x() - m_button_pos_x + event.x_root;
313     int new_y = m_selected_icon->y() - m_button_pos_y + event.y_root;
314 
315     // set the last known position of mouse
316     m_button_pos_x = event.x_root;
317     m_button_pos_y = event.y_root;
318 
319     // Make sure the icon is inside visible area
320     if (new_x < 0)
321         new_x = 0;
322     else if (new_x >= m_screen_width)
323         new_x = m_screen_width - 1;
324 
325     if (new_y < 0)
326         new_y = 0;
327     else if (new_y >= m_screen_height)
328         new_y = m_screen_height - 1;
329 
330     // move the icon the new position
331     if (m_selected_icon->x() != new_x ||
332         m_selected_icon->y() != new_y) {
333         m_selected_icon->move(new_x, new_y);
334     }
335 }
336 
clientMessageEvent(XClientMessageEvent & event)337 void FbDesk::clientMessageEvent(XClientMessageEvent &event) {
338     // TODO drag'n'drop
339 }
340 
execute(const std::string & commando) const341 void FbDesk::execute(const std::string &commando) const {
342     if (! fork()) {
343         string displaystring("DISPLAY=");
344         displaystring += DisplayString(FbTk::App::instance()->display());
345         setsid();
346         putenv((char *)displaystring.c_str());
347         execl("/bin/sh", "/bin/sh", "-c", commando.c_str(), 0);
348         exit(0);
349     }
350 }
351 
findIcon(Window w)352 Icon *FbDesk::findIcon(Window w) {
353     IconList::iterator it = m_iconlist.begin();
354     IconList::iterator it_end = m_iconlist.end();
355     for (; it != it_end; ++it) {
356         if ((*it)->iconWindow() == w ||
357             (*it)->labelWindow() == w) {
358             return (*it);
359         }
360     }
361 
362     return 0; // we didn't find any icon
363 }
364 
saveIcons(const std::string & filename) const365 bool FbDesk::saveIcons(const std::string &filename) const {
366     string realfilename(StringUtil::expandFilename(filename));
367     ofstream ofile(realfilename.c_str());
368     if (!ofile) {
369         cerr<<"Warning: Failed to save icons to file: "<<realfilename<<endl;
370         return false; // faild to open file
371     }
372     IconList::const_iterator it = m_iconlist.begin();
373     IconList::const_iterator it_end = m_iconlist.end();
374     for (; it != it_end; ++it) {
375         ofile<<"[Desktop Entry]"<<endl
376              <<"Name="<<(*it)->label()<<endl
377              <<"Exec="<<(*it)->command()<<endl
378              <<"Icon="<<(*it)->imageFilename()<<endl
379              <<"Pos= "<<(*it)->x()<<" "<<(*it)->y()<<endl
380              <<"[end]"<<endl<<endl;
381     }
382 
383     return true;
384 }
385 
deleteIcons()386 void FbDesk::deleteIcons() {
387     // destroy iconlist
388     while (!m_iconlist.empty()) {
389         FbTk::EventManager::instance()->remove(m_iconlist.back()->iconWindow());
390         FbTk::EventManager::instance()->remove(m_iconlist.back()->labelWindow());
391 
392         delete m_iconlist.back();
393         m_iconlist.pop_back();
394     }
395 }
396 
reloadConfig()397 void FbDesk::reloadConfig() {
398 
399     m_resmanager.load(StringUtil::expandFilename(m_config_filename).c_str());
400     // if style file is empty read fluxbox style
401     if ( (*m_themefile).empty() ) {
402         string filename(StringUtil::expandFilename("~/.fluxbox/init").c_str());
403         ResourceManager rm(filename.c_str(), false);
404         rm.addResource( m_themefile );
405         rm.load(filename.c_str());
406     }
407 
408     m_textcolor.setFromString(m_textcolorname->c_str(), 0);
409     if (!m_text_background_color.
410         setFromString(m_textbackgroundname->c_str(), 0)) {
411         m_text_background_color.setFromString("white", 0);
412     }
413 
414     // setup icon values
415     m_icon_config.setTextColor(m_textcolor);
416     m_icon_config.setTextBackground(m_text_background_color);
417     m_icon_config.setTextPlacement(*m_textplacement);
418     m_icon_config.setTextAlpha(*m_text_alpha);
419     m_icon_config.setIconAlpha(*m_icon_alpha);
420 
421     if (*m_textplacement == Icon::TEXTPLACE_LEFT ||
422         *m_textplacement == Icon::TEXTPLACE_RIGHT)
423         m_font.rotate(90);
424     else
425         m_font.rotate(0);
426 
427     loadTheme();
428     loadIcons(*m_iconfile); // reload icons
429 }
430 
createIcon()431 void FbDesk::createIcon() {
432     // create a new icon where we last pressed
433     Icon *ico = new Icon("", "", "default");
434     FbTk::EventManager::instance()->add(*this, ico->iconWindow());
435     FbTk::EventManager::instance()->add(*this, ico->labelWindow());
436     ico->move(m_button_pos_x, m_button_pos_y);
437     ico->show();
438     m_iconlist.push_back(ico);
439     m_selected_icon = 0;
440 }
441 
deleteLastIcon()442 void FbDesk::deleteLastIcon() {
443     if (m_last_icon != 0 &&
444         find(m_iconlist.begin(), m_iconlist.end(), m_last_icon) != m_iconlist.end()) {
445         m_iconlist.remove(m_last_icon);
446         delete m_last_icon;
447         m_last_icon = 0;
448     }
449 }
450 
setIconCommand()451 void FbDesk::setIconCommand() {
452     m_iconmenu.hide();
453     m_inputfield.setTitle("Set Command");
454     if (m_last_icon != 0 &&
455         find(m_iconlist.begin(), m_iconlist.end(), m_last_icon) != m_iconlist.end()) {
456         m_inputfield.setText(m_last_icon->command());
457     }
458 
459     m_inputfield.setOnEnter(new FbTk::SimpleCommand<FbDesk>(*this, &FbDesk::setCommandFromInput));
460     m_inputfield.show();
461     m_inputfield.move(m_button_pos_x, m_button_pos_y);
462     m_inputfield.raise();
463 }
464 
setIconLabel()465 void FbDesk::setIconLabel() {
466     m_iconmenu.hide();
467 
468     m_inputfield.setTitle("Set Label");
469     if (m_last_icon != 0 &&
470         find(m_iconlist.begin(), m_iconlist.end(), m_last_icon) != m_iconlist.end()) {
471         m_inputfield.setText(m_last_icon->label());
472     }
473 
474     m_inputfield.setOnEnter(new FbTk::SimpleCommand<FbDesk>(*this, &FbDesk::setLabelFromInput));
475     m_inputfield.show();
476     m_inputfield.move(m_button_pos_x, m_button_pos_y);
477     m_inputfield.raise();
478 }
479 
setLabelFromInput()480 void FbDesk::setLabelFromInput() {
481     if (m_last_icon != 0 &&
482         find(m_iconlist.begin(), m_iconlist.end(), m_last_icon) != m_iconlist.end()) {
483         m_last_icon->setLabel(m_inputfield.text());
484         saveIcons(*m_iconfile);
485     }
486     m_inputfield.hide();
487 }
488 
setCommandFromInput()489 void FbDesk::setCommandFromInput() {
490     if (m_last_icon != 0 &&
491         find(m_iconlist.begin(), m_iconlist.end(), m_last_icon) != m_iconlist.end()) {
492         m_last_icon->setCommand(m_inputfield.text());
493         saveIcons(*m_iconfile);
494     }
495     m_inputfield.hide();
496 }
497 
498 
499 class ToggleMenuItem:public MenuItem {
500 public:
ToggleMenuItem(const char * label,bool & val)501     explicit ToggleMenuItem(const char *label,
502                             bool &val ):
503         MenuItem(label),
504         m_value( val ) {
505         setToggleItem(true);
506     }
click(int button,int time)507     void click(int button, int time) {
508         setSelected(!m_value);
509         FbTk::MenuItem::click(button, time);
510     }
511 
setSelected(bool val)512     void setSelected(bool val) {
513         m_value = val;
514     }
isSelected() const515     bool isSelected() const {
516         return m_value;
517     }
518 
519 private:
520     bool &m_value;
521 };
522 
setupIconMenu()523 void FbDesk::setupIconMenu() {
524     using namespace FbTk;
525     // setup menu items
526     typedef RefCount<Command> CommandRef;
527     //    RefCount<Command> show_iconbrowser(new SimpleCommand<IconBrowser>(m_iconbrowser, &IconBrowser::show));
528     typedef SimpleCommand<FbDesk> FbDeskCmd;
529     CommandRef new_icon(new FbDeskCmd(*this, &FbDesk::createIcon));
530     CommandRef del_last_icon(new FbDeskCmd(*this, &FbDesk::deleteLastIcon));
531     CommandRef set_command(new FbDeskCmd(*this, &FbDesk::setIconCommand));
532     CommandRef set_label(new FbDeskCmd(*this, &FbDesk::setIconLabel));
533     CommandRef reload_style(new FbDeskCmd(*this, &FbDesk::reloadConfig));
534     CommandRef exit_fbdesk(new SimpleCommand<App>(*App::instance(), &App::end));
535     //        select_icon_image_hide(select_icon_macro);
536 
537     m_iconmenu.setLabel("Icon menu");
538 
539     m_iconmenu.insert("Set command", set_command);
540     m_iconmenu.insert("Set label", set_label);
541     m_iconmenu.insert(new FbTk::MenuSeparator());
542     m_iconmenu.insert("New icon", new_icon);
543     m_iconmenu.insert("Delete icon", del_last_icon);
544     m_iconmenu.insert(new FbTk::MenuSeparator());
545     // setup alpha menu
546     FbTk::MenuItem *item = new IntResMenuItem("Text alpha", m_text_alpha,
547                                               0, 255,
548                                               m_iconmenu);
549     CommandRef update_alpha(new FbTk::SimpleCommand<FbDesk>(*this, &FbDesk::updateAlpha));
550     item->setCommand(update_alpha);
551     m_iconmenu.insert(item);
552     item = new IntResMenuItem("Icon alpha", m_icon_alpha,
553                               0, 255,
554                               m_iconmenu);
555     item->setCommand(update_alpha);
556     m_iconmenu.insert(item);
557     m_iconmenu.insert("Reload config", reload_style);
558     m_iconmenu.insert(new FbTk::MenuSeparator());
559     m_iconmenu.insert(new ToggleMenuItem("Lock positions", *m_lock_positions) );
560     m_iconmenu.insert(new FbTk::MenuSeparator());
561     m_iconmenu.insert("Exit FbDesk", exit_fbdesk);
562     //    m_iconmenu.insert("Select icon image", select_icon_image_hide);
563     m_iconmenu.reconfigure(); // update graphics
564 }
565 
updateAlpha()566 void FbDesk::updateAlpha() {
567     m_resmanager.save(StringUtil::expandFilename(m_config_filename).c_str(),
568                       StringUtil::expandFilename(m_config_filename).c_str()); // merge
569     m_icon_config.setTextAlpha(*m_text_alpha);
570     m_icon_config.setIconAlpha(*m_icon_alpha);
571     updateIcons();
572 }
573 
updateIcons()574 void FbDesk::updateIcons() {
575     for_each(m_iconlist.begin(),
576              m_iconlist.end(),
577              mem_fun(&Icon::update));
578 }
579 
580 }; // end namespace FbDesk
581 
582 namespace FbTk {
583 
584 template <>
setFromString(const char * str)585 void Resource<int>::setFromString(const char *str) {
586     sscanf(str, "%d", &*(*this));
587 }
588 
589 template <>
getString() const590 std::string Resource<int>::getString() const {
591     char strval[256];
592     sprintf(strval, "%d", *(*this));
593     return std::string(strval);
594 }
595 
596 template <>
setFromString(const char * str)597 void Resource<std::string>::setFromString(const char *str) {
598     *(*this) = (str ? str : "");
599 }
600 
601 template <>
getString() const602 std::string Resource<std::string>::getString() const {
603     return (*this)->c_str();
604 }
605 
606 
607 
608 template <>
getString() const609 std::string Resource<FbDesk::Icon::TextPlacement>::getString() const {
610     switch (*(*this)) {
611     case FbDesk::Icon::TEXTPLACE_LEFT:
612         return "Left";
613     case FbDesk::Icon::TEXTPLACE_RIGHT:
614         return "Right";
615     case FbDesk::Icon::TEXTPLACE_TOP:
616         return "Top";
617     case FbDesk::Icon::TEXTPLACE_BOTTOM:
618         return "Bottom";
619     }
620     return "Bottom";
621 
622 }
623 
624 template <>
setFromString(const char * str)625 void Resource<FbDesk::Icon::TextPlacement>::setFromString(const char *str) {
626     if (strcmp("Left", str) == 0) {
627         *(*this) = FbDesk::Icon::TEXTPLACE_LEFT;
628     } else if (strcmp("Right", str) == 0) {
629         *(*this) = FbDesk::Icon::TEXTPLACE_RIGHT;
630     } else if (strcmp("Top", str) == 0)
631         *(*this) = FbDesk::Icon::TEXTPLACE_TOP;
632     else  if (strcmp("Bottom", str) == 0)
633         *(*this) = FbDesk::Icon::TEXTPLACE_BOTTOM;
634     else
635         *(*this) = FbDesk::Icon::TEXTPLACE_BOTTOM;
636 }
637 
638 template<>
639 std::string FbTk::Resource<bool>::
getString() const640 getString() const {
641     return std::string(**this == true ? "true" : "false");
642 }
643 
644 
645 template<>
646 void FbTk::Resource<bool>::
setFromString(char const * strval)647 setFromString(char const *strval) {
648     *this = (bool)!strcasecmp(strval, "true");
649 }
650 
651 } //end namespace FbTk
652