Changeset View
Changeset View
Standalone View
Standalone View
imports/activitymanager/switcherbackend.cpp
Show All 33 Lines | |||||
34 | #include <QQmlEngine> | 34 | #include <QQmlEngine> | ||
35 | 35 | | |||
36 | // KDE | 36 | // KDE | ||
37 | #include <kglobalaccel.h> | 37 | #include <kglobalaccel.h> | ||
38 | #include <klocalizedstring.h> | 38 | #include <klocalizedstring.h> | ||
39 | #include <KIO/PreviewJob> | 39 | #include <KIO/PreviewJob> | ||
40 | #include <KConfig> | 40 | #include <KConfig> | ||
41 | #include <KConfigGroup> | 41 | #include <KConfigGroup> | ||
42 | #include <KWindowSystem> | ||||
43 | #include <windowtasksmodel.h> | ||||
44 | #include <xwindowtasksmodel.h> | ||||
42 | 45 | | |||
43 | // X11 | 46 | // X11 | ||
44 | #include <X11/keysym.h> | 47 | #include <X11/keysym.h> | ||
45 | #include <X11/keysymdef.h> | 48 | #include <X11/keysymdef.h> | ||
46 | #include <X11/Xlib.h> | 49 | #include <X11/Xlib.h> | ||
47 | 50 | | |||
48 | #define ACTION_NAME_NEXT_ACTIVITY "next activity" | 51 | #define ACTION_NAME_NEXT_ACTIVITY "next activity" | ||
49 | #define ACTION_NAME_PREVIOUS_ACTIVITY "previous activity" | 52 | #define ACTION_NAME_PREVIOUS_ACTIVITY "previous activity" | ||
▲ Show 20 Lines • Show All 190 Lines • ▼ Show 20 Line(s) | 233 | { | |||
240 | using KActivities::Controller; | 243 | using KActivities::Controller; | ||
241 | 244 | | |||
242 | connect(action, &QAction::triggered, this, std::forward<Handler>(handler)); | 245 | connect(action, &QAction::triggered, this, std::forward<Handler>(handler)); | ||
243 | } | 246 | } | ||
244 | 247 | | |||
245 | SwitcherBackend::SwitcherBackend(QObject *parent) | 248 | SwitcherBackend::SwitcherBackend(QObject *parent) | ||
246 | : QObject(parent) | 249 | : QObject(parent) | ||
247 | , m_shouldShowSwitcher(false) | 250 | , m_shouldShowSwitcher(false) | ||
251 | , m_dropModeActive(false) | ||||
248 | , m_runningActivitiesModel(new SortedActivitiesModel({KActivities::Info::Running, KActivities::Info::Stopping}, this)) | 252 | , m_runningActivitiesModel(new SortedActivitiesModel({KActivities::Info::Running, KActivities::Info::Stopping}, this)) | ||
249 | , m_stoppedActivitiesModel(new SortedActivitiesModel({KActivities::Info::Stopped, KActivities::Info::Starting}, this)) | 253 | , m_stoppedActivitiesModel(new SortedActivitiesModel({KActivities::Info::Stopped, KActivities::Info::Starting}, this)) | ||
250 | { | 254 | { | ||
251 | registerShortcut(ACTION_NAME_NEXT_ACTIVITY, | 255 | registerShortcut(ACTION_NAME_NEXT_ACTIVITY, | ||
252 | i18n("Walk through activities"), | 256 | i18n("Walk through activities"), | ||
253 | Qt::META + Qt::Key_Tab, | 257 | Qt::META + Qt::Key_Tab, | ||
254 | &SwitcherBackend::keybdSwitchToNextActivity); | 258 | &SwitcherBackend::keybdSwitchToNextActivity); | ||
255 | 259 | | |||
256 | registerShortcut(ACTION_NAME_PREVIOUS_ACTIVITY, | 260 | registerShortcut(ACTION_NAME_PREVIOUS_ACTIVITY, | ||
257 | i18n("Walk through activities (Reverse)"), | 261 | i18n("Walk through activities (Reverse)"), | ||
258 | Qt::META + Qt::SHIFT + Qt::Key_Tab, | 262 | Qt::META + Qt::SHIFT + Qt::Key_Tab, | ||
259 | &SwitcherBackend::keybdSwitchToPreviousActivity); | 263 | &SwitcherBackend::keybdSwitchToPreviousActivity); | ||
260 | 264 | | |||
261 | connect(this, &SwitcherBackend::shouldShowSwitcherChanged, | 265 | connect(this, &SwitcherBackend::shouldShowSwitcherChanged, | ||
262 | m_runningActivitiesModel, &SortedActivitiesModel::setInhibitUpdates); | 266 | m_runningActivitiesModel, &SortedActivitiesModel::setInhibitUpdates); | ||
263 | 267 | | |||
268 | m_modKeyPollingTimer.setInterval(100); | ||||
269 | m_modKeyPollingTimer.setSingleShot(true); | ||||
264 | connect(&m_modKeyPollingTimer, &QTimer::timeout, | 270 | connect(&m_modKeyPollingTimer, &QTimer::timeout, | ||
265 | this, &SwitcherBackend::showActivitySwitcherIfNeeded); | 271 | this, &SwitcherBackend::showActivitySwitcherIfNeeded); | ||
272 | | ||||
273 | m_dropModeHider.setInterval(500); | ||||
274 | connect(&m_dropModeHider, &QTimer::timeout, | ||||
275 | this, [this] { setShouldShowSwitcher(false); }); | ||||
276 | | ||||
266 | connect(&m_activities, &KActivities::Controller::currentActivityChanged, | 277 | connect(&m_activities, &KActivities::Controller::currentActivityChanged, | ||
267 | this, &SwitcherBackend::onCurrentActivityChanged); | 278 | this, &SwitcherBackend::onCurrentActivityChanged); | ||
268 | m_previousActivity = m_activities.currentActivity(); | 279 | m_previousActivity = m_activities.currentActivity(); | ||
269 | } | 280 | } | ||
270 | 281 | | |||
271 | SwitcherBackend::~SwitcherBackend() | 282 | SwitcherBackend::~SwitcherBackend() | ||
272 | { | 283 | { | ||
273 | } | 284 | } | ||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Line(s) | |||||
319 | { | 330 | { | ||
320 | m_lastInvokedAction = dynamic_cast<QAction*>(sender()); | 331 | m_lastInvokedAction = dynamic_cast<QAction*>(sender()); | ||
321 | 332 | | |||
322 | QTimer::singleShot(90, this, &SwitcherBackend::showActivitySwitcherIfNeeded); | 333 | QTimer::singleShot(90, this, &SwitcherBackend::showActivitySwitcherIfNeeded); | ||
323 | } | 334 | } | ||
324 | 335 | | |||
325 | void SwitcherBackend::showActivitySwitcherIfNeeded() | 336 | void SwitcherBackend::showActivitySwitcherIfNeeded() | ||
326 | { | 337 | { | ||
327 | if (!m_lastInvokedAction) { | 338 | if (!m_lastInvokedAction || m_dropModeActive) { | ||
328 | return; | 339 | return; | ||
329 | } | 340 | } | ||
330 | 341 | | |||
331 | auto actionName = m_lastInvokedAction->objectName(); | 342 | auto actionName = m_lastInvokedAction->objectName(); | ||
332 | 343 | | |||
333 | if (!m_actionShortcut.contains(actionName)) { | 344 | if (!m_actionShortcut.contains(actionName)) { | ||
334 | return; | 345 | return; | ||
335 | } | 346 | } | ||
▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Line(s) | |||||
400 | void SwitcherBackend::setShouldShowSwitcher(bool shouldShowSwitcher) | 411 | void SwitcherBackend::setShouldShowSwitcher(bool shouldShowSwitcher) | ||
401 | { | 412 | { | ||
402 | if (m_shouldShowSwitcher == shouldShowSwitcher) return; | 413 | if (m_shouldShowSwitcher == shouldShowSwitcher) return; | ||
403 | 414 | | |||
404 | m_shouldShowSwitcher = shouldShowSwitcher; | 415 | m_shouldShowSwitcher = shouldShowSwitcher; | ||
405 | 416 | | |||
406 | if (m_shouldShowSwitcher) { | 417 | if (m_shouldShowSwitcher) { | ||
407 | // TODO: We really should NOT do this by polling | 418 | // TODO: We really should NOT do this by polling | ||
408 | m_modKeyPollingTimer.start(100); | 419 | m_modKeyPollingTimer.start(); | ||
409 | } else { | 420 | } else { | ||
410 | m_modKeyPollingTimer.stop(); | 421 | m_modKeyPollingTimer.stop(); | ||
411 | 422 | | |||
412 | // We might have an unprocessed onCurrentActivityChanged | 423 | // We might have an unprocessed onCurrentActivityChanged | ||
413 | onCurrentActivityChanged(m_activities.currentActivity()); | 424 | onCurrentActivityChanged(m_activities.currentActivity()); | ||
414 | } | 425 | } | ||
415 | 426 | | |||
416 | emit shouldShowSwitcherChanged(m_shouldShowSwitcher); | 427 | emit shouldShowSwitcherChanged(m_shouldShowSwitcher); | ||
Show All 13 Lines | |||||
430 | { | 441 | { | ||
431 | m_activities.setCurrentActivity(activity); | 442 | m_activities.setCurrentActivity(activity); | ||
432 | } | 443 | } | ||
433 | 444 | | |||
434 | void SwitcherBackend::stopActivity(const QString &activity) | 445 | void SwitcherBackend::stopActivity(const QString &activity) | ||
435 | { | 446 | { | ||
436 | m_activities.stopActivity(activity); | 447 | m_activities.stopActivity(activity); | ||
437 | } | 448 | } | ||
449 | | ||||
450 | bool SwitcherBackend::dropEnabled() const | ||||
451 | { | ||||
452 | #if HAVE_X11 | ||||
453 | return true; | ||||
454 | #else | ||||
455 | return false; | ||||
456 | #endif | ||||
457 | } | ||||
458 | | ||||
459 | void SwitcherBackend::drop(QMimeData* mimeData, int modifiers, const QVariant &activityId) | ||||
460 | { | ||||
461 | setDropMode(false); | ||||
462 | | ||||
463 | #if HAVE_X11 | ||||
464 | if (KWindowSystem::isPlatformX11()) { | ||||
465 | bool ok = false; | ||||
466 | const QList<WId> &ids = TaskManager::XWindowTasksModel::winIdsFromMimeData(mimeData, &ok); | ||||
467 | | ||||
468 | if (!ok) { | ||||
469 | return; | ||||
470 | } | ||||
471 | | ||||
472 | const QString newActivity = activityId.toString(); | ||||
473 | const QStringList runningActivities = m_activities.runningActivities(); | ||||
474 | | ||||
475 | if (!runningActivities.contains(newActivity)) { | ||||
476 | return; | ||||
477 | } | ||||
478 | | ||||
479 | for (const auto &id : ids) { | ||||
480 | QStringList activities = KWindowInfo(id, NET::Properties(), NET::WM2Activities).activities(); | ||||
481 | | ||||
482 | if (modifiers & Qt::ControlModifier) { | ||||
483 | // Add to the activity instead of moving. | ||||
484 | // This is a hack because the task manager reports that | ||||
485 | // is supports only the 'Move' DND action. | ||||
486 | if (!activities.contains(newActivity)) { | ||||
487 | activities << newActivity; | ||||
488 | } | ||||
489 | | ||||
490 | } else { | ||||
491 | // Move to this activity | ||||
492 | // if on only one activity, set it to only the new activity | ||||
493 | // if on >1 activity, remove it from the current activity and add it to the new activity | ||||
494 | | ||||
495 | const QString currentActivity = m_activities.currentActivity(); | ||||
496 | activities.removeAll(currentActivity); | ||||
497 | activities << newActivity; | ||||
498 | } | ||||
499 | | ||||
500 | KWindowSystem::setOnActivities(id, activities); | ||||
501 | } | ||||
502 | } | ||||
503 | #endif | ||||
504 | } | ||||
505 | | ||||
506 | void SwitcherBackend::setDropMode(bool value) | ||||
507 | { | ||||
508 | if (m_dropModeActive == value) return; | ||||
509 | | ||||
510 | m_dropModeActive = value; | ||||
511 | if (value) { | ||||
512 | setShouldShowSwitcher(true); | ||||
513 | m_dropModeHider.stop(); | ||||
514 | } else { | ||||
515 | m_dropModeHider.start(); | ||||
516 | } | ||||
517 | } | ||||
518 | | ||||
519 | |