From 0d60a7049d9138450eddb536e2e29a92dbcff641 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C4=8Cuki=C4=87?= Date: Thu, 17 May 2012 16:32:06 +0200 Subject: [PATCH] Adds activity window rules to KWin - adds the kcm rule option to set the activity - one or all option like for virtual desktops - makes the windows obey the rule - makes the rule enforced even when the user tries to change the window's activity via the alt+f3 menu REVIEW:104972 --- client.cpp | 28 +- kcmkwin/kwinrules/CMakeLists.txt | 5 +- kcmkwin/kwinrules/ruleswidget.cpp | 33 ++ kcmkwin/kwinrules/ruleswidget.h | 3 + kcmkwin/kwinrules/ruleswidgetbase.ui | 749 ++++++++++++++------------- manage.cpp | 6 + rules.cpp | 14 + rules.h | 7 +- 8 files changed, 481 insertions(+), 364 deletions(-) diff --git a/client.cpp b/client.cpp index 89b5bf8001..820a232b8b 100644 --- a/client.cpp +++ b/client.cpp @@ -1628,18 +1628,26 @@ void Client::setOnActivity(const QString &activity, bool enable) */ void Client::setOnActivities(QStringList newActivitiesList) { + QString joinedActivitiesList = newActivitiesList.join(","); + joinedActivitiesList = rules()->checkActivity(joinedActivitiesList, false); + newActivitiesList = joinedActivitiesList.split(','); + QStringList allActivities = workspace()->activityList(); if (newActivitiesList.size() == allActivities.size() || newActivitiesList.isEmpty()) { setOnAllActivities(true); - return; - } + activityList.clear(); + XChangeProperty(display(), window(), atoms->activities, XA_STRING, 8, + PropModeReplace, (const unsigned char *)"ALL", 3); - QByteArray joined = newActivitiesList.join(",").toAscii(); - char *data = joined.data(); - activityList = newActivitiesList; - XChangeProperty(display(), window(), atoms->activities, XA_STRING, 8, + } else { + QByteArray joined = joinedActivitiesList.toAscii(); + char *data = joined.data(); + activityList = newActivitiesList; + XChangeProperty(display(), window(), atoms->activities, XA_STRING, 8, PropModeReplace, (unsigned char *)data, joined.size()); + } + updateActivities(false); } @@ -1656,7 +1664,7 @@ void Client::updateActivities(bool includeTransients) workspace()->updateOnAllActivitiesOfTransients(this); workspace()->updateFocusChains(this, Workspace::FocusChainMakeFirst); updateVisibility(); - // TODO: add activity rule + updateWindowRules(Rules::Activity); // Update states of all other windows in this group if (tabGroup()) @@ -1714,10 +1722,8 @@ void Client::setOnAllActivities(bool on) if (on == isOnAllActivities()) return; if (on) { - activityList.clear(); - XChangeProperty(display(), window(), atoms->activities, XA_STRING, 8, - PropModeReplace, (const unsigned char *)"ALL", 3); - updateActivities(true); + setOnActivities(QStringList()); + } else { setOnActivity(Workspace::self()->currentActivity(), true); workspace()->updateOnAllActivitiesOfTransients(this); diff --git a/kcmkwin/kwinrules/CMakeLists.txt b/kcmkwin/kwinrules/CMakeLists.txt index 4e257b2f89..56dbf4b068 100644 --- a/kcmkwin/kwinrules/CMakeLists.txt +++ b/kcmkwin/kwinrules/CMakeLists.txt @@ -9,10 +9,9 @@ kde4_add_ui_files(kwinrules_SRCS ruleslist.ui detectwidget.ui editshortcut.ui ru set(kwin_rules_dialog_KDEINIT_SRCS main.cpp ${kwinrules_SRCS}) - kde4_add_kdeinit_executable( kwin_rules_dialog ${kwin_rules_dialog_KDEINIT_SRCS}) -target_link_libraries(kdeinit_kwin_rules_dialog ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} ${X11_LIBRARIES}) +target_link_libraries(kdeinit_kwin_rules_dialog ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} ${X11_LIBRARIES} ${KACTIVITIES_LIBRARY}) install(TARGETS kdeinit_kwin_rules_dialog ${INSTALL_TARGETS_DEFAULT_ARGS} ) install(TARGETS kwin_rules_dialog DESTINATION ${LIBEXEC_INSTALL_DIR} ) @@ -24,7 +23,7 @@ set(kcm_kwinrules_PART_SRCS kcm.cpp ${kwinrules_SRCS}) kde4_add_plugin(kcm_kwinrules ${kcm_kwinrules_PART_SRCS}) -target_link_libraries(kcm_kwinrules ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} ${X11_LIBRARIES}) +target_link_libraries(kcm_kwinrules ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} ${X11_LIBRARIES} ${KACTIVITIES_LIBRARY}) install(TARGETS kcm_kwinrules DESTINATION ${PLUGIN_INSTALL_DIR} ) diff --git a/kcmkwin/kwinrules/ruleswidget.cpp b/kcmkwin/kwinrules/ruleswidget.cpp index aadf34309c..b37c2939e2 100644 --- a/kcmkwin/kwinrules/ruleswidget.cpp +++ b/kcmkwin/kwinrules/ruleswidget.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -84,6 +85,7 @@ RulesWidget::RulesWidget(QWidget* parent) SETUP(position, set); SETUP(size, set); SETUP(desktop, set); + SETUP(activity, set); SETUP(maximizehoriz, set); SETUP(maximizevert, set); SETUP(minimize, set); @@ -131,6 +133,12 @@ RulesWidget::RulesWidget(QWidget* parent) ++i) desktop->addItem(QString::number(i).rightJustified(2) + ':' + KWindowSystem::desktopName(i)); desktop->addItem(i18n("All Desktops")); + + static KActivities::Consumer activities; + foreach (const QString & activityId, activities.listActivities()) { + activity->addItem(KActivities::Info::name(activityId), activityId); + } + activity->addItem(i18n("All Activities"), QString::fromLatin1("ALL")); } #undef SETUP @@ -146,6 +154,7 @@ RulesWidget::RulesWidget(QWidget* parent) UPDATE_ENABLE_SLOT(position) UPDATE_ENABLE_SLOT(size) UPDATE_ENABLE_SLOT(desktop) +UPDATE_ENABLE_SLOT(activity) UPDATE_ENABLE_SLOT(maximizehoriz) UPDATE_ENABLE_SLOT(maximizevert) UPDATE_ENABLE_SLOT(minimize) @@ -281,6 +290,27 @@ int RulesWidget::comboToDesktop(int val) const return val + 1; } +int RulesWidget::activityToCombo(QString d) const +{ + // TODO: ivan - do a multiselection list + for (int i = 0; i < activity->count(); i++) { + if (activity->itemData(i).toString() == d) { + return i; + } + } + + return activity->count() - 1; // on all activities +} + +QString RulesWidget::comboToActivity(int val) const +{ + // TODO: ivan - do a multiselection list + if (val < 0 || val >= activity->count()) + return QString(); + + return activity->itemData(val).toString(); +} + int RulesWidget::tilingToCombo(int t) const { return qBound(0, t, 1); @@ -423,6 +453,7 @@ void RulesWidget::setRules(Rules* rules) LINEEDIT_SET_RULE(position, positionToStr); LINEEDIT_SET_RULE(size, sizeToStr); COMBOBOX_SET_RULE(desktop, desktopToCombo); + COMBOBOX_SET_RULE(activity, activityToCombo); CHECKBOX_SET_RULE(maximizehoriz,); CHECKBOX_SET_RULE(maximizevert,); CHECKBOX_SET_RULE(minimize,); @@ -517,6 +548,7 @@ Rules* RulesWidget::rules() const LINEEDIT_SET_RULE(position, strToPosition); LINEEDIT_SET_RULE(size, strToSize); COMBOBOX_SET_RULE(desktop, comboToDesktop); + COMBOBOX_SET_RULE(activity, comboToActivity); CHECKBOX_SET_RULE(maximizehoriz,); CHECKBOX_SET_RULE(maximizevert,); CHECKBOX_SET_RULE(minimize,); @@ -635,6 +667,7 @@ void RulesWidget::prefillUnusedValues(const KWindowInfo& info) LINEEDIT_PREFILL(position, positionToStr, info.frameGeometry().topLeft()); LINEEDIT_PREFILL(size, sizeToStr, info.frameGeometry().size()); COMBOBOX_PREFILL(desktop, desktopToCombo, info.desktop()); + // COMBOBOX_PREFILL(activity, activityToCombo, info.activity()); // TODO: ivan CHECKBOX_PREFILL(maximizehoriz, , info.state() & NET::MaxHoriz); CHECKBOX_PREFILL(maximizevert, , info.state() & NET::MaxVert); CHECKBOX_PREFILL(minimize, , info.isMinimized()); diff --git a/kcmkwin/kwinrules/ruleswidget.h b/kcmkwin/kwinrules/ruleswidget.h index 224a5744b2..50a5ea284e 100644 --- a/kcmkwin/kwinrules/ruleswidget.h +++ b/kcmkwin/kwinrules/ruleswidget.h @@ -57,6 +57,7 @@ private slots: void updateEnableposition(); void updateEnablesize(); void updateEnabledesktop(); + void updateEnableactivity(); void updateEnablemaximizehoriz(); void updateEnablemaximizevert(); void updateEnableminimize(); @@ -93,6 +94,8 @@ private slots: private: int desktopToCombo(int d) const; int comboToDesktop(int val) const; + int activityToCombo(QString d) const; + QString comboToActivity(int val) const; int tilingToCombo(int t) const; int comboToTiling(int val) const; void prefillUnusedValues(const KWindowInfo& info); diff --git a/kcmkwin/kwinrules/ruleswidgetbase.ui b/kcmkwin/kwinrules/ruleswidgetbase.ui index 974ae6d946..318f3c4fca 100644 --- a/kcmkwin/kwinrules/ruleswidgetbase.ui +++ b/kcmkwin/kwinrules/ruleswidgetbase.ui @@ -6,7 +6,7 @@ 0 0 - 547 + 569 517 @@ -14,7 +14,7 @@ - 0 + 1 @@ -489,13 +489,6 @@ &Size && Position - - - - &Position - - - @@ -533,104 +526,6 @@ - - - - false - - - x,y - - - 0123456789-+,xX: - - - - - - - &Size - - - - - - - false - - - - Do Not Affect - - - - - Apply Initially - - - - - Remember - - - - - Force - - - - - Apply Now - - - - - Force Temporarily - - - - - - - - false - - - width,height - - - 0123456789-+,xX: - - - - - - - Qt::Horizontal - - - - - - - Maximized &horizontally - - - - - - - false - - - - - - - Maximized &vertically - - - @@ -668,43 +563,41 @@ - - + + false - - - - - - Qt::Horizontal + + x,y + + + 0123456789-+,xX: - - + + - &Fullscreen + &Size - - + + false - - - - - - &Desktop + + width,height + + + 0123456789-+,xX: - - + + false @@ -713,26 +606,11 @@ Do Not Affect - - - Apply Initially - - - - - Remember - - Force - - - Apply Now - - Force Temporarily @@ -740,42 +618,21 @@ - - - - false - - - - - - - Qt::Horizontal - - - - - - - M&inimized - - - - - - - false - - - - + Sh&aded - + + + + M&inimized + + + + false @@ -812,32 +669,8 @@ - - - - false - - - - - - - Qt::Horizontal - - - - - - - - - - Initial p&lacement - - - - - + + false @@ -846,11 +679,26 @@ Do Not Affect + + + Apply Initially + + + + + Remember + + Force + + + Apply Now + + Force Temporarily @@ -858,7 +706,58 @@ - + + + + false + + + + Do Not Affect + + + + + Apply Initially + + + + + Remember + + + + + Force + + + + + Apply Now + + + + + Force Temporarily + + + + + + + + false + + + + + + + false + + + + false @@ -915,85 +814,7 @@ - - - - Windows can ask to appear in a certain position. -By default this overrides the placement strategy -what might be nasty if the client abuses the feature -to unconditionally popup in the middle of your screen. - - - Ignore requested &geometry - - - - - - - false - - - - Do Not Affect - - - - - Force - - - - - Force Temporarily - - - - - - - - false - - - - - - - Qt::Horizontal - - - - - - - M&aximum size - - - - - - - false - - - - Do Not Affect - - - - - Force - - - - - Force Temporarily - - - - - + false @@ -1006,29 +827,113 @@ to unconditionally popup in the middle of your screen. - + + + + M&aximum size + + + + + + + Qt::Horizontal + + + + + + + + + + Initial p&lacement + + + + + + + false + + + + false - - + + - Qt::Vertical + Qt::Horizontal - - QSizePolicy::Expanding + + + + + + Qt::Horizontal - 20 - 16 + 40 + 20 + + + + Eg. terminals or video players can ask to keep a certain aspect ratio +or only grow by values larger than one +(eg. by the dimensions of one character). +This may be pointless and the restriction prevents arbitrary dimensions +like your complete screen area. + + + Qt::LeftToRight + + + Obey geometry restrictions + + + + + + + + + + false + + + + Do Not Affect + + + + + Force + + + + + Force Temporarily + + + + + + + + Qt::Horizontal + + + @@ -1103,8 +1008,127 @@ to unconditionally popup in the middle of your screen. - - + + + + false + + + + Do Not Affect + + + + + Force + + + + + Force Temporarily + + + + + + + + false + + + + + + + Windows can ask to appear in a certain position. +By default this overrides the placement strategy +what might be nasty if the client abuses the feature +to unconditionally popup in the middle of your screen. + + + Ignore requested &geometry + + + + + + + Maximized &horizontally + + + + + + + &Fullscreen + + + + + + + false + + + + + + + false + + + + + + + false + + + width,height + + + 0123456789-+,xX: + + + + + + + false + + + + Do Not Affect + + + + + Force + + + + + Force Temporarily + + + + + + + + &Position + + + + + + + false + + + + + false @@ -1140,49 +1164,28 @@ to unconditionally popup in the middle of your screen. - - - - false - - - width,height - - - 0123456789-+,xX: + + + + Maximized &vertically - - - - false + + + + &Desktop - - - Do Not Affect - - - - - Force - - - - - Force Temporarily - - - + M&inimum size - + Qt::Horizontal @@ -1195,40 +1198,14 @@ to unconditionally popup in the middle of your screen. - - + + Qt::Horizontal - - - 40 - 20 - - - - - - - - Eg. terminals or video players can ask to keep a certain aspect ratio -or only grow by values larger than one -(eg. by the dimensions of one character). -This may be pointless and the restriction prevents arbitrary dimensions -like your complete screen area. - - - Qt::LeftToRight - - - Obey geometry restrictions - - - - - + false @@ -1250,6 +1227,80 @@ like your complete screen area. + + + + Qt::Horizontal + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 16 + + + + + + + + Activit&y + + + + + + + false + + + + Do Not Affect + + + + + Apply Initially + + + + + Remember + + + + + Force + + + + + Apply Now + + + + + Force Temporarily + + + + + + + + false + + + diff --git a/manage.cpp b/manage.cpp index 71c567e7fa..18713b6529 100644 --- a/manage.cpp +++ b/manage.cpp @@ -205,6 +205,7 @@ bool Client::manage(Window w, bool isMapped) setOnActivity(Workspace::self()->currentActivity(), true); } } + if (desk == 0) // Assume window wants to be visible on the current desktop desk = isDesktop() ? NET::OnAllDesktops : workspace()->currentDesktop(); desk = rules()->checkDesktop(desk, !isMapped); @@ -214,6 +215,11 @@ bool Client::manage(Window w, bool isMapped) workspace()->updateOnAllDesktopsOfTransients(this); // SELI TODO //onAllDesktopsChange(); // Decoration doesn't exist here yet + QString activitiesList; + activitiesList = rules()->checkActivity(activitiesList, !isMapped); + if (!activitiesList.isEmpty()) + setOnActivities(activitiesList.split(",")); + QRect geom(attr.x, attr.y, attr.width, attr.height); bool placementDone = false; diff --git a/rules.cpp b/rules.cpp index 95c2d0b415..08111da98b 100644 --- a/rules.cpp +++ b/rules.cpp @@ -53,6 +53,7 @@ Rules::Rules() , tilingoptionrule(UnusedForceRule) , ignorepositionrule(UnusedForceRule) , desktoprule(UnusedSetRule) + , activityrule(UnusedSetRule) , typerule(UnusedForceRule) , maximizevertrule(UnusedSetRule) , maximizehorizrule(UnusedSetRule) @@ -158,6 +159,7 @@ void Rules::readFromCfg(const KConfigGroup& cfg) READ_FORCE_RULE(tilingoption, , 0); READ_FORCE_RULE(ignoreposition, , false); READ_SET_RULE(desktop, , 0); + READ_SET_RULE(activity, , QString()); type = readType(cfg, "type"); typerule = type != NET::Unknown ? readForceRule(cfg, "typerule") : UnusedForceRule; READ_SET_RULE(maximizevert, , false); @@ -247,6 +249,7 @@ void Rules::write(KConfigGroup& cfg) const WRITE_FORCE_RULE(tilingoption,); WRITE_FORCE_RULE(ignoreposition,); WRITE_SET_RULE(desktop,); + WRITE_SET_RULE(activity,); WRITE_FORCE_RULE(type, int); WRITE_SET_RULE(maximizevert,); WRITE_SET_RULE(maximizehoriz,); @@ -288,6 +291,7 @@ bool Rules::isEmpty() const && tilingoptionrule == UnusedForceRule && ignorepositionrule == UnusedForceRule && desktoprule == UnusedSetRule + && activityrule == UnusedSetRule && typerule == UnusedForceRule && maximizevertrule == UnusedSetRule && maximizehorizrule == UnusedSetRule @@ -459,6 +463,12 @@ bool Rules::update(Client* c, int selection) updated = updated || desktop != c->desktop(); desktop = c->desktop(); } + if NOW_REMEMBER(Activity, activity) { + // TODO: ivan - multiple activities support + const QString & joinedActivities = c->activities().join(","); + updated = updated || activity != joinedActivities; + activity = joinedActivities; + } if NOW_REMEMBER(MaximizeVert, maximizevert) { updated = updated || maximizevert != bool(c->maximizeMode() & MaximizeVertical); maximizevert = c->maximizeMode() & MaximizeVertical; @@ -576,6 +586,7 @@ bool Rules::applyIgnoreGeometry(bool& ignore) const } APPLY_RULE(desktop, Desktop, int) +APPLY_RULE(activity, Activity, QString) APPLY_FORCE_RULE(type, Type, NET::WindowType) bool Rules::applyMaximizeHoriz(MaximizeMode& mode, bool init) const @@ -666,6 +677,7 @@ void Rules::discardUsed(bool withdrawn) DISCARD_USED_FORCE_RULE(tilingoption); DISCARD_USED_FORCE_RULE(ignoreposition); DISCARD_USED_SET_RULE(desktop); + DISCARD_USED_SET_RULE(activity); DISCARD_USED_FORCE_RULE(type); DISCARD_USED_SET_RULE(maximizevert); DISCARD_USED_SET_RULE(maximizehoriz); @@ -781,6 +793,7 @@ bool WindowRules::checkIgnoreGeometry(bool ignore) const } CHECK_RULE(Desktop, int) +CHECK_RULE(Activity, QString) CHECK_FORCE_RULE(Type, NET::WindowType) CHECK_RULE(MaximizeVert, KDecorationDefines::MaximizeMode) CHECK_RULE(MaximizeHoriz, KDecorationDefines::MaximizeMode) @@ -837,6 +850,7 @@ void Client::applyWindowRules() // MinSize, MaxSize handled by Geometry // IgnorePosition setDesktop(desktop()); + setOnActivities(activities()); // Type maximize(maximizeMode()); // Minimize : functions don't check, and there are two functions diff --git a/rules.h b/rules.h index b66501c2c1..3b322fce77 100644 --- a/rules.h +++ b/rules.h @@ -64,6 +64,7 @@ public: int checkTilingOption(int s) const; bool checkIgnoreGeometry(bool ignore) const; int checkDesktop(int desktop, bool init = false) const; + QString checkActivity(QString activity, bool init = false) const; NET::WindowType checkType(NET::WindowType type) const; MaximizeMode checkMaximize(MaximizeMode mode, bool init = false) const; bool checkMinimize(bool minimized, bool init = false) const; @@ -105,7 +106,8 @@ public: MaximizeVert = 1<<3, MaximizeHoriz = 1<<4, Minimize = 1<<5, Shade = 1<<6, SkipTaskbar = 1<<7, SkipPager = 1<<8, SkipSwitcher = 1<<9, Above = 1<<10, Below = 1<<11, Fullscreen = 1<<12, - NoBorder = 1<<13, OpacityActive = 1<<14, OpacityInactive = 1<<15, All = 0xffffffff + NoBorder = 1<<13, OpacityActive = 1<<14, OpacityInactive = 1<<15, + Activity = 1<<16, All = 0xffffffff }; Q_DECLARE_FLAGS(Types, Type) void write(KConfigGroup&) const; @@ -128,6 +130,7 @@ public: bool applyTilingOption(int& s) const; bool applyIgnoreGeometry(bool& ignore) const; bool applyDesktop(int& desktop, bool init) const; + bool applyActivity(QString& activity, bool init) const; bool applyType(NET::WindowType& type) const; bool applyMaximizeVert(MaximizeMode& mode, bool init) const; bool applyMaximizeHoriz(MaximizeMode& mode, bool init) const; @@ -226,6 +229,8 @@ private: ForceRule ignorepositionrule; int desktop; SetRule desktoprule; + QString activity; + SetRule activityrule; NET::WindowType type; // type for setting ForceRule typerule; bool maximizevert;