Adds 'ClientPatternTest' command
ClientPatterns might be tricky to get right. Instead of fiddling around in either the keys-file or the apps-file and restarting fluxbox to see if the changes had any effect / matched the right windows, 'ClientPatternTest' and the fluxbox-remote should make this easier: $> fluxbox-remote "clientpatterntest (title=.*vim*)" This causes fluxbox to store the list of matched windows in the _FLUXBOX_ACTION_RESULT property onto the rootwindow. This property might then be read by: $> xprop -root _FLUXBOX_ACTION_RESULT or $> fluxbox-remote result The format of the list is: win_id \t title_of_window \n win_id is '-1' when fluxbox wasn't able to parse the given ClientPattern. win_id is '0' when there are no windows matching the given ClientPattern.
This commit is contained in:
parent
716532dd47
commit
dc47491533
7 changed files with 177 additions and 53 deletions
|
@ -89,6 +89,7 @@ public:
|
|||
* the column of the error is stored in m_matchlimit
|
||||
*/
|
||||
int error() const { return m_terms.empty() ? 1 : 0; }
|
||||
int error_col() const { return m_matchlimit; }
|
||||
|
||||
static FbTk::FbString getProperty(WinProperty prop, const Focusable &client);
|
||||
|
||||
|
|
|
@ -445,13 +445,12 @@ REGISTER_UNTRUSTED_COMMAND_WITH_ARGS(bindkey, FbCommands::BindKeyCmd, void);
|
|||
BindKeyCmd::BindKeyCmd(const string &keybind):m_keybind(keybind) { }
|
||||
|
||||
void BindKeyCmd::execute() {
|
||||
if (Fluxbox::instance()->keys() != 0) {
|
||||
if (Fluxbox::instance()->keys()->addBinding(m_keybind)) {
|
||||
ofstream ofile(Fluxbox::instance()->keys()->filename().c_str(), ios::app);
|
||||
if (!ofile)
|
||||
return;
|
||||
ofile<<m_keybind<<endl;
|
||||
}
|
||||
Keys* keys = Fluxbox::instance()->keys();
|
||||
if (keys && keys->addBinding(m_keybind)) {
|
||||
ofstream ofile(keys->filename().c_str(), ios::app);
|
||||
if (!ofile)
|
||||
return;
|
||||
ofile<<m_keybind<<endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -542,4 +541,73 @@ void DeiconifyCmd::execute() {
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
REGISTER_COMMAND_WITH_ARGS(clientpatterntest, FbCommands::ClientPatternTestCmd, void);
|
||||
|
||||
void ClientPatternTestCmd::execute() {
|
||||
|
||||
std::vector< const FluxboxWindow* > matches;
|
||||
std::string result;
|
||||
std::string pat;
|
||||
int opts;
|
||||
ClientPattern* cp;
|
||||
Display* dpy;
|
||||
Atom atom_utf8;
|
||||
Atom atom_fbcmd_result;
|
||||
Fluxbox::ScreenList::const_iterator screen;
|
||||
const Fluxbox::ScreenList screens(Fluxbox::instance()->screenList());
|
||||
|
||||
dpy = Fluxbox::instance()->display();
|
||||
atom_utf8 = XInternAtom(dpy, "UTF8_STRING", False);
|
||||
atom_fbcmd_result = XInternAtom(dpy, "_FLUXBOX_ACTION_RESULT", False);
|
||||
|
||||
FocusableList::parseArgs(m_args, opts, pat);
|
||||
cp = new ClientPattern(pat.c_str());
|
||||
|
||||
if (!cp->error()) {
|
||||
|
||||
const FocusableList* windows;
|
||||
FocusControl::Focusables::const_iterator wit;
|
||||
FocusControl::Focusables::const_iterator wit_end;
|
||||
|
||||
for (screen = screens.begin(); screen != screens.end(); screen++) {
|
||||
|
||||
windows = FocusableList::getListFromOptions(**screen, opts|FocusableList::LIST_GROUPS);
|
||||
wit = windows->clientList().begin();
|
||||
wit_end = windows->clientList().end();
|
||||
|
||||
for ( ; wit != wit_end; wit++) {
|
||||
if (typeid(**wit) == typeid(FluxboxWindow) && cp->match(**wit)) {
|
||||
matches.push_back(static_cast<const FluxboxWindow*>(*wit));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!matches.empty()) {
|
||||
std::vector< const FluxboxWindow* >::const_iterator win;
|
||||
for (win = matches.begin(); win != matches.end(); win++) {
|
||||
result += "0x";
|
||||
result += FbTk::StringUtil::number2HexString((*win)->clientWindow());
|
||||
result += "\t";
|
||||
result += (*win)->title().logical();
|
||||
result += "\n";
|
||||
}
|
||||
} else {
|
||||
result += "0\n";
|
||||
}
|
||||
} else {
|
||||
result = "-1\t";
|
||||
result += FbTk::StringUtil::number2String(cp->error_col());
|
||||
result += "\n";
|
||||
}
|
||||
|
||||
|
||||
// write result to _FLUXBOX_ACTION_RESULT property
|
||||
for (screen = screens.begin(); screen != screens.end(); screen++) {
|
||||
(*screen)->rootWindow().changeProperty(atom_fbcmd_result, atom_utf8, 8,
|
||||
PropModeReplace, (unsigned char*)result.c_str(), result.size());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // end namespace FbCommands
|
||||
|
|
|
@ -218,6 +218,16 @@ private:
|
|||
Destination m_dest;
|
||||
};
|
||||
|
||||
|
||||
/// test client pattern
|
||||
class ClientPatternTestCmd: public FbTk::Command<void> {
|
||||
public:
|
||||
ClientPatternTestCmd(const std::string& args) : m_args(args) { };
|
||||
void execute();
|
||||
private:
|
||||
std::string m_args;
|
||||
};
|
||||
|
||||
} // end namespace FbCommands
|
||||
|
||||
#endif // FBCOMMANDS_HH
|
||||
|
|
|
@ -145,10 +145,17 @@ int extractNumber(const std::string& in, unsigned long long& out) {
|
|||
|
||||
std::string number2String(long long num) {
|
||||
char s[128];
|
||||
sprintf(s, "%lld", num);
|
||||
snprintf(s, sizeof(s), "%lld", num);
|
||||
return std::string(s);
|
||||
}
|
||||
|
||||
std::string number2HexString(long long num) {
|
||||
char s[17];
|
||||
snprintf(s, sizeof(s), "%lx", num);
|
||||
return std::string(s);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Tries to find a string in another and
|
||||
ignoring the case of the characters
|
||||
|
|
|
@ -44,6 +44,7 @@ int extractNumber(const std::string& in, unsigned long long& out);
|
|||
|
||||
/// creates a number to a string
|
||||
std::string number2String(long long num);
|
||||
std::string number2HexString(long long num);
|
||||
|
||||
/// Similar to `strstr' but this function ignores the case of both strings
|
||||
const char *strcasestr(const char *str, const char *ptn);
|
||||
|
|
|
@ -231,6 +231,22 @@ const TabPlacementString placement_strings[] = {
|
|||
{ FbWinFrame::RIGHTTOP, "RightTop" }
|
||||
};
|
||||
|
||||
Atom atom_fbcmd = 0;
|
||||
Atom atom_wm_check = 0;
|
||||
Atom atom_net_desktop = 0;
|
||||
Atom atom_utf8_string = 0;
|
||||
Atom atom_kde_systray = 0;
|
||||
Atom atom_kwm1 = 0;
|
||||
|
||||
void initAtoms(Display* dpy) {
|
||||
atom_wm_check = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
|
||||
atom_net_desktop = XInternAtom(dpy, "_NET_CURRENT_DESKTOP", False);
|
||||
atom_fbcmd = XInternAtom(dpy, "_FLUXBOX_ACTION", False);
|
||||
atom_utf8_string = XInternAtom(dpy, "UTF8_STRING", False);
|
||||
atom_kde_systray = XInternAtom(dpy, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False);
|
||||
atom_kwm1 = XInternAtom(dpy, "KWM_DOCKWINDOW", False);
|
||||
}
|
||||
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
|
@ -317,8 +333,7 @@ BScreen::BScreen(FbTk::ResourceManager &rm,
|
|||
m_geom_window(new OSDWindow(m_root_window, *this, *m_focused_windowtheme)),
|
||||
m_pos_window(new OSDWindow(m_root_window, *this, *m_focused_windowtheme)),
|
||||
m_tooltip_window(new TooltipWindow(m_root_window, *this, *m_focused_windowtheme)),
|
||||
m_dummy_window(scrn, -1, -1, 1, 1, 0, true, false, CopyFromParent,
|
||||
InputOnly),
|
||||
m_dummy_window(scrn, -1, -1, 1, 1, 0, true, false, CopyFromParent, InputOnly),
|
||||
resource(rm, screenname, altscreenname),
|
||||
m_resource_manager(rm),
|
||||
m_name(screenname),
|
||||
|
@ -331,8 +346,11 @@ BScreen::BScreen(FbTk::ResourceManager &rm,
|
|||
m_shutdown(false) {
|
||||
|
||||
|
||||
Display *disp = m_root_window.display();
|
||||
Fluxbox *fluxbox = Fluxbox::instance();
|
||||
Display *disp = fluxbox->display();
|
||||
|
||||
initAtoms(disp);
|
||||
|
||||
|
||||
// TODO fluxgen: check if this is the right place (it was not -lis)
|
||||
//
|
||||
|
@ -349,7 +367,7 @@ BScreen::BScreen(FbTk::ResourceManager &rm,
|
|||
SubstructureRedirectMask | KeyPressMask | KeyReleaseMask |
|
||||
ButtonPressMask | ButtonReleaseMask| SubstructureNotifyMask);
|
||||
|
||||
FbTk::App::instance()->sync(false);
|
||||
fluxbox->sync(false);
|
||||
|
||||
XSetErrorHandler((XErrorHandler) old);
|
||||
|
||||
|
@ -370,12 +388,11 @@ BScreen::BScreen(FbTk::ResourceManager &rm,
|
|||
#endif // HAVE_GETPID
|
||||
|
||||
// check if we're the first EWMH compliant window manager on this screen
|
||||
Atom wm_check = XInternAtom(disp, "_NET_SUPPORTING_WM_CHECK", False);
|
||||
Atom xa_ret_type;
|
||||
int ret_format;
|
||||
unsigned long ret_nitems, ret_bytes_after;
|
||||
unsigned char *ret_prop;
|
||||
if (rootWindow().property(wm_check, 0l, 1l,
|
||||
if (rootWindow().property(atom_wm_check, 0l, 1l,
|
||||
False, XA_WINDOW, &xa_ret_type, &ret_format, &ret_nitems,
|
||||
&ret_bytes_after, &ret_prop) ) {
|
||||
m_restart = (ret_prop != NULL);
|
||||
|
@ -415,7 +432,7 @@ BScreen::BScreen(FbTk::ResourceManager &rm,
|
|||
|
||||
FbTk::EventManager *evm = FbTk::EventManager::instance();
|
||||
evm->add(*this, rootWindow());
|
||||
Keys *keys = Fluxbox::instance()->keys();
|
||||
Keys *keys = fluxbox->keys();
|
||||
if (keys)
|
||||
keys->registerWindow(rootWindow().window(), *this,
|
||||
Keys::GLOBAL|Keys::ON_DESKTOP);
|
||||
|
@ -476,9 +493,8 @@ BScreen::BScreen(FbTk::ResourceManager &rm,
|
|||
// check which desktop we should start on
|
||||
unsigned int first_desktop = 0;
|
||||
if (m_restart) {
|
||||
Atom net_desktop = XInternAtom(disp, "_NET_CURRENT_DESKTOP", False);
|
||||
bool exists;
|
||||
unsigned int ret=static_cast<unsigned int>(rootWindow().cardinalProperty(net_desktop, &exists));
|
||||
unsigned int ret=static_cast<unsigned int>(rootWindow().cardinalProperty(atom_net_desktop, &exists));
|
||||
if (exists) {
|
||||
if (ret < static_cast<unsigned int>(nr_ws))
|
||||
first_desktop = ret;
|
||||
|
@ -764,29 +780,29 @@ void BScreen::focusedWinFrameThemeReconfigured() {
|
|||
}
|
||||
|
||||
void BScreen::propertyNotify(Atom atom) {
|
||||
static Atom fbcmd_atom = XInternAtom(FbTk::App::instance()->display(),
|
||||
"_FLUXBOX_ACTION", False);
|
||||
if (allowRemoteActions() && atom == fbcmd_atom) {
|
||||
|
||||
if (allowRemoteActions() && atom == atom_fbcmd) {
|
||||
Atom xa_ret_type;
|
||||
int ret_format;
|
||||
unsigned long ret_nitems, ret_bytes_after;
|
||||
char *str;
|
||||
if (rootWindow().property(fbcmd_atom, 0l, 64l,
|
||||
if (rootWindow().property(atom_fbcmd, 0l, 64l,
|
||||
True, XA_STRING, &xa_ret_type, &ret_format, &ret_nitems,
|
||||
&ret_bytes_after, (unsigned char **)&str) && str) {
|
||||
|
||||
if (ret_bytes_after) {
|
||||
XFree(str);
|
||||
long len = 64 + (ret_bytes_after + 3)/4;
|
||||
rootWindow().property(fbcmd_atom, 0l, len,
|
||||
rootWindow().property(atom_fbcmd, 0l, len,
|
||||
True, XA_STRING, &xa_ret_type, &ret_format, &ret_nitems,
|
||||
&ret_bytes_after, (unsigned char **)&str);
|
||||
}
|
||||
|
||||
static std::auto_ptr<FbTk::Command<void> > cmd(0);
|
||||
cmd.reset(FbTk::CommandParser<void>::instance().parse(str, false));
|
||||
if (cmd.get())
|
||||
if (cmd.get()) {
|
||||
cmd->execute();
|
||||
}
|
||||
XFree(str);
|
||||
|
||||
}
|
||||
|
@ -852,9 +868,8 @@ void BScreen::cycleFocus(int options, const ClientPattern *pat, bool reverse) {
|
|||
}
|
||||
|
||||
FbMenu *BScreen::createMenu(const string &label) {
|
||||
FbMenu *menu = new FbMenu(menuTheme(),
|
||||
imageControl(),
|
||||
*layerManager().getLayer(ResourceLayer::MENU));
|
||||
FbTk::Layer* layer = layerManager().getLayer(ResourceLayer::MENU);
|
||||
FbMenu *menu = new FbMenu(menuTheme(), imageControl(), *layer);
|
||||
if (!label.empty())
|
||||
menu->setLabel(label);
|
||||
|
||||
|
@ -862,9 +877,8 @@ FbMenu *BScreen::createMenu(const string &label) {
|
|||
}
|
||||
|
||||
FbMenu *BScreen::createToggleMenu(const string &label) {
|
||||
FbMenu *menu = new ToggleMenu(menuTheme(),
|
||||
imageControl(),
|
||||
*layerManager().getLayer(ResourceLayer::MENU));
|
||||
FbTk::Layer* layer = layerManager().getLayer(ResourceLayer::MENU);
|
||||
FbMenu *menu = new ToggleMenu(menuTheme(), imageControl(), *layer);
|
||||
if (!label.empty())
|
||||
menu->setLabel(label);
|
||||
|
||||
|
@ -1177,9 +1191,7 @@ bool BScreen::isKdeDockapp(Window client) const {
|
|||
unsigned long *data = 0, uljunk;
|
||||
Display *disp = FbTk::App::instance()->display();
|
||||
// Check if KDE v2.x dock applet
|
||||
if (XGetWindowProperty(disp, client,
|
||||
XInternAtom(FbTk::App::instance()->display(),
|
||||
"_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False),
|
||||
if (XGetWindowProperty(disp, client, atom_kde_systray,
|
||||
0l, 1l, False,
|
||||
XA_WINDOW, &ajunk, &ijunk, &uljunk,
|
||||
&uljunk, (unsigned char **) &data) == Success) {
|
||||
|
@ -1192,11 +1204,9 @@ bool BScreen::isKdeDockapp(Window client) const {
|
|||
|
||||
// Check if KDE v1.x dock applet
|
||||
if (!iskdedockapp) {
|
||||
Atom kwm1 = XInternAtom(FbTk::App::instance()->display(),
|
||||
"KWM_DOCKWINDOW", False);
|
||||
if (XGetWindowProperty(disp, client,
|
||||
kwm1, 0l, 1l, False,
|
||||
kwm1, &ajunk, &ijunk, &uljunk,
|
||||
atom_kwm1, 0l, 1l, False,
|
||||
atom_kwm1, &ajunk, &ijunk, &uljunk,
|
||||
&uljunk, (unsigned char **) &data) == Success && data) {
|
||||
iskdedockapp = (data && data[0] != 0);
|
||||
XFree((void *) data);
|
||||
|
|
|
@ -21,50 +21,77 @@
|
|||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
bool g_gotError;
|
||||
|
||||
bool g_gotError = false;
|
||||
static int HandleIPCError(Display *disp, XErrorEvent*ptr)
|
||||
{
|
||||
// ptr->error_code contains the actual error flags
|
||||
g_gotError=true;
|
||||
g_gotError = true;
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
typedef int (*xerror_cb_t)(Display*,XErrorEvent*);
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
int rc;
|
||||
Display* disp;
|
||||
Window root;
|
||||
Atom atom_utf8;
|
||||
Atom atom_fbcmd;
|
||||
Atom atom_result;
|
||||
xerror_cb_t error_cb;
|
||||
char* cmd;
|
||||
|
||||
if (argc <= 1) {
|
||||
printf("fluxbox-remote <fluxbox-command>\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
Display *disp = XOpenDisplay(NULL);
|
||||
disp = XOpenDisplay(NULL);
|
||||
if (!disp) {
|
||||
perror("error, can't open display.");
|
||||
return EXIT_FAILURE;
|
||||
return rc;
|
||||
}
|
||||
|
||||
Atom fbcmd_atom = XInternAtom(disp, "_FLUXBOX_ACTION", False);
|
||||
Window root = DefaultRootWindow(disp);
|
||||
cmd = argv[1];
|
||||
atom_utf8 = XInternAtom(disp, "UTF8_STRING", False);
|
||||
atom_fbcmd = XInternAtom(disp, "_FLUXBOX_ACTION", False);
|
||||
atom_result = XInternAtom(disp, "_FLUXBOX_ACTION_RESULT", False);
|
||||
root = DefaultRootWindow(disp);
|
||||
|
||||
char *str = argv[1];
|
||||
// assign the custom handler, clear the flag, sync the data,
|
||||
// then check it for success/failure
|
||||
error_cb = XSetErrorHandler(HandleIPCError);
|
||||
|
||||
typedef int (*x_error_handler_t)(Display*,XErrorEvent*);
|
||||
|
||||
// assign the custom handler, clear the flag, sync the data, then check it for success/failure
|
||||
x_error_handler_t handler = XSetErrorHandler( HandleIPCError );
|
||||
g_gotError=false;
|
||||
XChangeProperty(disp, root, fbcmd_atom,
|
||||
if (strcmp(cmd, "result") == 0) {
|
||||
XTextProperty text_prop;
|
||||
if (XGetTextProperty(disp, root, &text_prop, atom_result) != 0
|
||||
&& text_prop.value > 0
|
||||
&& text_prop.nitems > 0) {
|
||||
|
||||
printf("%s", text_prop.value);
|
||||
XFree(text_prop.value);
|
||||
}
|
||||
} else {
|
||||
XChangeProperty(disp, root, atom_fbcmd,
|
||||
XA_STRING, 8, PropModeReplace,
|
||||
(unsigned char *) str, strlen(str));
|
||||
XSync(disp,False);
|
||||
int ret=(g_gotError?EXIT_FAILURE:EXIT_SUCCESS);
|
||||
XSetErrorHandler(handler);
|
||||
(unsigned char *)cmd, strlen(cmd));
|
||||
XSync(disp, false);
|
||||
}
|
||||
|
||||
rc = (g_gotError ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||
|
||||
XSetErrorHandler(error_cb);
|
||||
XCloseDisplay(disp);
|
||||
|
||||
return ret;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue