add regular expression support in remember capabilities

see ChangeLog for details
This commit is contained in:
rathnor 2003-06-12 15:12:19 +00:00
parent 94f1c16416
commit e139cbb028
9 changed files with 657 additions and 124 deletions

View file

@ -1,4 +1,25 @@
(Format: Year/Month/Day)
Changes for 0.9.4:
*03/06/13:
* Regular expression support for remember (Simon)
Also ability to limit number of matches for a given rule
Also ability to match several different window attributes
Can disable in compile using --disable-regexp (will just do plain
string equality then)
- General format is:
[app] (property=expr) ... {number}
If "property=" is excluded, the name property is assumed.
If {number} is excluded, 0 = no limit is assumed.
- Current available properties are:
* name -> the name of the window - the first field of WM_CLASS
* class -> the class of the window - the second field of WM_CLASS
* title -> the title of the window - the WM_NAME property
- e.g. [app] (*[tT]erm) {2}
will match anything ending with term, for up to 2 instances
- e.g. [app] (title=.*gaim.*)
will match anything with gaim in the title ("gaim", "the gaim
window", etc.
RegExp.hh/cc ClientPattern.hh/cc configure.in Makefile.am Remember.hh/cc WinClient.hh/cc StringUtil.hh/cc
Changes for 0.9.3:
*03/06/08:
* Add Reconfigure and Restart Key actions, thanks Jann Fisher (Simon)

View file

@ -119,6 +119,32 @@ AC_ARG_ENABLE(
)
AM_CONDITIONAL(REMEMBER_SRC, test x$REMEMBER_SRC = xtrue)
AC_MSG_CHECKING([whether to have (POSIX) regular expression support])
AC_ARG_ENABLE(
regexp,
[ --enable-regexp regular expression support [default=yes]],
if test x$enableval = "xyes"; then
AC_EGREP_HEADER([regex_t],regex.h,
AC_DEFINE(USE_REGEXP, 1, "Regular Expression support")
AC_MSG_RESULT([yes])
REGEXP_SRC=true,
AC_MSG_RESULT([no])
REGEXP_SRC=false
)
else
AC_MSG_RESULT([no])
REGEXP_SRC=false
fi,
AC_EGREP_HEADER([regex_t],regex.h,
AC_DEFINE(USE_REGEXP, 1, "Regular Expression support")
AC_MSG_RESULT([yes])
REGEXP_SRC=true,
AC_MSG_RESULT([no])
REGEXP_SRC=false
)
)
AM_CONDITIONAL(REGEXP_SRC, test x$REGEXP_SRC = xtrue)
AC_MSG_CHECKING([whether to include the new WM Spec])
AC_ARG_ENABLE(
newwmspec,
@ -307,9 +333,6 @@ AC_ARG_ENABLE(
)
AC_MSG_CHECKING([whether to have Xmb (multibyte font, utf-8) support])
AC_ARG_ENABLE(
xmb,

235
src/ClientPattern.cc Normal file
View file

@ -0,0 +1,235 @@
// ClientPattern.cc for Fluxbox Window Manager
// Copyright (c) 2003 Henrik Kinnunen (fluxgen at users.sourceforge.net)
// 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.
// $Id: ClientPattern.cc,v 1.1 2003/06/12 15:12:19 rathnor Exp $
#include "ClientPattern.hh"
#include "RegExp.hh"
#include "StringUtil.hh"
#include "WinClient.hh"
//use GNU extensions
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif // _GNU_SOURCE
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <memory>
using namespace std;
/********************************************************
* ClientPattern *
***********/
ClientPattern::ClientPattern():
m_matchlimit(0),
m_nummatches(0) {}
// parse the given pattern (to end of line)
ClientPattern::ClientPattern(const char *str):
m_matchlimit(0),
m_nummatches(0)
{
/* A rough grammar of a pattern is:
PATTERN ::= MATCH+ LIMIT?
MATCH ::= '(' word ')'
| '(' propertyname '=' word ')'
LIMIT ::= '{' number '}'
i.e. one or more match definitions, followed by
an optional limit on the number of apps to match to
Match definitions are enclosed in parentheses, and if no
property name is given, then CLASSNAME is assumed.
If no limit is specified, no limit is applied (i.e. limit = infinity)
*/
int had_error = 0;
int pos = 0;
string match;
int err = 1; // for starting first loop
while (had_error == 0 && err > 0) {
err = FbTk::StringUtil::getStringBetween(match,
str + pos,
'(', ')', " \t\n", true);
if (err > 0) {
size_t eq = match.find_first_of('=');
if (eq == match.npos) {
if (!addTerm(match, NAME)) {
had_error = pos + match.find_first_of('(') + 1;
break;
}
} else {
// need to determine the property used
string memstr, expr;
WinProperty prop;
memstr.assign(match, 0, eq); // memstr = our identifier
expr.assign(match, eq+1, match.length());
if (strcasecmp(memstr.c_str(), "name") == 0) {
prop = NAME;
} else if (strcasecmp(memstr.c_str(), "class") == 0) {
prop = CLASS;
} else if (strcasecmp(memstr.c_str(), "title") == 0) {
prop = TITLE;
} else {
had_error = pos + match.find_first_of('(') + 1;
break;
}
if (!addTerm(expr, prop)) {
had_error = pos + ((str+pos) - index(str+pos, '=')) + 1;
break;
}
}
pos += err;
}
}
if (pos == 0 && had_error == 0) {
// no match terms given, this is not allowed
had_error = 1;
}
if (had_error == 0) {
// otherwise, we check for a number
string number;
err = FbTk::StringUtil::getStringBetween(number,
str+pos,
'{', '}');
if (err > 0) {
istringstream iss(number.c_str());
iss >> m_matchlimit;
pos+=err;
}
// we don't care if there isn't one
// there shouldn't be anything else on the line
match = str + pos;
err = match.find_first_not_of(" \t\n", pos);
if ((unsigned) err != match.npos) {
// found something, not good
had_error = err;
}
}
if (had_error > 0) {
m_matchlimit = had_error;
// delete all the terms
while (!m_terms.empty()) {
Term * term = m_terms.back();
delete term;
m_terms.pop_back();
}
}
}
ClientPattern::~ClientPattern() {
// delete all the terms
while (!m_terms.empty()) {
delete m_terms.back();
m_terms.pop_back();
}
}
// return a string representation of this pattern
std::string ClientPattern::toString() const {
string pat;
Terms::const_iterator it = m_terms.begin();
Terms::const_iterator it_end = m_terms.end();
for (; it != it_end; ++it) {
pat.append(" (");
if ((*it)->prop == NAME) {
// do nothing -> this is the default
} else if ((*it)->prop == CLASS) {
pat.append("class=");
} else if ((*it)->prop == TITLE) {
pat.append("title=");
} else {
#ifdef DEBUG
cerr<<"WARNING: unknown window property, can't save properly"<<endl;
#endif //DEBUG
}
pat.append((*it)->orig);
pat.append(")");
}
if (m_matchlimit > 0) {
char num[20];
sprintf(num, " {%d}", m_matchlimit);
pat.append(num);
}
return pat;
}
// does this client match this pattern?
bool ClientPattern::match(const WinClient &win) const {
if (m_matchlimit != 0 && m_nummatches >= m_matchlimit ||
m_terms.empty())
return false; // already matched out
// regmatch everything
// currently, we use an "AND" policy for multiple terms
// changing to OR would require minor modifications in this function only
Terms::const_iterator it = m_terms.begin();
Terms::const_iterator it_end = m_terms.end();
for (; it != it_end; ++it) {
if (!(*it)->regexp.match(getProperty((*it)->prop, win)))
return false;
}
return true;
}
// add an expression to match against
// The first argument is a regular expression, the second is the member
// function that we wish to match against.
bool ClientPattern::addTerm(const std::string &str, WinProperty prop) {
Term *term = new Term(str, true);
term->orig = str;
term->prop = prop;
if (term->regexp.error()) {
delete term;
return false;
}
m_terms.push_back(term);
return true;
}
std::string ClientPattern::getProperty(WinProperty prop, const WinClient &client) const {
switch (prop) {
case TITLE:
return client.getTitle();
break;
case CLASS:
return client.getWMClassClass();
break;
case NAME:
default:
return client.getWMClassName();
break;
}
}

99
src/ClientPattern.hh Normal file
View file

@ -0,0 +1,99 @@
// ClientPattern.hh for Fluxbox Window Manager
// Copyright (c) 2002 Xavier Brouckaert
// Copyright (c) 2003 Henrik Kinnunen (fluxgen at users.sourceforge.net)
// 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.
// $Id: ClientPattern.hh,v 1.1 2003/06/12 15:12:19 rathnor Exp $
#ifndef CLIENTPATTERN_HH
#define CLIENTPATTERN_HH
#include "RegExp.hh"
#include <string>
#include <list>
class WinClient;
/**
* This class represents a "pattern" that we can match against a
* Window based on various properties.
*/
class ClientPattern {
public:
ClientPattern();
// create the pattern from the given string as it would appear in the
// apps file. the bool value returns the character at which
// there was a parse problem, or -1.
explicit ClientPattern(const char * str);
~ClientPattern();
// return a string representation of this pattern
std::string toString() const;
enum WinProperty { TITLE, CLASS, NAME };
// does this client match this pattern?
bool match(const WinClient &win) const;
// add an expression to match against
// The first argument is a regular expression, the second is the member
// function that we wish to match against.
// returns false if the regexp wasn't valid
bool addTerm(const std::string &str, WinProperty prop);
inline void addMatch() { ++m_nummatches; }
inline void delMatch() { --m_nummatches; }
inline bool operator == (const WinClient &win) const {
return match(win);
}
// if there are no terms, then there is assumed to be an error
// the column of the error is stored in m_matchlimit
inline int error() { return (m_terms.empty())?m_matchlimit:0; }
std::string getProperty(WinProperty prop, const WinClient &winclient) const;
private:
// This is the type of the actual pattern we want to match against
// We have a "term" in the whole expression which is the full pattern
// we also need to keep track of the uncompiled regular expression
// for final output
struct Term {
Term(const std::string &regstr, bool full_match) :regexp(regstr, full_match){};
std::string orig;
RegExp regexp;
WinProperty prop;
};
// our pattern is made up of a sequence of terms
// currently we "and" them all
typedef std::list<Term *> Terms;
Terms m_terms;
int m_matchlimit, m_nummatches;
};
#endif // CLIENTPATTERN_HH

View file

@ -48,6 +48,10 @@ gnome_SOURCE= Gnome.hh Gnome.cc
endif
if REMEMBER_SRC
REMEMBER_SOURCE= Remember.hh Remember.cc
# For now we only want regexp if we have remember
if REGEXP_SRC
REGEXP_SOURCE = RegExp.hh RegExp.cc ClientPattern.hh ClientPattern.cc
endif
endif
fluxbox_SOURCES = AtomHandler.hh ArrowButton.hh ArrowButton.cc \
@ -76,7 +80,7 @@ fluxbox_SOURCES = AtomHandler.hh ArrowButton.hh ArrowButton.cc \
IntResMenuItem.hh IntResMenuItem.cc FbMenu.hh \
WinClient.hh WinClient.cc \
Xinerama.hh \
${REMEMBER_SOURCE}
${REMEMBER_SOURCE} ${REGEXP_SOURCE}
LDADD=FbTk/libFbTk.a

94
src/RegExp.cc Normal file
View file

@ -0,0 +1,94 @@
// RegExp.cc for Fluxbox Window Manager
// Copyright (c) 2003 Henrik Kinnunen (fluxgen at users.sourceforge.net)
// 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.
// $Id: RegExp.cc,v 1.1 2003/06/12 15:12:19 rathnor Exp $
#include "RegExp.hh"
//use GNU extensions
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif // _GNU_SOURCE
#include <string>
#include <iostream>
using namespace std;
/********************************************************
* RegExp *
***********/
// full_match is to say if we match on this regexp using the full string
// or just a substring. Substrings aren't supported if not HAVE_REGEXP
RegExp::RegExp(const std::string &str, bool full_match):
#ifdef USE_REGEXP
m_regex(0) {
string match;
if (full_match) {
match = "^";
match.append(str);
match.append("$");
} else {
match = str;
}
m_regex = new regex_t;
int ret = regcomp(m_regex, match.c_str(), REG_NOSUB | REG_EXTENDED);
if (ret != 0) {
char *errstr = 0;
// gives us the length of the string
unsigned int size = regerror(ret, m_regex, errstr, 0);
errstr = new char[size];
regerror(ret, m_regex, errstr, size);
cerr<<"Error parsing regular expression: "<<errstr<<endl;
delete [] errstr;
delete m_regex; // I don't think I regfree a failed compile?
m_regex = 0;
}
}
#else // notdef USE_REGEXP
m_str(str) {}
#endif // USE_REGEXP
RegExp::~RegExp() {
#ifdef USE_REGEXP
if (m_regex != 0) {
regfree(m_regex);
delete m_regex;
}
#endif // USE_REGEXP
}
bool RegExp::match(const std::string &str) {
#ifdef USE_REGEXP
if (m_regex)
return (regexec(m_regex, str.c_str(), 0, 0, 0) == 0);
else
return false;
#else // notdef USE_REGEXP
return (m_str == str);
#endif // USE_REGEXP
}

66
src/RegExp.hh Normal file
View file

@ -0,0 +1,66 @@
// RegExp.hh for Fluxbox Window Manager
// Copyright (c) 2002 Xavier Brouckaert
// Copyright (c) 2003 Henrik Kinnunen (fluxgen at users.sourceforge.net)
// 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.
// $Id: RegExp.hh,v 1.1 2003/06/12 15:12:19 rathnor Exp $
#ifndef REGEXP_HH
#define REGEXP_HH
#include "config.h"
#include <string>
/*
* If USE_REGEXP isn't defined, then we match just using simple string equality
*/
#ifdef USE_REGEXP
#include <regex.h>
#include <sys/types.h>
#endif // USE_REGEXP
class WinClient;
class RegExp {
public:
RegExp(const std::string &str, bool full_match = true);
~RegExp();
bool match(const std::string &str);
#ifdef USE_REGEXP
inline bool error() { return m_regex == 0; }
#else // notdef USE_REGEXP
inline bool error() { return m_str == ""; }
#endif // USE_REGEXP
private:
#ifdef USE_REGEXP
regex_t* m_regex;
#else // notdef USE_REGEXP
std::string m_str;
#endif // USE_REGEXP
};
#endif // REGEXP_HH

View file

@ -21,9 +21,10 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
// $Id: Remember.cc,v 1.23 2003/06/06 14:07:22 rathnor Exp $
// $Id: Remember.cc,v 1.24 2003/06/12 15:12:19 rathnor Exp $
#include "Remember.hh"
#include "ClientPattern.hh"
#include "StringUtil.hh"
#include "Screen.hh"
#include "Window.hh"
@ -125,32 +126,7 @@ FbTk::Menu *createRememberMenu(Remember &remember, FluxboxWindow &win) {
return menu;
};
std::string getWMClass(Window w) {
XClassHint ch;
if (XGetClassHint(FbTk::App::instance()->display(), w, &ch) == 0) {
cerr<<"Failed to read class hint!"<<endl;
return "";
} else {
string instance_name;
if (ch.res_name != 0) {
instance_name = const_cast<char *>(ch.res_name);
XFree(ch.res_name);
} else
instance_name = "";
if (ch.res_class != 0) {
//m_class_name = const_cast<char *>(ch.res_class);
XFree(ch.res_class);
} else {
//m_class_name = "";
}
return instance_name;
}
}
};
}; // end anonymous namespace
Application::Application() {
workspace_remember =
@ -165,35 +141,56 @@ Application::Application() {
save_on_close_remember = false;
}
/********************************************************
* Remember *
************/
Remember::Remember() {
load();
}
Application* Remember::add(const char* app_name) {
if (!app_name)
return 0;
Application* a = new Application();
apps[app_name] = a;
return a;
Remember::~Remember() {
// free our resources
// the patterns free the "Application"s
// the client mapping shouldn't need cleaning
Patterns::iterator it;
while (!m_pats.empty()) {
it = m_pats.begin();
delete it->first; // ClientPattern
delete it->second; // Application
m_pats.erase(it);
}
}
Application* Remember::find(WinClient &winclient) {
return find(getWMClass(winclient.window()).c_str());
// if it is already associated with a application, return that one
// otherwise, check it against every pattern that we've got
Clients::iterator wc_it = m_clients.find(&winclient);
if (wc_it != m_clients.end())
return wc_it->second;
else {
Patterns::iterator it = m_pats.begin();
for (; it != m_pats.end(); it++)
if (it->first->match(winclient)) {
it->first->addMatch();
m_clients[&winclient] = it->second;
return it->second;
}
}
// oh well, no matches
return 0;
}
Application* Remember::add(WinClient &winclient) {
return add(getWMClass(winclient.window()).c_str());
}
Application* Remember::find(const char* app_name) {
if (!app_name)
return 0;
Apps::iterator i = apps.find(app_name);
if (i != apps.end())
return i->second;
else
return 0;
Application * Remember::add(WinClient &winclient) {
ClientPattern *p = new ClientPattern();
Application *app = new Application();
// by default, we match against the WMClass of a window.
p->addTerm(p->getProperty(ClientPattern::NAME, winclient), ClientPattern::NAME);
m_clients[&winclient] = app;
p->addMatch();
m_pats.push_back(make_pair(p, app));
return app;
}
int Remember::parseApp(ifstream &file, Application &app) {
@ -315,31 +312,24 @@ void Remember::load() {
if (line[0] == '#')
continue;
string key;
int pos=0;
int err = FbTk::StringUtil::getStringBetween(key,
int err=0;
int pos = FbTk::StringUtil::getStringBetween(key,
line.c_str(),
'[', ']');
if (err > 0 && key == "app") {
pos += err;
string label;
err = FbTk::StringUtil::getStringBetween(label,
line.c_str()+pos,
'(', ')');
if (err>0) {
Application *app = 0;
Apps::iterator i = apps.find(label);
if (i == apps.end()) {
app = new Application();
apps[label] = app;
} else
app = i->second;
if (pos > 0 && key == "app") {
ClientPattern *pat = new ClientPattern(line.c_str() + pos);
if ((err = pat->error()) == 0) {
Application *app = new Application();
m_pats.push_back(make_pair(pat, app));
row += parseApp(apps_file, *app);
} else
cerr<<"Error1 in apps file. Line("<<row<<")"<<endl;
} else {
cerr<<"Error reading apps file at line "<<row<<", column "<<(err+pos)<<"."<<endl;
delete pat; // since it didn't work
}
} else
cerr<<"Error2 in apps file. Line("<<row<<")"<<endl;
cerr<<"Error in apps file on line "<<row<<"."<<endl;
}
} else {
#ifdef DEBUG
@ -358,28 +348,28 @@ void Remember::save() {
string apps_string;
Fluxbox::instance()->getDefaultDataFilename("apps", apps_string);
ofstream apps_file(apps_string.c_str());
Apps::iterator it = apps.begin();
Apps::iterator it_end = apps.end();
Patterns::iterator it = m_pats.begin();
Patterns::iterator it_end = m_pats.end();
for (; it != it_end; ++it) {
apps_file << "[app] (" << it->first << ")" << endl;
Application *a = it->second;
if (a->workspace_remember) {
apps_file << " [Workspace]\t{" << a->workspace << "}" << endl;
apps_file << "[app]"<<it->first->toString()<<endl;
Application &a = *it->second;
if (a.workspace_remember) {
apps_file << " [Workspace]\t{" << a.workspace << "}" << endl;
}
if (a->dimensions_remember) {
apps_file << " [Dimensions]\t{" << a->w << " " << a->h << "}" << endl;
if (a.dimensions_remember) {
apps_file << " [Dimensions]\t{" << a.w << " " << a.h << "}" << endl;
}
if (a->position_remember) {
apps_file << " [Position]\t{" << a->x << " " << a->y << "}" << endl;
if (a.position_remember) {
apps_file << " [Position]\t{" << a.x << " " << a.y << "}" << endl;
}
if (a->shadedstate_remember) {
apps_file << " [Shaded]\t{" << ((a->shadedstate)?"yes":"no") << "}" << endl;
if (a.shadedstate_remember) {
apps_file << " [Shaded]\t{" << ((a.shadedstate)?"yes":"no") << "}" << endl;
}
if (a->tabstate_remember) {
apps_file << " [Tab]\t\t{" << ((a->tabstate)?"yes":"no") << "}" << endl;
if (a.tabstate_remember) {
apps_file << " [Tab]\t\t{" << ((a.tabstate)?"yes":"no") << "}" << endl;
}
if (a->decostate_remember) {
switch (a->decostate) {
if (a.decostate_remember) {
switch (a.decostate) {
case (0) :
apps_file << " [Deco]\t{NONE}" << endl;
break;
@ -401,21 +391,21 @@ void Remember::save() {
apps_file << " [Deco]\t{BORDER}" << endl;
break;
default:
apps_file << " [Deco]\t{0x"<<hex<<a->decostate<<dec<<"}"<<endl;
apps_file << " [Deco]\t{0x"<<hex<<a.decostate<<dec<<"}"<<endl;
break;
}
}
if (a->stuckstate_remember) {
apps_file << " [Sticky]\t{" << ((a->stuckstate)?"yes":"no") << "}" << endl;
if (a.stuckstate_remember) {
apps_file << " [Sticky]\t{" << ((a.stuckstate)?"yes":"no") << "}" << endl;
}
if (a->jumpworkspace_remember) {
apps_file << " [Jump]\t{" << ((a->jumpworkspace)?"yes":"no") << "}" << endl;
if (a.jumpworkspace_remember) {
apps_file << " [Jump]\t{" << ((a.jumpworkspace)?"yes":"no") << "}" << endl;
}
if (a->layer_remember) {
apps_file << " [Layer]\t{" << a->layer << "}" << endl;
if (a.layer_remember) {
apps_file << " [Layer]\t{" << a.layer << "}" << endl;
}
if (a->save_on_close_remember) {
apps_file << " [Close]\t{" << ((a->save_on_close)?"yes":"no") << "}" << endl;
if (a.save_on_close_remember) {
apps_file << " [Close]\t{" << ((a.save_on_close)?"yes":"no") << "}" << endl;
}
apps_file << "[end]" << endl;
}
@ -563,6 +553,7 @@ void Remember::setupWindow(FluxboxWindow &win) {
if (winclient.transientFor()) {
// still put something in the menu so people don't get confused
// so, we add a disabled item...
// TODO: nls
FbTk::MenuItem *item = new FbTk::MenuItem("Remember...");
item->setEnabled(false);
win.menu().insert(item, menupos);
@ -623,10 +614,15 @@ void Remember::setupWindow(FluxboxWindow &win) {
void Remember::updateWindowClose(FluxboxWindow &win) {
// This doesn't work at present since fluxbox.cc is missing the windowclose stuff.
// I don't trust it (particularly winClient()) while this is the case
return;
WinClient &winclient = win.winClient();
Application *app = find(winclient);
Clients::iterator wc_it = m_clients.find(&win.winClient());
if (wc_it != m_clients.end())
m_clients.erase(wc_it);
if (!app || !(app->save_on_close_remember && app->save_on_close))
return;
@ -636,23 +632,6 @@ void Remember::updateWindowClose(FluxboxWindow &win) {
rememberAttrib(winclient, (Attribute) attrib);
}
}
/*
if (app->workspace_remember)
app->rememberWorkspace(win.workspaceNumber());
if (app->dimensions_remember)
app->rememberDimensions(win.width(), win.height());
if (app->position_remember)
app->rememberPosition(win.x(), win.y());
if (app->shadedstate_remember)
app->rememberShadedstate(win.isShaded());
// external tabs off atm
//if (app->tabstate_remember) ...
if (app->decostate_remember)
app->rememberDecostate(win.decorationMask());
if (app->stuckstate_remember)
app->rememberStuckstate(win.isStuck());
if (app->jumpworkspace_remember)
app->rememberJumpworkspace(true);
*/
save();
}

View file

@ -21,7 +21,7 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
// $Id: Remember.hh,v 1.6 2003/06/05 13:33:27 fluxgen Exp $
// $Id: Remember.hh,v 1.7 2003/06/12 15:12:19 rathnor Exp $
/* Based on the original "Remember patch" by Xavier Brouckaert */
@ -32,7 +32,14 @@
#include <fstream>
#include <map>
#include <list>
#include <string>
#include <utility>
class FluxboxWindow;
class BScreen;
class WinClient;
class ClientPattern;
class Application {
public:
@ -99,13 +106,9 @@ public:
bool save_on_close_remember;
bool save_on_close;
};
class FluxboxWindow;
class BScreen;
class WinClient;
/**
* Class Remember is an atomhandler to avoid interfering with
* the main code as much as possible, since we hope that one day
@ -132,13 +135,21 @@ public:
REM_LASTATTRIB // not actually used
};
typedef std::map<std::string, Application *> Apps;
// a "pattern" to the relevant app
// each app exists ONLY for that pattern.
// And we need to keep a list of pairs as we want to keep the
// applications in the same order as they will be in the apps file
typedef std::list< std::pair<ClientPattern *, Application *> > Patterns;
// We keep track of which app is assigned to a winclient
// particularly useful to update counters etc on windowclose
typedef std::map<WinClient *, Application *> Clients;
Remember();
~Remember();
Application* find(WinClient &winclient);
Application* find(const char* app_name);
Application* add(WinClient &winclient);
Application* add(const char* app_name);
void load();
void save();
@ -176,7 +187,8 @@ private:
// returns number of lines read
int parseApp(std::ifstream &file, Application &app);
Apps apps;
Patterns m_pats;
Clients m_clients;
};