Index: src/ToolFactory.cc =================================================================== --- src/ToolFactory.cc (Revision 3927) +++ src/ToolFactory.cc (Arbeitskopie) @@ -30,9 +30,9 @@ #include "IconbarTool.hh" #include "WorkspaceNameTool.hh" #include "ArrowButton.hh" +#include "RunTool.hh" // Themes -#include "IconbarTheme.hh" #include "WorkspaceNameTheme.hh" #include "ButtonTheme.hh" @@ -78,9 +78,11 @@ m_button_theme(new ButtonTheme(screen.screenNumber(), "toolbar.button", "Toolbar.Button", "toolbar.clock", "Toolbar.Clock")), m_systray_theme(new ButtonTheme(screen.screenNumber(), "toolbar.systray", "Toolbar.Systray", - "toolbar.clock", "Toolbar.Systray")), + "toolbar.clock", "Toolbar.Clock")), m_workspace_theme(new WorkspaceNameTheme(screen.screenNumber(), "toolbar.workspace", "Toolbar.Workspace")), - m_iconbar_theme(screen.screenNumber(), "toolbar.iconbar", "Toolbar.Iconbar") { + m_iconbar_theme(screen.screenNumber(), "toolbar.iconbar", "Toolbar.Iconbar"), + m_run_theme(new ButtonTheme(screen.screenNumber(), "toolbar.run", "Toolbar.Run", + "toolbar.clock", "Toolbar.Clock")) { } @@ -100,6 +102,8 @@ item = witem; } else if (name == "iconbar") { item = new IconbarTool(parent, m_iconbar_theme, screen(), tbar.menu()); + } else if (name == "run") { + item = new RunTool(parent, *m_run_theme, screen()); } else if (name == "systemtray") { item = new SystemTray(parent, dynamic_cast(*m_systray_theme), screen()); } else if (name == "clock") { @@ -111,7 +115,7 @@ if (*cmd == 0) // we need a command return 0; - // TODO maybe direction of arrows should depend on toolbar layout ? + // TODO maybe direction of arrows should depend on toolbar layout ? ArrowButton::Type arrow_type = ArrowButton::LEFT; if (name == "nextworkspace") arrow_type = ArrowButton::RIGHT; @@ -134,7 +138,7 @@ ArrowButton::Type arrow_type = ArrowButton::LEFT; if (name == "nextwindow") arrow_type = ArrowButton::RIGHT; - + ArrowButton *win = new ArrowButton(arrow_type, parent, 0, 0, button_size, button_size); @@ -153,6 +157,7 @@ void ToolFactory::updateThemes() { m_clock_theme.setAntialias(screen().antialias()); + m_run_theme->setAntialias(screen().antialias()); m_iconbar_theme.setAntialias(screen().antialias()); m_button_theme->setAntialias(screen().antialias()); m_workspace_theme->setAntialias(screen().antialias()); Index: src/RunTool.hh =================================================================== --- src/RunTool.hh (Revision 0) +++ src/RunTool.hh (Revision 0) @@ -0,0 +1,92 @@ +// RunNameTool.hh +// Copyright (c) 2005 Mathias Gumz (akira at fluxbox dot org) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +// $Id: Exp $ + +#ifndef RUNTOOL_HH +#define RUNTOOL_HH + +#include "ToolbarItem.hh" +#include "RunBox.hh" +#include "CommandParser.hh" + +#include "FbTk/Observer.hh" +#include "FbTk/Resource.hh" + +class BScreen; +class ToolTheme; + +class RunTool: public ToolbarItem, CommandFactory, FbTk::Observer { +public: + + enum WheelMode { + + OFF, ///< no wheeling + ON, ///< wheel to next/prev workspace + WORKSPACE = ON, ///< wheel to next/prev workspace + SCREEN, ///< in perfect harmony with desktop-wheeling + HISTORY ///< wheel to next/prev historyitem + }; + + RunTool(const FbTk::FbWindow &parent, ToolTheme &theme, + BScreen &screen); + virtual ~RunTool(); + + void move(int x, int y); + void resize(unsigned int width, unsigned int height); + void moveResize(int x, int y, + unsigned int width, unsigned int height); + + void show(); + void hide(); + unsigned int width() const; + unsigned int height() const; + unsigned int borderWidth() const; + + void update(FbTk::Subject *subj); + RunBox &button() { return m_box; } + const RunBox &button() const { return m_box; } + + WheelMode wheelMode() const { return *m_wheel_mode; } + + const BScreen& screen() const { return m_screen; } + + ///< CommandParser code + FbTk::Command *stringToCommand(const std::string &command, + const std::string &arguments); + +private: + void renderTheme(unsigned char alpha = 0); + void updateSizing(); + + RunBox m_box; + ToolTheme &m_theme; + BScreen &m_screen; + Pixmap m_pixmap; + + FbTk::Resource m_history_file; + FbTk::Resource m_width; + FbTk::Resource m_wheel_mode; + FbTk::Resource m_padding; +}; + +#endif // RUNTOOL_HH + Index: src/ButtonTheme.cc =================================================================== --- src/ButtonTheme.cc (Revision 3927) +++ src/ButtonTheme.cc (Arbeitskopie) @@ -57,7 +57,18 @@ return FbTk::ThemeManager::instance().loadItem(item, m_fallbackname, m_altfallbackname); + } else if (item.name().find(".font") != std::string::npos) { + return FbTk::ThemeManager::instance().loadItem(item, + m_fallbackname + ".font", + m_altfallbackname + ".Font"); + + } else if (item.name().find(".textColor") != std::string::npos) { + + return FbTk::ThemeManager::instance().loadItem(item, + m_fallbackname + ".textColor", + m_altfallbackname + ".TextColor"); + } else if (item.name().find(".picColor") != std::string::npos) { // if we've fallen back to alternate name, and it doesn't have a picColor, // try its text color instead Index: src/Keys.cc =================================================================== --- src/Keys.cc (Revision 3927) +++ src/Keys.cc (Arbeitskopie) @@ -92,7 +92,12 @@ #endif #include -using namespace std; +using std::string; +using std::vector; +using std::endl; +using std::ifstream; +using std::cerr; +using FbTk::StringUtil::stringtok; Keys::Keys(const char *filename): m_display(FbTk::App::instance()->display()) @@ -169,11 +174,11 @@ // return true; } -bool Keys::addBinding(const std::string &linebuffer) { +bool Keys::addBinding(const string &linebuffer) { vector val; // Parse arguments - FbTk::StringUtil::stringtok(val, linebuffer.c_str()); + stringtok(val, linebuffer.c_str()); // must have at least 1 argument if (val.size() <= 0) @@ -225,8 +230,7 @@ } bool ret_val = true; const char *str = - FbTk::StringUtil::strcasestr(linebuffer.c_str(), - val[argc].c_str() + 1); // +1 to skip ':' + FbTk::StringUtil::strcasestr(linebuffer.c_str(), val[argc].c_str() + 1); // +1 to skip ':' if (str == 0) { cerr<<_FBTEXT(Keys, BadLine, "Keys: Error on line", "Error on line (number following)")<<": "< "<> defaults.hh echo '#define DEFAULT_INITFILE "$(DEFAULT_INITFILE)"' >> defaults.hh echo '#define LOCALEPATH "$(pkgdatadir)/nls"' >> defaults.hh + echo '#define DEFAULTHISTORYFILE "~/.fluxbox/history"' >> defaults.hh echo 'const char* svnversion(void);' >> defaults.hh defaults.cc: force @@ -79,6 +80,7 @@ SystemTray.hh SystemTray.cc \ GenericTool.hh GenericTool.cc \ ButtonTool.hh ButtonTool.cc ButtonTheme.hh ButtonTheme.cc \ + RunBox.cc RunBox.hh RunTool.cc RunTool.hh \ ToolFactory.hh ToolFactory.cc endif Index: src/RunBox.hh =================================================================== --- src/RunBox.hh (Revision 0) +++ src/RunBox.hh (Revision 0) @@ -0,0 +1,116 @@ +// RunBox.hh +// Copyright (c) 2005 Mathias Gumz (akira at fluxbox dot org) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +// $Id: RunBox.hh,v 1.15 2004/04/18 14:16:09 fluxgen Exp $ + +#ifndef RUNBUTTON_HH +#define RUNBUTTON_HH + +#include "FbTk/EventHandler.hh" +#include "FbTk/Font.hh" +#include "FbTk/FbWindow.hh" +#include "FbTk/TextBox.hh" +#include "FbTk/GContext.hh" +#include "FbTk/FbPixmap.hh" +#include "FbTk/History.hh" +#include "FbTk/Command.hh" + +#include +#include + + +class BScreen; +class RunTool; + +/** + Creates and managed a run window +*/ +class RunBox: public FbTk::TextBox { +public: + RunBox(const FbTk::FbWindow &parent, + const BScreen& screen, + const RunTool& runtool, + FbTk::Font &font, const std::string &text, size_t width = 200); + ~RunBox(); + void handleEvent(XEvent * const ev); + void setTitle(const std::string &title); + void resize(unsigned int width, unsigned int height); + + /// load and reconfigure for new font + bool loadFont(const std::string &fontname); + void setForegroundColor(const FbTk::Color &color); + void setAntialias(bool val) { m_font->setAntialias(val); } + const FbTk::Font &font() const { return *m_font; } + /// execute command and exit + void run(const std::string &execstring); + /// is this application done? + /** + loads history file. + @return true on success, else false + */ + bool loadHistory(const char *filename); + /** + @name events + */ + ///@{ + void keyPressEvent(XKeyEvent &ev); + void buttonPressEvent(XButtonEvent& be); + void enterNotifyEvent(XCrossingEvent &ce); + ///@} + + void nextHistoryItem(); + void prevHistoryItem(); + + const BScreen& screen() const { return m_screen; } + +private: + void drawString(int x, int y, const char *text, size_t len); + void getSize(size_t &width, size_t &height); + void createWindow(int x, int y, size_t width, size_t height); + void redrawLabel(); + + void insertCharacter(char key); + void adjustStartPos(); + void adjustEndPos(); + void firstHistoryItem(); + void lastHistoryItem(); + void tabCompleteHistory(); + void tabCompleteApps(); + + const BScreen& m_screen; + FbTk::Font* m_font; + FbTk::GContext m_gc; + int m_bevel; + + FbTk::History m_history; + + typedef std::vector AppsContainer; + typedef AppsContainer::iterator AppsContainerIt; + AppsContainer m_apps; ///< holds all apps in $PATH + size_t m_current_apps_item; ///< holds current position in apps-history + + Cursor m_cursor; + + std::auto_ptr m_cmd_button4; + std::auto_ptr m_cmd_button5; +}; + +#endif // RUNBUTTON_HH Index: src/RunTool.cc =================================================================== --- src/RunTool.cc (Revision 0) +++ src/RunTool.cc (Revision 0) @@ -0,0 +1,205 @@ +// RunTool.cc +// Copyright (c) 2005 Mathias Gumz (akira at fluxbox dot org) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +// $Id: Exp $ + +#include "RunTool.hh" +#include "defaults.hh" + +#include "ToolTheme.hh" +#include "Screen.hh" +#include "Workspace.hh" + +#include "RunBox.hh" + +#include "FbTk/App.hh" +#include "FbTk/ImageControl.hh" +#include "FbTk/StringUtil.hh" +#include "FbTk/EventManager.hh" + +using std::string; + +namespace { + +class FocusToRunCmd : public FbTk::Command { +public: + explicit FocusToRunCmd(RunBox& button) : m_box(button) { } + void execute() { + m_box.setInputFocus(); + } +private: + RunBox& m_box; +}; // FocusToRunCmd + +}; // anonymous namespace + + +template<> +void FbTk::Resource::setDefaultValue() { + m_value = RunTool::SCREEN; +} + + +template<> +void FbTk::Resource::setFromString(const char* strval) { + if (strncasecmp(strval, "off", strlen("off")) == 0) + m_value = RunTool::OFF; + else if (strncasecmp(strval, "workspace", strlen("workspace")) == 0) + m_value = RunTool::WORKSPACE; + else if (strncasecmp(strval, "on", strlen("on")) == 0) + m_value = RunTool::ON; + else if (strncasecmp(strval, "screen", strlen("screen")) == 0) + m_value = RunTool::SCREEN; + else if (strncasecmp(strval, "history", strlen("history")) == 0) + m_value = RunTool::HISTORY; + else + setDefaultValue(); +} + + +template<> +string FbTk::Resource::getString() { + switch(m_value) { + case RunTool::ON: + return string("On"); + break; + case RunTool::SCREEN: + return string("Screen"); + break; + case RunTool::HISTORY: + return string("History"); + break; + }; + return string("Off"); +} + + + + + +RunTool::RunTool(const FbTk::FbWindow &parent, ToolTheme &theme, BScreen &screen): + ToolbarItem(ToolbarItem::FIXED), + m_box(parent, screen, *this, theme.font(), ""), + m_theme(theme), + m_screen(screen), + m_pixmap(0), + m_history_file(screen.resourceManager(), DEFAULTHISTORYFILE, + screen.name() + ".run.historyfile", screen.altName() + ".Run.HistoryFile"), + m_width(screen.resourceManager(), 200, screen.name() + ".run.width", + screen.altName() + ".Run.Width"), + m_wheel_mode(screen.resourceManager(), RunTool::SCREEN, + screen.name() + ".run.wheelMode", screen.altName() + ".Run.WheelMode"), + m_padding(screen.resourceManager(), 10, screen.name() + ".run.padding", ".Run.Padding") { + + theme.reconfigSig().attach(this); + + m_box.setGC(m_theme.textGC()); + m_box.loadHistory(FbTk::StringUtil::expandFilename(*m_history_file).c_str()); + m_box.resize(*m_width, m_box.height()); + m_box.setTextPadding(*m_padding); + + // add command-entry to the commandparser + addCommand("focusruntool"); + + update(0); +} + +RunTool::~RunTool() { + if (m_pixmap) + m_screen.imageControl().removeImage(m_pixmap); +} + +void RunTool::move(int x, int y) { + m_box.move(x, y); +} + +void RunTool::resize(unsigned int width, unsigned int height) { + m_box.resize(*m_width, height); +} + + +void RunTool::moveResize(int x, int y, unsigned int width, unsigned int height) { + m_box.moveResize(x, y, width, height); +} + +void RunTool::update(FbTk::Subject *subj) { + + if (m_box.width() != width()) { + resize(width(), height()); + resizeSig().notify(); + } + + renderTheme(); +} + +unsigned int RunTool::width() const { + return m_box.width(); +} + +unsigned int RunTool::height() const { + return m_box.height(); +} + +unsigned int RunTool::borderWidth() const { + return m_box.borderWidth(); +} + +void RunTool::show() { + m_box.show(); +} + +void RunTool::hide() { + m_box.hide(); +} + +void RunTool::renderTheme(unsigned char alpha) { + Pixmap tmp = m_pixmap; + if (!m_theme.texture().usePixmap()) { + m_pixmap = 0; + m_box.setBackgroundColor(m_theme.texture().color()); + } else { + m_pixmap = m_screen.imageControl().renderImage(width(), height(), + m_theme.texture()); + m_box.setBackgroundPixmap(m_pixmap); + } + if (tmp) + m_screen.imageControl().removeImage(tmp); + + m_box.setTextPadding(*m_padding); + m_box.setForegroundColor(m_theme.textColor()); + m_box.setBorderWidth(m_theme.border().width()); + m_box.setBorderColor(m_theme.border().color()); + //m_box.setAlpha(m_theme.alpha()); + m_box.clear(); +} + +void RunTool::updateSizing() { + update(0); +} + +FbTk::Command* RunTool::stringToCommand(const std::string &command, + const std::string &arguments) { + if (command == "focusruntool") + return new FocusToRunCmd(m_box); + + return 0; +} + Index: src/FbTk/TextBox.hh =================================================================== --- src/FbTk/TextBox.hh (Revision 3927) +++ src/FbTk/TextBox.hh (Arbeitskopie) @@ -42,6 +42,9 @@ virtual ~TextBox(); void setText(const std::string &text); + void setTextPadding(unsigned int padding); + void setTextPaddingLeft(unsigned int leftpadding); + void setTextPaddingRight(unsigned int rightpadding); void setFont(const Font &font); void setGC(GC gc); void setCursorPosition(int cursor); @@ -75,6 +78,8 @@ const FbTk::Font *m_font; std::string m_text; + unsigned int m_left_padding; + unsigned int m_right_padding; GC m_gc; std::string::size_type m_cursor_pos, m_start_pos, m_end_pos; }; Index: src/FbTk/History.cc =================================================================== --- src/FbTk/History.cc (Revision 0) +++ src/FbTk/History.cc (Revision 0) @@ -0,0 +1,276 @@ +// History.cc for Fluxbox - an X11 Window manager +// Copyright (c) 2005 Mathias Gumz (akira at fluxbox dot org) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +// $Id: $ + +#include "History.hh" +#include "StringUtil.hh" + +#include +#include +#include + +using namespace std; +using namespace FbTk; + +namespace { + +ostream& operator<<(ostream& oss, const History::Item& item) { + oss << "[ " << item.first << " ] "; + oss << item.second; + return oss; +} + + +}; // anonymouse namespace end + +History::History(const char* history_file, bool create_hist_file) { + + if (load(history_file)) { + m_history_file = history_file; + } else if (history_file) { + cerr << "warning: cant load history file [" << history_file << "].\n"; + if (create_hist_file) { + ofstream ofile(history_file); + if (!ofile) + cerr << "warning: cant create history file [" << history_file << "].\n"; + } + } else { +#ifdef DEBUG + cerr << "warning: no historyfile given.\n"; +#endif // DEBUG + } + + m_history.push_back(Item(time(0), "")); + lastItem(); +} + + +bool History::setFilename(const char* filename, bool create_hist_file) { + + if (filename) { + ifstream ifile(filename); + if (!ifile) { + if (create_hist_file) { + ofstream ofile(filename); + if (!ofile) + return false; + } + } + m_history_file = filename; + return true; + } + + return false; +} + +void History::appendItem(const string& txt) { + Item& last_item = m_history[m_history.size() - 1]; + last_item.second = txt; + last_item.first = time(0); + m_history.push_back(Item(time(0), "")); +} + + +bool History::firstItem() { + m_current_item = 0; + return true; +} + +bool History::lastItem() { + m_current_item = m_history.size()-1; + return true; +} + +bool History::nextItem() { + if (m_current_item != m_history.size()-1) { + m_current_item++; + return true; + } + + return false; +} + +bool History::prevItem() { + if(m_current_item != 0) { + m_current_item--; + return true; + } + return false; +} + + +unsigned int History::removeDuplicates() { + + ItemContainerIt it; + + map tmp; + map::iterator tmp_it; + + unsigned int nr_doubles = 0; + + // delete doubles, skip "" + for(it = m_history.begin(); it != m_history.end(); it++) { + if ((*it).second == "") + continue; + if (tmp.find((*it).second) != tmp.end()) + nr_doubles++; + tmp[(*it).second] = *it; + } + + ItemContainer tmp2; + for(tmp_it = tmp.begin(); tmp_it != tmp.end(); tmp_it++) { + tmp2.push_back((*tmp_it).second); + } + swap(m_history, tmp2); + + if (!m_history.empty() && m_history.size() > 1) { + sort(m_history.begin(), m_history.end()); + } + m_history.push_back(Item(time(0), "")); + lastItem(); + + return nr_doubles; +} + +ostream& History::writeTo(ostream& oss, WriteMode mode) const { + + ConstItemContainerIt it; + + switch(mode) { + case UNIQUE: { + + History tmp(*this); + tmp.removeDuplicates(); + + for(it = tmp.m_history.begin(); it != tmp.m_history.end(); it++) { + if (it->second == "") + continue; + oss << *it << endl; + } + } + break; + case ALL: + default: + for(it = m_history.begin(); it != m_history.end(); it++) { + if (it->second == "") + continue; + oss << *it << endl; + } + break; + }; + + return oss; +} + +bool History::save(const char* filename) const { + + const char* fn = 0; + + if (filename) + fn = filename; + else if (!m_history.empty()) + fn = m_history_file.c_str(); + + if(fn) { + ofstream ofile(StringUtil::expandFilename(fn).c_str()); + if (ofile) { + writeTo(ofile, UNIQUE); + } + } +} + + +istream& History::readFrom(istream& iss, ReadMode mode) { + + if (mode == REPLACE) { + m_history.clear(); + } + + string tmp; + time_t tstamp; + char key; + bool space; + + while (iss.good()) { + tstamp = 0; + tmp = ""; + space = true; + + iss >> tmp; + if (tmp != "[" ) + break; + + iss >> tstamp >> tmp; + + if (!iss.good() || tmp != "]" ) + break; + + tmp.clear(); + + while ((key = iss.get()) != '\n') { + if (space) { + if (isspace(key)) + continue; + else + space = false; + } + tmp += key; + } + + if (!tmp.empty()) + m_history.push_back(History::Item(tstamp, tmp)); + + } + + if (!m_history.empty() && m_history.size() > 1) { + sort(m_history.begin(), m_history.end()); + lastItem(); + } + + if (m_history.empty() || currentLabel() != "") { + m_history.push_back(Item(time(0), "")); + lastItem(); + } + + return iss; +} + +bool History::load(const char* filename) { + + const char* fn = 0; + + if(filename) + fn = filename; + else if (!m_history_file.empty()) + fn = m_history_file.c_str(); + else + return false; + + ifstream ifile(fn); + if (ifile) { + readFrom(ifile); + return true; + } + + return false; +} + Index: src/FbTk/History.hh =================================================================== --- src/FbTk/History.hh (Revision 0) +++ src/FbTk/History.hh (Revision 0) @@ -0,0 +1,104 @@ +// History.hh for Fluxbox - an X11 Window manager +// Copyright (c) 2005 Mathias Gumz (akira at fluxbox dot org) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +// $Id: $ + +#ifndef HISTORY_HH +#define HISTORY_HH + +#include +#include +#include +#include + +namespace FbTk { + +class History { + public: + + // typedefs + typedef std::pair Item; + typedef std::vector ItemContainer; + typedef ItemContainer::iterator ItemContainerIt; + typedef ItemContainer::const_iterator ConstItemContainerIt; + + + typedef enum { + APPEND, + REPLACE + } ReadMode; + + + typedef enum { + UNIQUE, + ALL + } WriteMode; + + + // constructors + History(const char* history_file = "", bool create_history_file = true); + + // accessors + const ItemContainer& history() const { return m_history; } + ConstItemContainerIt begin() const { return m_history.begin(); } + ConstItemContainerIt end() const { return m_history.end(); } + size_t current() { return m_current_item; } + const size_t current() const { return m_current_item; } + time_t currentTimeStamp() const { return m_history[m_current_item].first; } + const char* currentLabel() const { return m_history[m_current_item].second.c_str(); } + + const char* filename() const { return m_history_file.c_str(); } + + // modificators + bool setFilename(const char* filename, bool create_history_file = true); + + // actually: insert before final ""-item + void appendItem(const std::string& text); + void insertItem(const std::string& text, time_t tstamp = time(0)); + void deleteItem(const std::string& text); + void deleteItem(time_t tstamp); + void deleteItem(ItemContainerIt item); + + bool firstItem(); + bool lastItem(); + bool nextItem(); + bool prevItem(); + + unsigned int removeDuplicates(); + + // io + bool save(const char* filename = 0) const; + bool load(const char* filename = 0); + bool merge(const char* filename); + + std::ostream& writeTo(std::ostream& oss, WriteMode mode = ALL ) const; + std::istream& readFrom(std::istream& iss, ReadMode mode = REPLACE); + + private: + + ItemContainer m_history; + size_t m_current_item; + + std::string m_history_file; +}; // class History + +}; // namespace FbTk +#endif // HISTORY_HH Index: src/FbTk/TextBox.cc =================================================================== --- src/FbTk/TextBox.cc (Revision 3927) +++ src/FbTk/TextBox.cc (Arbeitskopie) @@ -39,9 +39,11 @@ TextBox::TextBox(int screen_num, const Font &font, const std::string &text): - FbWindow(screen_num, 0, 0, 1, 1, ExposureMask | KeyPressMask | ButtonPressMask), + FbWindow(screen_num, 0, 0, 1, 1, ExposureMask | KeyPressMask | ButtonPressMask | EnterWindowMask), m_font(&font), m_text(text), + m_left_padding(0), + m_right_padding(0), m_gc(0), m_cursor_pos(0), m_start_pos(0), @@ -52,9 +54,11 @@ TextBox::TextBox(const FbWindow &parent, const Font &font, const std::string &text): - FbWindow(parent, 0, 0, 1, 1, ExposureMask | KeyPressMask | ButtonPressMask), + FbWindow(parent, 0, 0, 1, 1, ExposureMask | KeyPressMask | ButtonPressMask | EnterWindowMask), m_font(&font), m_text(text), + m_left_padding(0), + m_right_padding(0), m_gc(0), m_cursor_pos(0), m_start_pos(0), @@ -78,6 +82,19 @@ m_font = &font; } +void TextBox::setTextPadding(unsigned int padding) { + setTextPaddingLeft(padding/2); + setTextPaddingRight(padding/2); +} + +void TextBox::setTextPaddingLeft(unsigned int padding) { + m_left_padding = padding; +} + +void TextBox::setTextPaddingRight(unsigned int padding) { + m_right_padding = padding; +} + void TextBox::setGC(GC gc) { m_gc = gc; } @@ -157,20 +174,22 @@ void TextBox::clear() { FbWindow::clear(); - // center text by default - int center_pos = (height() + font().ascent())/2; if (gc() == 0) setGC(DefaultGC(FbTk::App::instance()->display(), screenNumber())); + // center text by default + int center_pos = height()/2 + font().ascent()/2 - 1; font().drawText(*this, screenNumber(), gc(), text().c_str() + m_start_pos, m_end_pos - m_start_pos, - 0, center_pos); // pos + m_left_padding, center_pos); // pos // draw cursor position - int cursor_pos = font().textWidth(text().c_str() + m_start_pos, m_cursor_pos) + 1; - drawLine(gc(), cursor_pos, center_pos, cursor_pos, center_pos - font().height()); + int cursor_pos = m_left_padding + font().textWidth(text().c_str() + m_start_pos, m_cursor_pos) + 1; + drawLine(gc(), + cursor_pos, center_pos + 2, + cursor_pos, center_pos + 2 - font().height()); } void TextBox::moveResize(int x, int y, @@ -331,8 +350,9 @@ void TextBox::adjustEndPos() { m_end_pos = text().size(); + const int w = static_cast(width() - (m_right_padding + m_left_padding)); int text_width = font().textWidth(text().c_str() + m_start_pos, m_end_pos - m_start_pos); - while (text_width > static_cast(width())) { + while (text_width > w) { m_end_pos--; text_width = font().textWidth(text().c_str() + m_start_pos, m_end_pos - m_start_pos); } @@ -340,12 +360,13 @@ void TextBox::adjustStartPos() { + const int w = static_cast(width() - (m_right_padding + m_left_padding)); int text_width = font().textWidth(text().c_str(), m_end_pos); - if (text_width < static_cast(width())) + if (text_width < w) return; int start_pos = 0; - while (text_width > static_cast(width())) { + while (text_width > w) { start_pos++; text_width = font().textWidth(text().c_str() + start_pos, m_end_pos - start_pos); } Index: src/FbTk/Makefile.am =================================================================== --- src/FbTk/Makefile.am (Revision 3927) +++ src/FbTk/Makefile.am (Arbeitskopie) @@ -49,6 +49,7 @@ KeyUtil.hh KeyUtil.cc \ MenuSeparator.hh MenuSeparator.cc \ MenuIcon.hh MenuIcon.cc \ + History.hh History.cc \ stringstream.hh \ ${xpm_SOURCE} \ ${xft_SOURCE} \ Index: src/ToolFactory.hh =================================================================== --- src/ToolFactory.hh (Revision 3927) +++ src/ToolFactory.hh (Arbeitskopie) @@ -56,6 +56,7 @@ std::auto_ptr m_workspace_theme; std::auto_ptr m_systray_theme; IconbarTheme m_iconbar_theme; + std::auto_ptr m_run_theme; }; #endif // TOOLFACTORY_HH Index: src/RunBox.cc =================================================================== --- src/RunBox.cc (Revision 0) +++ src/RunBox.cc (Revision 0) @@ -0,0 +1,417 @@ +// RunBox.cc +// Copyright (c) 2005 Mathias Gumz (akira at fluxbox dot org) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +// $Id: $ + +#include "RunBox.hh" +#include "RunTool.hh" +#include "FbCommands.hh" +#include "CommandParser.hh" +#include "Toolbar.hh" +#include "Screen.hh" + +#include "FbTk/App.hh" +#include "FbTk/EventManager.hh" +#include "FbTk/Color.hh" +#include "FbTk/KeyUtil.hh" +#include "FbTk/FileUtil.hh" +#include "FbTk/RefCount.hh" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using std::string; + +typedef FbTk::RefCount RefCmd; + +namespace { + +///< helper command for the history +class HistorySwitchCmd : public FbTk::Command { +public: + explicit HistorySwitchCmd(RunBox& button, bool next) : m_button(&button), m_next(next) { } + void execute() { + m_next ? m_button->nextHistoryItem() : m_button->prevHistoryItem(); + m_button->clear(); + } +private: + RunBox* m_button; + bool m_next; +}; + +///< little helper to do the wheeling +class WheelRunToolCmd : public FbTk::Command { +public: + explicit WheelRunToolCmd(const RunTool& runtool, RunBox& button, bool next) : + m_button(&button), m_runtool(runtool), + m_hist_cmd(0), m_wheel_cmd(0) { + + m_hist_cmd = new HistorySwitchCmd(button, next); + m_wheel_cmd = CommandParser::instance().parseLine(next ? "NextWorkspace" : "PrevWorkspace"); + } + + void execute() { + + switch(m_runtool.wheelMode()) { + case RunTool::ON: + m_wheel_cmd->execute(); + break; + case RunTool::SCREEN: + if(m_runtool.screen().isDesktopWheeling()) + m_wheel_cmd->execute(); + break; + case RunTool::HISTORY: + m_hist_cmd->execute(); + break; + case RunTool::OFF: + default: + break; + }; + } + +private: + RunBox* m_button; + RefCmd m_hist_cmd; + RefCmd m_wheel_cmd; + const RunTool& m_runtool; +}; + +}; // anonymous - namespace + +RunBox::RunBox(const FbTk::FbWindow& parent, + const BScreen& screen, + const RunTool& runtool, + FbTk::Font &font, + const std::string &text, size_t width): + FbTk::TextBox(parent, font, text), + m_screen(screen), + m_font(&font), + m_bevel(4), + m_gc(*this), + m_history(0), + m_current_apps_item(0), + m_cursor(XCreateFontCursor(display(), XC_xterm)), + m_cmd_button4(0), + m_cmd_button5(0) { + + setGC(m_gc.gc()); + setCursor(m_cursor); + + // up -> nextworkspace, but prevhistoryitem because so its in sync + // with the cursor-up/down + m_cmd_button4.reset(new WheelRunToolCmd(runtool, *this, false)); + m_cmd_button5.reset(new WheelRunToolCmd(runtool, *this, true)); +} + + +RunBox::~RunBox() { + hide(); + m_history.save(); +} + +void RunBox::run(const std::string &command) { + + FbCommands::ExecuteCmd runcmd(command); + runcmd.execute(); + + if (text().size() != 0) { + m_history.appendItem(text()); + m_history.lastItem(); + } + + setText(m_history.currentLabel()); +} + +bool RunBox::loadHistory(const char *filename) { + m_history.setFilename(filename, true); + return m_history.load(); +} + +bool RunBox::loadFont(const string &fontname) { + if (!m_font->load(fontname.c_str())) + return false; + + // resize to fit new font height + setFont(*m_font); + resize(width(), font().height() + m_bevel); + return true; +} + +void RunBox::setForegroundColor(const FbTk::Color &color) { + m_gc.setForeground(color); + setGC(m_gc.gc()); +} + +void RunBox::setTitle(const string &title) { + setName(title.c_str()); +} + +void RunBox::resize(unsigned int width, unsigned int height) { + FbTk::TextBox::resize(width, height); +} + +void RunBox::redrawLabel() { + clear(); +} + +void RunBox::enterNotifyEvent(XCrossingEvent &ce) { + if (m_screen.isSloppyFocus() || m_screen.isSemiSloppyFocus()) + FbTk::TextBox::setInputFocus(); +} + + +void RunBox::buttonPressEvent(XButtonEvent& be) { + + if (be.button == Button4 && m_cmd_button4.get()) + m_cmd_button4->execute(); + else if (be.button == Button5 && m_cmd_button5.get()) + m_cmd_button5->execute(); + else + TextBox::buttonPressEvent(be); +} + +void RunBox::keyPressEvent(XKeyEvent &ke) { + // strip numlock, capslock and scrolllock mask + ke.state = FbTk::KeyUtil::instance().cleanMods(ke.state); + + int cp= cursorPosition(); + FbTk::TextBox::keyPressEvent(ke); + KeySym ks; + char keychar[1]; + XLookupString(&ke, keychar, 1, &ks, 0); + // a modifier key by itself doesn't do anything + if (IsModifierKey(ks)) return; + + if (ke.state) { // a modifier key is down + if (ke.state == ControlMask) { + switch (ks) { + case XK_p: + prevHistoryItem(); + break; + case XK_n: + nextHistoryItem(); + break; + case XK_Tab: + tabCompleteHistory(); + setCursorPosition(cp); + break; + } + } else if (ke.state == (Mod1Mask | ShiftMask)) { + switch (ks) { + case XK_less: + firstHistoryItem(); + break; + case XK_greater: + lastHistoryItem(); + break; + } + } + } else { // no modifier key + switch (ks) { + case XK_Return: + run(text()); + break; + case XK_Up: + prevHistoryItem(); + break; + case XK_Down: + nextHistoryItem(); + break; + case XK_Tab: + tabCompleteApps(); + setCursorPosition(cp); + break; + } + } + clear(); +} + +void RunBox::prevHistoryItem() { + if (!m_history.prevItem()) { + XBell(display(), 0); + } else { + setText(m_history.currentLabel()); + } +} + +void RunBox::nextHistoryItem() { + if (!m_history.nextItem()) { + XBell(display(), 0); + } else { + setText(m_history.currentLabel()); + } +} + +void RunBox::firstHistoryItem() { + if (!m_history.firstItem()) { + XBell(display(), 0); + } else { + setText(m_history.currentLabel()); + } +} + +void RunBox::lastHistoryItem() { + if (!m_history.lastItem()) { + XBell(display(), 0); + } else { + setText(m_history.currentLabel()); + } +} + +void RunBox::tabCompleteHistory() { + /* + if (m_current_history_item == 0 || m_history.empty() ) { + XBell(m_display, 0); + } else { + unsigned int nr= 0; + int history_item = m_current_history_item - 1; + string prefix = text().substr(0, cursorPosition()); + while (history_item != m_current_history_item && nr++ < m_history.size()) { + if (history_item <= -1 ) + history_item= m_history.size() - 1; + if (m_history[history_item].find(prefix) == 0) { + m_current_history_item = history_item; + setText(m_history[m_current_history_item]); + break; + } + history_item--; + } + if (history_item == m_current_history_item) XBell(m_display, 0); + } + */ +} + +void RunBox::tabCompleteApps() { + + static bool first_run= true; + static string saved_prefix= ""; + string prefix= text().substr(0, cursorPosition()); + FbTk::Directory dir; + + bool add_dirs= false; + bool changed_prefix= false; + + // (re)build m_apps-container + if (first_run || saved_prefix != prefix) { + first_run= false; + + string path; + + if(!prefix.empty() && prefix[0] =='/') { + size_t rseparator= prefix.find_last_of("/"); + path= prefix.substr(0, rseparator + 1) + ":"; + add_dirs= true; + } else + path= getenv("PATH"); + + m_apps.clear(); + + unsigned int l; + unsigned int r; + + for(l= 0, r= 0; r < path.size(); r++) { + if ((path[r]==':' || r == path.size() - 1) && r - l > 0) { + string filename; + string fncomplete; + dir.open(path.substr(l, r - l).c_str()); + int n= dir.entries(); + if (n >= 0) { + while(n--) { + filename= dir.readFilename(); + fncomplete= dir.name() + + (*dir.name().rbegin() != '/' ? "/" : "") + + filename; + + // directories in dirmode ? + if (add_dirs && FbTk::FileUtil::isDirectory(fncomplete.c_str()) && + filename != ".." && filename != ".") { + m_apps.push_back(fncomplete); + // executables in dirmode ? + } else if (add_dirs && FbTk::FileUtil::isRegularFile(fncomplete.c_str()) && + FbTk::FileUtil::isExecutable(fncomplete.c_str()) && + (prefix == "" || + fncomplete.substr(0, prefix.size()) == prefix)) { + m_apps.push_back(fncomplete); + // executables in $PATH ? + } else if (FbTk::FileUtil::isRegularFile(fncomplete.c_str()) && + FbTk::FileUtil::isExecutable(fncomplete.c_str()) && + (prefix == "" || + filename.substr(0, prefix.size()) == prefix)) { + m_apps.push_back(filename); + } + } + } + l= r + 1; + dir.close(); + } + } + sort(m_apps.begin(), m_apps.end()); + unique(m_apps.begin(), m_apps.end()); + + saved_prefix= prefix; + changed_prefix= true; + m_current_apps_item= 0; + } + + if (m_apps.empty() ) { + XBell(display(), 0); + } else { + size_t apps_item = m_current_apps_item + (changed_prefix ? 0 : 1); + bool loop= false; + + while (true) { + if (apps_item >= m_apps.size() ) { + loop = true; + apps_item = 0; + } + + if ((!changed_prefix || loop) && apps_item == m_current_apps_item) { + break; + } + if (m_apps[apps_item].find(prefix) == 0) { + m_current_apps_item = apps_item; + if (FbTk::FileUtil::isDirectory(m_apps[m_current_apps_item].c_str())) + setText(m_apps[m_current_apps_item] + "/"); + else + setText(m_apps[m_current_apps_item]); + break; + } + apps_item++; + } + if (!changed_prefix && apps_item == m_current_apps_item) + XBell(display(), 0); + } +} + +void RunBox::insertCharacter(char keychar) { + char val[2] = {keychar, 0}; + insertText(val); +} +