all repos — fluxbox @ dc47491533e0ca7cf5a5386a10e68fbaf873e9db

custom fork of the fluxbox windowmanager

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.
Mathias Gumz akira at fluxbox dot org
commit

dc47491533e0ca7cf5a5386a10e68fbaf873e9db

parent

716532dd47d718cb548da5f65b53a8b744ce235f

M src/ClientPattern.hhsrc/ClientPattern.hh

@@ -89,6 +89,7 @@ * If there are no terms, then there is assumed to be an error

* 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);
M src/FbCommands.ccsrc/FbCommands.cc

@@ -445,13 +445,12 @@

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; } }

@@ -541,5 +540,74 @@ }

break; }; } + + +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
M src/FbCommands.hhsrc/FbCommands.hh

@@ -218,6 +218,16 @@ Mode m_mode;

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
M src/FbTk/StringUtil.ccsrc/FbTk/StringUtil.cc

@@ -145,9 +145,16 @@

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
M src/FbTk/StringUtil.hhsrc/FbTk/StringUtil.hh

@@ -44,6 +44,7 @@ /// \@}

/// 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);
M src/Screen.ccsrc/Screen.cc

@@ -231,6 +231,22 @@ { FbWinFrame::RIGHT, "Right" },

{ 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 @@ m_root_window(scrn),

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 @@ m_restart(false),

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 @@ rootWindow().setEventMask(ColormapChangeMask | EnterWindowMask | PropertyChangeMask |

SubstructureRedirectMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask| SubstructureNotifyMask); - FbTk::App::instance()->sync(false); + fluxbox->sync(false); XSetErrorHandler((XErrorHandler) old);

@@ -370,12 +388,11 @@ (unsigned char *) &bpid, 1);

#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 @@ #endif // DEBUG

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 @@

// 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::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 @@

} 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 @@ return menu;

} 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 @@ int ijunk;

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 @@ }

// 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);
M util/fluxbox-remote.ccutil/fluxbox-remote.cc

@@ -21,50 +21,77 @@ // DEALINGS IN THE SOFTWARE.

#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); + + // assign the custom handler, clear the flag, sync the data, + // then check it for success/failure + error_cb = XSetErrorHandler(HandleIPCError); - char *str = argv[1]; - typedef int (*x_error_handler_t)(Display*,XErrorEvent*); + 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) { - // 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, + 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; }