2003-12-19 03:53:21 +00:00
|
|
|
// CommandDialog.cc for Fluxbox
|
2006-02-16 06:53:05 +00:00
|
|
|
// Copyright (c) 2003 - 2006 Henrik Kinnunen (fluxgen at fluxbox dot org)
|
2003-12-19 03:53:21 +00:00
|
|
|
// and Simon Bowden (rathnor at users.sourceforge.net)
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
|
|
|
|
#include "CommandDialog.hh"
|
|
|
|
|
|
|
|
#include "Screen.hh"
|
|
|
|
#include "FbWinFrameTheme.hh"
|
|
|
|
#include "WinClient.hh"
|
2008-01-11 07:41:22 +00:00
|
|
|
#include "FbTk/CommandParser.hh"
|
2006-02-18 20:19:22 +00:00
|
|
|
#include "FocusControl.hh"
|
2006-07-25 21:54:58 +00:00
|
|
|
#include "fluxbox.hh"
|
2003-12-19 03:53:21 +00:00
|
|
|
|
|
|
|
#include "FbTk/ImageControl.hh"
|
|
|
|
#include "FbTk/EventManager.hh"
|
2004-01-02 13:53:21 +00:00
|
|
|
#include "FbTk/StringUtil.hh"
|
2005-05-06 09:22:53 +00:00
|
|
|
#include "FbTk/KeyUtil.hh"
|
2003-12-19 03:53:21 +00:00
|
|
|
#include "FbTk/App.hh"
|
|
|
|
|
|
|
|
#include <X11/keysym.h>
|
|
|
|
#include <X11/Xutil.h>
|
|
|
|
|
|
|
|
#include <memory>
|
2004-01-02 13:53:21 +00:00
|
|
|
#include <stdexcept>
|
2006-10-30 19:31:15 +00:00
|
|
|
|
|
|
|
using std::string;
|
|
|
|
using std::vector;
|
|
|
|
using std::auto_ptr;
|
|
|
|
using std::less;
|
|
|
|
using std::out_of_range;
|
2003-12-19 03:53:21 +00:00
|
|
|
|
2005-05-06 09:22:53 +00:00
|
|
|
CommandDialog::CommandDialog(BScreen &screen,
|
2006-10-30 19:31:15 +00:00
|
|
|
const string &title, const string precommand) :
|
2004-10-21 10:46:21 +00:00
|
|
|
FbTk::FbWindow(screen.rootWindow().screenNumber(), 0, 0, 200, 1, ExposureMask),
|
2008-01-07 20:08:56 +00:00
|
|
|
m_textbox(*this, screen.focusedWinFrameTheme()->font(), ""),
|
|
|
|
m_label(*this, screen.focusedWinFrameTheme()->font(), title),
|
2003-12-19 03:53:21 +00:00
|
|
|
m_gc(m_textbox),
|
|
|
|
m_screen(screen),
|
|
|
|
m_move_x(0),
|
|
|
|
m_move_y(0),
|
|
|
|
m_pixmap(0),
|
|
|
|
m_precommand(precommand) {
|
|
|
|
init();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
CommandDialog::~CommandDialog() {
|
|
|
|
FbTk::EventManager::instance()->remove(*this);
|
|
|
|
hide();
|
|
|
|
if (m_pixmap != 0)
|
|
|
|
m_screen.imageControl().removeImage(m_pixmap);
|
|
|
|
}
|
|
|
|
|
2006-10-30 19:31:15 +00:00
|
|
|
void CommandDialog::setText(const string &text) {
|
2003-12-19 03:53:21 +00:00
|
|
|
m_textbox.setText(text);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CommandDialog::show() {
|
|
|
|
FbTk::FbWindow::show();
|
|
|
|
m_textbox.setInputFocus();
|
|
|
|
m_label.clear();
|
2006-07-25 21:54:58 +00:00
|
|
|
Fluxbox::instance()->setShowingDialog(true);
|
2003-12-19 18:16:01 +00:00
|
|
|
// resize to correct width, which should be the width of label text
|
|
|
|
// no need to truncate label text in this dialog
|
|
|
|
// but if label text size < 200 we set 200
|
|
|
|
if (m_label.textWidth() < 200)
|
|
|
|
return;
|
|
|
|
else {
|
|
|
|
resize(m_label.textWidth(), height());
|
|
|
|
updateSizes();
|
|
|
|
render();
|
|
|
|
}
|
2003-12-19 03:53:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CommandDialog::hide() {
|
|
|
|
FbTk::FbWindow::hide();
|
2006-07-25 21:54:58 +00:00
|
|
|
Fluxbox::instance()->setShowingDialog(false);
|
2003-12-19 03:53:21 +00:00
|
|
|
}
|
|
|
|
|
2003-12-19 18:16:01 +00:00
|
|
|
void CommandDialog::exposeEvent(XExposeEvent &event) {
|
|
|
|
if (event.window == window())
|
|
|
|
clearArea(event.x, event.y, event.width, event.height);
|
|
|
|
}
|
|
|
|
|
2003-12-19 03:53:21 +00:00
|
|
|
void CommandDialog::buttonPressEvent(XButtonEvent &event) {
|
|
|
|
m_textbox.setInputFocus();
|
|
|
|
m_move_x = event.x_root - x();
|
|
|
|
m_move_y = event.y_root - y();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CommandDialog::handleEvent(XEvent &event) {
|
|
|
|
if (event.type == ConfigureNotify && event.xconfigure.window != window()) {
|
|
|
|
moveResize(event.xconfigure.x, event.xconfigure.y,
|
|
|
|
event.xconfigure.width, event.xconfigure.height);
|
|
|
|
} else if (event.type == DestroyNotify)
|
|
|
|
delete this;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CommandDialog::motionNotifyEvent(XMotionEvent &event) {
|
|
|
|
int new_x = event.x_root - m_move_x;
|
|
|
|
int new_y = event.y_root - m_move_y;
|
|
|
|
move(new_x, new_y);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CommandDialog::keyPressEvent(XKeyEvent &event) {
|
2005-05-06 09:22:53 +00:00
|
|
|
unsigned int state = FbTk::KeyUtil::instance().isolateModifierMask(event.state);
|
|
|
|
if (state)
|
2003-12-19 03:53:21 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
KeySym ks;
|
2005-05-06 09:22:53 +00:00
|
|
|
char keychar;
|
|
|
|
XLookupString(&event, &keychar, 1, &ks, 0);
|
2003-12-19 03:53:21 +00:00
|
|
|
|
|
|
|
if (ks == XK_Return) {
|
2008-01-11 07:41:22 +00:00
|
|
|
// create Command<void> from line
|
|
|
|
auto_ptr<FbTk::Command<void> > cmd(FbTk::CommandParser<void>::instance().parse(m_precommand + m_textbox.text()));
|
2003-12-19 03:53:21 +00:00
|
|
|
if (cmd.get())
|
|
|
|
cmd->execute();
|
2005-05-06 09:22:53 +00:00
|
|
|
// post execute
|
2003-12-19 18:16:01 +00:00
|
|
|
if (*m_postcommand != 0)
|
|
|
|
m_postcommand->execute();
|
|
|
|
|
2003-12-19 03:53:21 +00:00
|
|
|
delete this; // end this
|
|
|
|
} else if (ks == XK_Escape)
|
|
|
|
delete this; // end this
|
2004-01-02 13:53:21 +00:00
|
|
|
else if (ks == XK_Tab) {
|
|
|
|
// try to expand a command
|
|
|
|
tabComplete();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CommandDialog::tabComplete() {
|
|
|
|
try {
|
|
|
|
string::size_type first = m_textbox.text().find_last_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
|
|
"abcdefghijklmnopqrstuvwxyz"
|
2005-05-06 09:22:53 +00:00
|
|
|
"0123456789",
|
2004-01-02 13:53:21 +00:00
|
|
|
m_textbox.cursorPosition());
|
|
|
|
if (first == string::npos)
|
|
|
|
first = 0;
|
|
|
|
string prefix = FbTk::StringUtil::toLower(m_textbox.text().substr(first, m_textbox.cursorPosition()));
|
2004-01-21 13:16:09 +00:00
|
|
|
if (prefix.empty()) {
|
2004-01-02 13:53:21 +00:00
|
|
|
XBell(FbTk::App::instance()->display(), 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-06-03 07:15:37 +00:00
|
|
|
FbTk::CommandParser<void>::CreatorMap::const_iterator it = FbTk::CommandParser<void>::instance().creatorMap().begin();
|
|
|
|
const FbTk::CommandParser<void>::CreatorMap::const_iterator it_end = FbTk::CommandParser<void>::instance().creatorMap().end();
|
2006-10-30 19:31:15 +00:00
|
|
|
vector<string> matches;
|
2004-01-02 13:53:21 +00:00
|
|
|
for (; it != it_end; ++it) {
|
|
|
|
if ((*it).first.find(prefix) == 0) {
|
|
|
|
matches.push_back((*it).first);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!matches.empty()) {
|
|
|
|
// sort and apply larges match
|
2006-10-30 19:31:15 +00:00
|
|
|
sort(matches.begin(), matches.end(), less<string>());
|
2004-01-02 13:53:21 +00:00
|
|
|
m_textbox.setText(m_textbox.text() + matches[0].substr(prefix.size()));
|
|
|
|
} else
|
|
|
|
XBell(FbTk::App::instance()->display(), 0);
|
|
|
|
|
2006-10-30 19:31:15 +00:00
|
|
|
} catch (out_of_range &oor) {
|
2004-01-02 13:53:21 +00:00
|
|
|
XBell(FbTk::App::instance()->display(), 0);
|
|
|
|
}
|
2003-12-19 03:53:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CommandDialog::render() {
|
|
|
|
Pixmap tmp = m_pixmap;
|
2008-01-07 20:08:56 +00:00
|
|
|
if (!m_screen.focusedWinFrameTheme()->iconbarTheme().texture().usePixmap()) {
|
|
|
|
m_label.setBackgroundColor(m_screen.focusedWinFrameTheme()->iconbarTheme().texture().color());
|
2003-12-19 03:53:21 +00:00
|
|
|
m_pixmap = 0;
|
|
|
|
} else {
|
|
|
|
m_pixmap = m_screen.imageControl().renderImage(m_label.width(), m_label.height(),
|
2008-01-07 20:08:56 +00:00
|
|
|
m_screen.focusedWinFrameTheme()->iconbarTheme().texture());
|
2003-12-19 03:53:21 +00:00
|
|
|
m_label.setBackgroundPixmap(m_pixmap);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tmp)
|
|
|
|
m_screen.imageControl().removeImage(tmp);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void CommandDialog::init() {
|
|
|
|
|
2003-12-19 18:16:01 +00:00
|
|
|
|
|
|
|
// setup label
|
2003-12-19 03:53:21 +00:00
|
|
|
// we listen to motion notify too
|
2005-05-06 09:22:53 +00:00
|
|
|
m_label.setEventMask(m_label.eventMask() | ButtonPressMask | ButtonMotionMask);
|
2008-01-07 20:08:56 +00:00
|
|
|
m_label.setGC(m_screen.focusedWinFrameTheme()->iconbarTheme().text().textGC());
|
2003-12-19 03:53:21 +00:00
|
|
|
m_label.show();
|
|
|
|
|
2003-12-19 18:16:01 +00:00
|
|
|
// setup text box
|
|
|
|
FbTk::Color white("white", m_textbox.screenNumber());
|
|
|
|
m_textbox.setBackgroundColor(white);
|
2003-12-19 03:53:21 +00:00
|
|
|
FbTk::Color black("black", m_textbox.screenNumber());
|
|
|
|
m_gc.setForeground(black);
|
|
|
|
m_textbox.setGC(m_gc.gc());
|
|
|
|
m_textbox.show();
|
|
|
|
|
2003-12-19 18:16:01 +00:00
|
|
|
// setup this window
|
|
|
|
setBorderWidth(1);
|
|
|
|
setBackgroundColor(white);
|
2003-12-19 03:53:21 +00:00
|
|
|
// move to center of the screen
|
|
|
|
move((m_screen.width() - width())/2, (m_screen.height() - height())/2);
|
|
|
|
|
2003-12-19 18:16:01 +00:00
|
|
|
updateSizes();
|
|
|
|
resize(width(), m_textbox.height() + m_label.height());
|
|
|
|
|
|
|
|
render();
|
|
|
|
|
2003-12-19 03:53:21 +00:00
|
|
|
// we need ConfigureNotify from children
|
|
|
|
FbTk::EventManager::instance()->addParent(*this, *this);
|
|
|
|
}
|
2003-12-19 18:16:01 +00:00
|
|
|
|
|
|
|
void CommandDialog::updateSizes() {
|
|
|
|
m_label.moveResize(0, 0,
|
2004-10-06 19:02:03 +00:00
|
|
|
width(), m_textbox.font().height() + 2);
|
2005-05-06 09:22:53 +00:00
|
|
|
|
2003-12-19 18:16:01 +00:00
|
|
|
m_textbox.moveResize(2, m_label.height(),
|
2005-05-06 09:22:53 +00:00
|
|
|
width() - 4, m_textbox.font().height() + 2);
|
2003-12-19 18:16:01 +00:00
|
|
|
}
|