diff --git a/client.cpp b/client.cpp index ac66746da8..f7ffa31c2d 100644 --- a/client.cpp +++ b/client.cpp @@ -262,7 +262,7 @@ void Client::releaseWindow(bool on_shutdown) emit clientFinishUserMovedResized(this); emit windowClosed(this, del); finishCompositing(); - workspace()->discardUsedWindowRules(this, true); // Remove ForceTemporarily rules + RuleBook::self()->discardUsed(this, true); // Remove ForceTemporarily rules StackingUpdatesBlocker blocker(workspace()); if (moveResizeMode) leaveMoveResize(); @@ -330,7 +330,7 @@ void Client::destroyClient() emit clientFinishUserMovedResized(this); emit windowClosed(this, del); finishCompositing(); - workspace()->discardUsedWindowRules(this, true); // Remove ForceTemporarily rules + RuleBook::self()->discardUsed(this, true); // Remove ForceTemporarily rules StackingUpdatesBlocker blocker(workspace()); if (moveResizeMode) leaveMoveResize(); diff --git a/manage.cpp b/manage.cpp index 36d3578d03..93eaa592cf 100644 --- a/manage.cpp +++ b/manage.cpp @@ -612,7 +612,7 @@ bool Client::manage(Window w, bool isMapped) client_rules.discardTemporary(); applyWindowRules(); // Just in case - workspace()->discardUsedWindowRules(this, false); // Remove ApplyNow rules + RuleBook::self()->discardUsed(this, false); // Remove ApplyNow rules updateWindowRules(Rules::All); // Was blocked while !isManaged() updateCompositeBlocking(true); diff --git a/rules.cpp b/rules.cpp index acb927a964..df5f50908e 100644 --- a/rules.cpp +++ b/rules.cpp @@ -22,6 +22,7 @@ along with this program. If not, see . #include #include +#include #include #include #include @@ -736,7 +737,7 @@ void WindowRules::update(Client* c, int selection) if ((*it)->update(c, selection)) // no short-circuiting here updated = true; if (updated) - Workspace::self()->rulesUpdated(); + RuleBook::self()->requestDiskStorage(); } #define CHECK_RULE( rule, type ) \ @@ -840,7 +841,7 @@ CHECK_FORCE_RULE(DisableGlobalShortcuts, bool) void Client::setupWindowRules(bool ignore_temporary) { - client_rules = workspace()->findWindowRules(this, ignore_temporary); + client_rules = RuleBook::self()->find(this, ignore_temporary); // check only after getting the rules, because there may be a rule forcing window type } @@ -901,7 +902,7 @@ void Client::updateWindowRules(Rules::Types selection) { if (!isManaged()) // not fully setup yet return; - if (workspace()->rulesUpdatesDisabled()) + if (RuleBook::self()->areUpdatesDisabled()) return; client_rules.update(this, selection); } @@ -913,12 +914,37 @@ void Client::finishWindowRules() } // Workspace +KWIN_SINGLETON_FACTORY(RuleBook) -WindowRules Workspace::findWindowRules(const Client* c, bool ignore_temporary) +RuleBook::RuleBook(QObject *parent) + : QObject(parent) + , m_updateTimer(new QTimer(this)) + , m_updatesDisabled(false) + , m_temporaryRulesMessages(new KXMessages("_KDE_NET_WM_TEMPORARY_RULES", NULL)) +{ + connect(m_temporaryRulesMessages.data(), SIGNAL(gotMessage(QString)), SLOT(temporaryRulesMessage(QString))); + connect(m_updateTimer, SIGNAL(timeout()), SLOT(save())); + m_updateTimer->setInterval(1000); + m_updateTimer->setSingleShot(true); +} + +RuleBook::~RuleBook() +{ + save(); + deleteAll(); +} + +void RuleBook::deleteAll() +{ + qDeleteAll(m_rules); + m_rules.clear(); +} + +WindowRules RuleBook::find(const Client* c, bool ignore_temporary) { QVector< Rules* > ret; - for (QList< Rules* >::Iterator it = rules.begin(); - it != rules.end(); + for (QList< Rules* >::Iterator it = m_rules.begin(); + it != m_rules.end(); ) { if (ignore_temporary && (*it)->isTemporary()) { ++it; @@ -928,7 +954,7 @@ WindowRules Workspace::findWindowRules(const Client* c, bool ignore_temporary) Rules* rule = *it; kDebug(1212) << "Rule found:" << rule << ":" << c; if (rule->isTemporary()) - it = rules.erase(it); + it = m_rules.erase(it); else ++it; ret.append(rule); @@ -939,9 +965,9 @@ WindowRules Workspace::findWindowRules(const Client* c, bool ignore_temporary) return WindowRules(ret); } -void Workspace::editWindowRules(Client* c, bool whole_app) +void RuleBook::edit(Client* c, bool whole_app) { - writeWindowRules(); + save(); QStringList args; args << "--wid" << QString::number(c->window()); if (whole_app) @@ -949,12 +975,9 @@ void Workspace::editWindowRules(Client* c, bool whole_app) KToolInvocation::kdeinitExec("kwin_rules_dialog", args); } -void Workspace::loadWindowRules() +void RuleBook::load() { - while (!rules.isEmpty()) { - delete rules.front(); - rules.pop_front(); - } + deleteAll(); KConfig cfg(QLatin1String(KWIN_NAME) + "rulesrc", KConfig::NoGlobals); int count = cfg.group("General").readEntry("count", 0); for (int i = 1; @@ -962,23 +985,23 @@ void Workspace::loadWindowRules() ++i) { KConfigGroup cg(&cfg, QString::number(i)); Rules* rule = new Rules(cg); - rules.append(rule); + m_rules.append(rule); } } -void Workspace::writeWindowRules() +void RuleBook::save() { - rulesUpdatedTimer.stop(); + m_updateTimer->stop(); KConfig cfg(QLatin1String(KWIN_NAME) + "rulesrc", KConfig::NoGlobals); QStringList groups = cfg.groupList(); for (QStringList::ConstIterator it = groups.constBegin(); it != groups.constEnd(); ++it) cfg.deleteGroup(*it); - cfg.group("General").writeEntry("count", rules.count()); + cfg.group("General").writeEntry("count", m_rules.count()); int i = 1; - for (QList< Rules* >::ConstIterator it = rules.constBegin(); - it != rules.constEnd(); + for (QList< Rules* >::ConstIterator it = m_rules.constBegin(); + it != m_rules.constEnd(); ++it) { if ((*it)->isTemporary()) continue; @@ -988,29 +1011,31 @@ void Workspace::writeWindowRules() } } -void Workspace::gotTemporaryRulesMessage(const QString& message) +void RuleBook::temporaryRulesMessage(const QString& message) { bool was_temporary = false; - for (QList< Rules* >::ConstIterator it = rules.constBegin(); - it != rules.constEnd(); + for (QList< Rules* >::ConstIterator it = m_rules.constBegin(); + it != m_rules.constEnd(); ++it) if ((*it)->isTemporary()) was_temporary = true; Rules* rule = new Rules(message, true); - rules.prepend(rule); // highest priority first + m_rules.prepend(rule); // highest priority first if (!was_temporary) QTimer::singleShot(60000, this, SLOT(cleanupTemporaryRules())); } -void Workspace::cleanupTemporaryRules() +void RuleBook::cleanupTemporaryRules() { bool has_temporary = false; - for (QList< Rules* >::Iterator it = rules.begin(); - it != rules.end(); + for (QList< Rules* >::Iterator it = m_rules.begin(); + it != m_rules.end(); ) { - if ((*it)->discardTemporary(false)) - it = rules.erase(it); - else { + if ((*it)->discardTemporary(false)) { + Rules *rules = (*it); + it = m_rules.erase(it); + delete rules; + } else { if ((*it)->isTemporary()) has_temporary = true; ++it; @@ -1020,11 +1045,11 @@ void Workspace::cleanupTemporaryRules() QTimer::singleShot(60000, this, SLOT(cleanupTemporaryRules())); } -void Workspace::discardUsedWindowRules(Client* c, bool withdrawn) +void RuleBook::discardUsed(Client* c, bool withdrawn) { bool updated = false; - for (QList< Rules* >::Iterator it = rules.begin(); - it != rules.end(); + for (QList< Rules* >::Iterator it = m_rules.begin(); + it != m_rules.end(); ) { if (c->rules()->contains(*it)) { updated = true; @@ -1032,7 +1057,7 @@ void Workspace::discardUsedWindowRules(Client* c, bool withdrawn) if ((*it)->isEmpty()) { c->removeRule(*it); Rules* r = *it; - it = rules.erase(it); + it = m_rules.erase(it); delete r; continue; } @@ -1040,20 +1065,19 @@ void Workspace::discardUsedWindowRules(Client* c, bool withdrawn) ++it; } if (updated) - rulesUpdated(); + requestDiskStorage(); } -void Workspace::rulesUpdated() +void RuleBook::requestDiskStorage() { - rulesUpdatedTimer.setSingleShot(true); - rulesUpdatedTimer.start(1000); + m_updateTimer->start(); } -void Workspace::disableRulesUpdates(bool disable) +void RuleBook::setUpdatesDisabled(bool disable) { - rules_updates_disabled = disable; + m_updatesDisabled = disable; if (!disable) { - foreach (Client * c, clients) + foreach (Client * c, Workspace::self()->clientList()) c->updateWindowRules(Rules::All); } } diff --git a/rules.h b/rules.h index a4893b5fc0..2a635535af 100644 --- a/rules.h +++ b/rules.h @@ -33,6 +33,7 @@ along with this program. If not, see . #include "utils.h" class KConfig; +class KXMessages; namespace KWin { @@ -91,6 +92,7 @@ private: MaximizeMode checkMaximizeHoriz(MaximizeMode mode, bool init) const; QVector< Rules* > rules; }; + #endif class Rules @@ -277,6 +279,39 @@ private: }; #ifndef KCMRULES +class RuleBook : public QObject +{ + Q_OBJECT +public: + virtual ~RuleBook(); + WindowRules find(const Client*, bool); + void discardUsed(Client* c, bool withdraw); + void setUpdatesDisabled(bool disable); + bool areUpdatesDisabled() const; + void load(); + void edit(Client* c, bool whole_app); + void requestDiskStorage(); +private Q_SLOTS: + void temporaryRulesMessage(const QString&); + void cleanupTemporaryRules(); + void save(); + +private: + void deleteAll(); + QTimer *m_updateTimer; + bool m_updatesDisabled; + QList m_rules; + QScopedPointer m_temporaryRulesMessages; + + KWIN_SINGLETON(RuleBook) +}; + +inline +bool RuleBook::areUpdatesDisabled() const +{ + return m_updatesDisabled; +} + inline bool Rules::checkSetRule(SetRule rule, bool init) { diff --git a/sm.cpp b/sm.cpp index 1d6b89aaf6..1e90eb63cf 100644 --- a/sm.cpp +++ b/sm.cpp @@ -369,7 +369,7 @@ static void save_yourself(SmcConn conn_P, SmPointer ptr, int, Bool shutdown, int if (conn_P != session->connection()) return; if (shutdown) - Workspace::self()->disableRulesUpdates(true); + RuleBook::self()->setUpdatesDisabled(true); SmcSaveYourselfDone(conn_P, True); } @@ -395,7 +395,7 @@ static void shutdown_cancelled(SmcConn conn_P, SmPointer ptr) SessionSaveDoneHelper* session = reinterpret_cast< SessionSaveDoneHelper* >(ptr); if (conn_P != session->connection()) return; - Workspace::self()->disableRulesUpdates(false); // re-enable + RuleBook::self()->setUpdatesDisabled(false); // re-enable // no need to differentiate between successful finish and cancel session->saveDone(); } diff --git a/useractions.cpp b/useractions.cpp index 20d6ad828c..753b8c16cb 100755 --- a/useractions.cpp +++ b/useractions.cpp @@ -1111,10 +1111,10 @@ void Workspace::performWindowOperation(Client* c, Options::WindowOperation op) c->performMouseCommand(Options::MouseShade, cursorPos()); break; case Options::WindowRulesOp: - editWindowRules(c, false); + RuleBook::self()->edit(c, false); break; case Options::ApplicationRulesOp: - editWindowRules(c, true); + RuleBook::self()->edit(c, true); break; case Options::SetupWindowShortcutOp: setupWindowShortcut(c); diff --git a/workspace.cpp b/workspace.cpp index 5aee3f8e7f..42dd9c185e 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -86,8 +86,6 @@ Workspace::Workspace(bool restore) // Unsorted , active_popup(NULL) , active_popup_client(NULL) - , temporaryRulesMessages("_KDE_NET_WM_TEMPORARY_RULES", NULL) - , rules_updates_disabled(false) , active_client(0) , last_active_client(0) , most_recently_raised(0) @@ -148,9 +146,6 @@ Workspace::Workspace(bool restore) default_colormap = DefaultColormap(display(), screen_number); installed_colormap = default_colormap; - connect(&temporaryRulesMessages, SIGNAL(gotMessage(QString)), - this, SLOT(gotTemporaryRulesMessage(QString))); - connect(&rulesUpdatedTimer, SIGNAL(timeout()), this, SLOT(writeWindowRules())); updateXTime(); // Needed for proper initialization of user_time in Client ctor delayFocusTimer = 0; @@ -158,7 +153,7 @@ Workspace::Workspace(bool restore) if (restore) loadSessionInfo(); - loadWindowRules(); + RuleBook::create(this)->load(); // Call this before XSelectInput() on the root window startup = new KStartupInfo( @@ -505,7 +500,7 @@ Workspace::~Workspace() (*it)->release(true); XDeleteProperty(display(), rootWindow(), atoms->kwin_running); - writeWindowRules(); + delete RuleBook::self(); KGlobal::config()->sync(); delete rootInfo; @@ -513,10 +508,6 @@ Workspace::~Workspace() delete startup; delete Placement::self(); delete client_keys_dialog; - while (!rules.isEmpty()) { - delete rules.front(); - rules.pop_front(); - } foreach (SessionInfo * s, session) delete s; XDestroyWindow(display(), null_focus_window); @@ -907,13 +898,13 @@ void Workspace::slotReconfigure() c->triggerDecorationRepaint(); } - loadWindowRules(); + RuleBook::self()->load(); for (ClientList::Iterator it = clients.begin(); it != clients.end(); ++it) { (*it)->setupWindowRules(true); (*it)->applyWindowRules(); - discardUsedWindowRules(*it, false); + RuleBook::self()->discardUsed(*it, false); } if (borderlessMaximizedWindows != options->borderlessMaximizedWindows() && diff --git a/workspace.h b/workspace.h index 3ea9c2e27a..da968c8549 100644 --- a/workspace.h +++ b/workspace.h @@ -29,7 +29,6 @@ along with this program. If not, see . #include "utils.h" // KDE #include -#include // Qt #include #include @@ -52,10 +51,8 @@ namespace KWin class Client; class KillWindow; class RootInfo; -class Rules; class ShortcutDialog; class UserActionsMenu; -class WindowRules; class Compositor; class Workspace : public QObject, public KDecorationDefines @@ -246,11 +243,6 @@ public: void loadSubSessionInfo(const QString &name); SessionInfo* takeSessionInfo(Client*); - WindowRules findWindowRules(const Client*, bool); - void rulesUpdated(); - void discardUsedWindowRules(Client* c, bool withdraw); - void disableRulesUpdates(bool disable); - bool rulesUpdatesDisabled() const; // D-Bus interface bool waitForCompositingSetup(); @@ -397,9 +389,6 @@ private slots: void desktopResized(); void slotUpdateToolWindows(); void delayFocus(); - void gotTemporaryRulesMessage(const QString&); - void cleanupTemporaryRules(); - void writeWindowRules(); void slotBlockShortcuts(int data); void slotReloadConfig(); void updateCurrentActivity(const QString &new_activity); @@ -481,14 +470,7 @@ private: void loadSessionInfo(); void addSessionInfo(KConfigGroup &cg); - void loadWindowRules(); - void editWindowRules(Client* c, bool whole_app); - QList session; - QList rules; - KXMessages temporaryRulesMessages; - QTimer rulesUpdatedTimer; - bool rules_updates_disabled; static const char* windowTypeToTxt(NET::WindowType type); static NET::WindowType txtToWindowType(const char* txt); static bool sessionInfoWindowTypeMatch(Client* c, SessionInfo* info); @@ -712,11 +694,6 @@ inline bool Workspace::globalShortcutsDisabled() const return global_shortcuts_disabled || global_shortcuts_disabled_for_client; } -inline bool Workspace::rulesUpdatesDisabled() const -{ - return rules_updates_disabled; -} - inline void Workspace::forceRestacking() { force_restacking = true;