Changeset View
Changeset View
Standalone View
Standalone View
effects/screenshot/screenshot.cpp
Show All 21 Lines | |||||
22 | #include <kwinglplatform.h> | 22 | #include <kwinglplatform.h> | ||
23 | #include <kwinglutils.h> | 23 | #include <kwinglutils.h> | ||
24 | #include <kwinxrenderutils.h> | 24 | #include <kwinxrenderutils.h> | ||
25 | #include <QtConcurrentRun> | 25 | #include <QtConcurrentRun> | ||
26 | #include <QDataStream> | 26 | #include <QDataStream> | ||
27 | #include <QTemporaryFile> | 27 | #include <QTemporaryFile> | ||
28 | #include <QDir> | 28 | #include <QDir> | ||
29 | #include <QDBusConnection> | 29 | #include <QDBusConnection> | ||
30 | #include <QDBusConnectionInterface> | ||||
31 | #include <QDBusReply> | ||||
30 | #include <QVarLengthArray> | 32 | #include <QVarLengthArray> | ||
31 | #include <QPainter> | 33 | #include <QPainter> | ||
32 | #include <QMatrix4x4> | 34 | #include <QMatrix4x4> | ||
33 | #include <xcb/xcb_image.h> | 35 | #include <xcb/xcb_image.h> | ||
34 | #include <QPoint> | 36 | #include <QPoint> | ||
35 | 37 | | |||
36 | #include <KLocalizedString> | 38 | #include <KLocalizedString> | ||
37 | #include <KNotification> | 39 | #include <KNotification> | ||
38 | 40 | | |||
39 | #include <unistd.h> | 41 | #include <unistd.h> | ||
42 | #include "../service_utils.h" | ||||
40 | 43 | | |||
41 | class ComparableQPoint : public QPoint | 44 | class ComparableQPoint : public QPoint | ||
42 | { | 45 | { | ||
43 | public: | 46 | public: | ||
44 | ComparableQPoint(QPoint& point): QPoint(point.x(), point.y()) | 47 | ComparableQPoint(QPoint& point): QPoint(point.x(), point.y()) | ||
45 | {} | 48 | {} | ||
46 | 49 | | |||
47 | ComparableQPoint(QPoint point): QPoint(point.x(), point.y()) | 50 | ComparableQPoint(QPoint point): QPoint(point.x(), point.y()) | ||
Show All 10 Lines | |||||
58 | }; | 61 | }; | ||
59 | 62 | | |||
60 | 63 | | |||
61 | namespace KWin | 64 | namespace KWin | ||
62 | { | 65 | { | ||
63 | 66 | | |||
64 | const static QString s_errorAlreadyTaking = QStringLiteral("org.kde.kwin.Screenshot.Error.AlreadyTaking"); | 67 | const static QString s_errorAlreadyTaking = QStringLiteral("org.kde.kwin.Screenshot.Error.AlreadyTaking"); | ||
65 | const static QString s_errorAlreadyTakingMsg = QStringLiteral("A screenshot is already been taken"); | 68 | const static QString s_errorAlreadyTakingMsg = QStringLiteral("A screenshot is already been taken"); | ||
69 | const static QString s_errorNotAuthorized = QStringLiteral("org.kde.kwin.Screenshot.Error.NoAuthorized"); | ||||
70 | const static QString s_errorNotAuthorizedMsg = QStringLiteral("The process is not authorized to take a screenshot"); | ||||
66 | const static QString s_errorFd = QStringLiteral("org.kde.kwin.Screenshot.Error.FileDescriptor"); | 71 | const static QString s_errorFd = QStringLiteral("org.kde.kwin.Screenshot.Error.FileDescriptor"); | ||
67 | const static QString s_errorFdMsg = QStringLiteral("No valid file descriptor"); | 72 | const static QString s_errorFdMsg = QStringLiteral("No valid file descriptor"); | ||
68 | const static QString s_errorCancelled = QStringLiteral("org.kde.kwin.Screenshot.Error.Cancelled"); | 73 | const static QString s_errorCancelled = QStringLiteral("org.kde.kwin.Screenshot.Error.Cancelled"); | ||
69 | const static QString s_errorCancelledMsg = QStringLiteral("Screenshot got cancelled"); | 74 | const static QString s_errorCancelledMsg = QStringLiteral("Screenshot got cancelled"); | ||
70 | const static QString s_errorInvalidArea = QStringLiteral("org.kde.kwin.Screenshot.Error.InvalidArea"); | 75 | const static QString s_errorInvalidArea = QStringLiteral("org.kde.kwin.Screenshot.Error.InvalidArea"); | ||
71 | const static QString s_errorInvalidAreaMsg = QStringLiteral("Invalid area requested"); | 76 | const static QString s_errorInvalidAreaMsg = QStringLiteral("Invalid area requested"); | ||
72 | const static QString s_errorInvalidScreen = QStringLiteral("org.kde.kwin.Screenshot.Error.InvalidScreen"); | 77 | const static QString s_errorInvalidScreen = QStringLiteral("org.kde.kwin.Screenshot.Error.InvalidScreen"); | ||
73 | const static QString s_errorInvalidScreenMsg = QStringLiteral("Invalid screen requested"); | 78 | const static QString s_errorInvalidScreenMsg = QStringLiteral("Invalid screen requested"); | ||
79 | const static QString s_dbusInterfaceName = QStringLiteral("org_kde_kwin_effect-screenshot"); | ||||
apol: But this is not a wayland interface, is it? :/ | |||||
I am abusing things here by using the same X-KDE-Wayland-Interfaces for authorized Wayland protocol and DBUS interface. meven: I am abusing things here by using the same `X-KDE-Wayland-Interfaces` for authorized Wayland… | |||||
zzag: This is not a proper d-bus interface name. | |||||
I am well-aware. This is a key that application's desktop file must declare in a X-KDE-DBUS-Restricted-Interfaces field. So I should rename and add some comments, I guess. meven: I am well-aware.
This is a key that application's desktop file must declare in a X-KDE-DBUS… | |||||
74 | 80 | | |||
75 | bool ScreenShotEffect::supported() | 81 | bool ScreenShotEffect::supported() | ||
76 | { | 82 | { | ||
77 | return effects->compositingType() == XRenderCompositing || | 83 | return effects->compositingType() == XRenderCompositing || | ||
78 | (effects->isOpenGLCompositing() && GLRenderTarget::supported()); | 84 | (effects->isOpenGLCompositing() && GLRenderTarget::supported()); | ||
79 | } | 85 | } | ||
80 | 86 | | |||
81 | ScreenShotEffect::ScreenShotEffect() | 87 | ScreenShotEffect::ScreenShotEffect() | ||
▲ Show 20 Lines • Show All 409 Lines • ▼ Show 20 Line(s) | 495 | { | |||
491 | EffectWindow* w = effects->findWindow(winid); | 497 | EffectWindow* w = effects->findWindow(winid); | ||
492 | if(w && !w->isMinimized() && !w->isDeleted()) { | 498 | if(w && !w->isMinimized() && !w->isDeleted()) { | ||
493 | m_windowMode = WindowMode::Xpixmap; | 499 | m_windowMode = WindowMode::Xpixmap; | ||
494 | m_scheduledScreenshot = w; | 500 | m_scheduledScreenshot = w; | ||
495 | m_scheduledScreenshot->addRepaintFull(); | 501 | m_scheduledScreenshot->addRepaintFull(); | ||
496 | } | 502 | } | ||
497 | } | 503 | } | ||
498 | 504 | | |||
499 | QString ScreenShotEffect::interactive(int mask) | 505 | bool ScreenShotEffect::checkCall () const | ||
ngraham: whitespace | |||||
500 | { | 506 | { | ||
501 | if (!calledFromDBus()) { | 507 | if (!calledFromDBus()) { | ||
502 | return QString(); | 508 | return false; | ||
509 | } | ||||
510 | | ||||
511 | const QDBusReply<uint> reply = connection().interface()->servicePid(message().service()); | ||||
512 | if (reply.isValid()) { | ||||
513 | const uint pid = reply.value(); | ||||
514 | const auto interfaces = KWin::fetchRestrictedDBusInterfacesFromPid(pid); | ||||
515 | if (!interfaces.contains(s_dbusInterfaceName)) { | ||||
516 | sendErrorReply(s_errorNotAuthorized, s_errorNotAuthorizedMsg); | ||||
517 | qCWarning(KWINEFFECTS) << "Process " << pid << " tried to take a screenshot without being granted to DBus interface" << s_dbusInterfaceName; | ||||
518 | return false; | ||||
503 | } | 519 | } | ||
520 | } else { | ||||
521 | return false; | ||||
522 | } | ||||
523 | | ||||
504 | if (isTakingScreenshot()) { | 524 | if (isTakingScreenshot()) { | ||
505 | sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg); | 525 | sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg); | ||
526 | return false; | ||||
527 | } | ||||
528 | return true; | ||||
529 | } | ||||
530 | | ||||
531 | QString ScreenShotEffect::interactive(int mask) | ||||
532 | { | ||||
533 | if (!checkCall()) { | ||||
506 | return QString(); | 534 | return QString(); | ||
507 | } | 535 | } | ||
508 | m_type = (ScreenShotType) mask; | 536 | m_type = (ScreenShotType) mask; | ||
509 | m_windowMode = WindowMode::File; | 537 | m_windowMode = WindowMode::File; | ||
510 | m_replyMessage = message(); | 538 | m_replyMessage = message(); | ||
511 | setDelayedReply(true); | 539 | setDelayedReply(true); | ||
512 | effects->startInteractiveWindowSelection( | 540 | effects->startInteractiveWindowSelection( | ||
513 | [this] (EffectWindow *w) { | 541 | [this] (EffectWindow *w) { | ||
Show All 9 Lines | |||||
523 | }); | 551 | }); | ||
524 | 552 | | |||
525 | showInfoMessage(InfoMessageMode::Window); | 553 | showInfoMessage(InfoMessageMode::Window); | ||
526 | return QString(); | 554 | return QString(); | ||
527 | } | 555 | } | ||
528 | 556 | | |||
529 | void ScreenShotEffect::interactive(QDBusUnixFileDescriptor fd, int mask) | 557 | void ScreenShotEffect::interactive(QDBusUnixFileDescriptor fd, int mask) | ||
530 | { | 558 | { | ||
531 | if (!calledFromDBus()) { | 559 | if (!checkCall()) { | ||
532 | return; | | |||
533 | } | | |||
534 | if (isTakingScreenshot()) { | | |||
535 | sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg); | | |||
536 | return; | 560 | return; | ||
537 | } | 561 | } | ||
538 | m_fd = dup(fd.fileDescriptor()); | 562 | m_fd = dup(fd.fileDescriptor()); | ||
539 | if (m_fd == -1) { | 563 | if (m_fd == -1) { | ||
540 | sendErrorReply(s_errorFd, s_errorFdMsg); | 564 | sendErrorReply(s_errorFd, s_errorFdMsg); | ||
541 | return; | 565 | return; | ||
542 | } | 566 | } | ||
543 | m_type = (ScreenShotType) mask; | 567 | m_type = (ScreenShotType) mask; | ||
Show All 32 Lines | |||||
576 | 600 | | |||
577 | void ScreenShotEffect::hideInfoMessage() | 601 | void ScreenShotEffect::hideInfoMessage() | ||
578 | { | 602 | { | ||
579 | effects->hideOnScreenMessage(EffectsHandler::OnScreenMessageHideFlag::SkipsCloseAnimation); | 603 | effects->hideOnScreenMessage(EffectsHandler::OnScreenMessageHideFlag::SkipsCloseAnimation); | ||
580 | } | 604 | } | ||
581 | 605 | | |||
582 | QString ScreenShotEffect::screenshotFullscreen(bool captureCursor) | 606 | QString ScreenShotEffect::screenshotFullscreen(bool captureCursor) | ||
583 | { | 607 | { | ||
584 | if (!calledFromDBus()) { | 608 | if (!checkCall()) { | ||
585 | return QString(); | | |||
586 | } | | |||
587 | if (isTakingScreenshot()) { | | |||
588 | sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg); | | |||
589 | return QString(); | 609 | return QString(); | ||
590 | } | 610 | } | ||
591 | m_replyMessage = message(); | 611 | m_replyMessage = message(); | ||
592 | setDelayedReply(true); | 612 | setDelayedReply(true); | ||
593 | m_scheduledGeometry = effects->virtualScreenGeometry(); | 613 | m_scheduledGeometry = effects->virtualScreenGeometry(); | ||
594 | m_captureCursor = captureCursor; | 614 | m_captureCursor = captureCursor; | ||
595 | effects->addRepaintFull(); | 615 | effects->addRepaintFull(); | ||
596 | return QString(); | 616 | return QString(); | ||
597 | } | 617 | } | ||
598 | 618 | | |||
599 | void ScreenShotEffect::screenshotFullscreen(QDBusUnixFileDescriptor fd, bool captureCursor, bool shouldReturnNativeSize) | 619 | void ScreenShotEffect::screenshotFullscreen(QDBusUnixFileDescriptor fd, bool captureCursor, bool shouldReturnNativeSize) | ||
600 | { | 620 | { | ||
601 | if (!calledFromDBus()) { | 621 | if (!checkCall()) { | ||
602 | return; | | |||
603 | } | | |||
604 | if (isTakingScreenshot()) { | | |||
605 | sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg); | | |||
606 | return; | 622 | return; | ||
607 | } | 623 | } | ||
608 | m_fd = dup(fd.fileDescriptor()); | 624 | m_fd = dup(fd.fileDescriptor()); | ||
609 | if (m_fd == -1) { | 625 | if (m_fd == -1) { | ||
610 | sendErrorReply(s_errorFd, s_errorFdMsg); | 626 | sendErrorReply(s_errorFd, s_errorFdMsg); | ||
611 | return; | 627 | return; | ||
612 | } | 628 | } | ||
613 | m_captureCursor = captureCursor; | 629 | m_captureCursor = captureCursor; | ||
614 | m_nativeSize = shouldReturnNativeSize; | 630 | m_nativeSize = shouldReturnNativeSize; | ||
615 | 631 | | |||
616 | showInfoMessage(InfoMessageMode::Screen); | | |||
617 | effects->startInteractivePositionSelection( | | |||
618 | [this] (const QPoint &p) { | | |||
619 | hideInfoMessage(); | | |||
620 | if (p == QPoint(-1, -1)) { | | |||
621 | // error condition | | |||
622 | close(m_fd); | | |||
623 | m_fd = -1; | | |||
624 | } else { | | |||
625 | m_scheduledGeometry = effects->virtualScreenGeometry(); | 632 | m_scheduledGeometry = effects->virtualScreenGeometry(); | ||
626 | effects->addRepaint(m_scheduledGeometry); | 633 | effects->addRepaint(m_scheduledGeometry); | ||
627 | } | 634 | } | ||
628 | } | | |||
629 | ); | | |||
630 | } | | |||
631 | 635 | | |||
632 | QString ScreenShotEffect::screenshotScreen(int screen, bool captureCursor) | 636 | QString ScreenShotEffect::screenshotScreen(int screen, bool captureCursor) | ||
633 | { | 637 | { | ||
634 | if (!calledFromDBus()) { | 638 | if (!checkCall()) { | ||
635 | return QString(); | | |||
636 | } | | |||
637 | if (isTakingScreenshot()) { | | |||
638 | sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg); | | |||
639 | return QString(); | 639 | return QString(); | ||
640 | } | 640 | } | ||
641 | m_scheduledGeometry = effects->clientArea(FullScreenArea, screen, 0); | 641 | m_scheduledGeometry = effects->clientArea(FullScreenArea, screen, 0); | ||
642 | if (m_scheduledGeometry.isNull()) { | 642 | if (m_scheduledGeometry.isNull()) { | ||
643 | sendErrorReply(s_errorInvalidScreen, s_errorInvalidScreenMsg); | 643 | sendErrorReply(s_errorInvalidScreen, s_errorInvalidScreenMsg); | ||
644 | return QString(); | 644 | return QString(); | ||
645 | } | 645 | } | ||
646 | m_captureCursor = captureCursor; | 646 | m_captureCursor = captureCursor; | ||
647 | m_replyMessage = message(); | 647 | m_replyMessage = message(); | ||
648 | setDelayedReply(true); | 648 | setDelayedReply(true); | ||
649 | effects->addRepaint(m_scheduledGeometry); | 649 | effects->addRepaint(m_scheduledGeometry); | ||
650 | return QString(); | 650 | return QString(); | ||
651 | } | 651 | } | ||
652 | 652 | | |||
653 | void ScreenShotEffect::screenshotScreen(QDBusUnixFileDescriptor fd, bool captureCursor) | 653 | void ScreenShotEffect::screenshotScreen(QDBusUnixFileDescriptor fd, bool captureCursor) | ||
654 | { | 654 | { | ||
655 | if (!calledFromDBus()) { | 655 | if (!checkCall()) { | ||
656 | return; | | |||
657 | } | | |||
658 | if (isTakingScreenshot()) { | | |||
659 | sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg); | | |||
660 | return; | 656 | return; | ||
661 | } | 657 | } | ||
662 | m_fd = dup(fd.fileDescriptor()); | 658 | m_fd = dup(fd.fileDescriptor()); | ||
663 | if (m_fd == -1) { | 659 | if (m_fd == -1) { | ||
664 | sendErrorReply(s_errorFd, s_errorFdMsg); | 660 | sendErrorReply(s_errorFd, s_errorFdMsg); | ||
665 | return; | 661 | return; | ||
666 | } | 662 | } | ||
667 | m_captureCursor = captureCursor; | 663 | m_captureCursor = captureCursor; | ||
Show All 16 Lines | 673 | } else { | |||
684 | effects->addRepaint(m_scheduledGeometry); | 680 | effects->addRepaint(m_scheduledGeometry); | ||
685 | } | 681 | } | ||
686 | } | 682 | } | ||
687 | ); | 683 | ); | ||
688 | } | 684 | } | ||
689 | 685 | | |||
690 | QString ScreenShotEffect::screenshotArea(int x, int y, int width, int height, bool captureCursor) | 686 | QString ScreenShotEffect::screenshotArea(int x, int y, int width, int height, bool captureCursor) | ||
691 | { | 687 | { | ||
692 | if (!calledFromDBus()) { | 688 | if (!checkCall()) { | ||
693 | return QString(); | | |||
694 | } | | |||
695 | if (isTakingScreenshot()) { | | |||
696 | sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg); | | |||
697 | return QString(); | 689 | return QString(); | ||
698 | } | 690 | } | ||
699 | m_scheduledGeometry = QRect(x, y, width, height); | 691 | m_scheduledGeometry = QRect(x, y, width, height); | ||
700 | if (m_scheduledGeometry.isNull() || m_scheduledGeometry.isEmpty()) { | 692 | if (m_scheduledGeometry.isNull() || m_scheduledGeometry.isEmpty()) { | ||
701 | m_scheduledGeometry = QRect(); | 693 | m_scheduledGeometry = QRect(); | ||
702 | sendErrorReply(s_errorInvalidArea, s_errorInvalidAreaMsg); | 694 | sendErrorReply(s_errorInvalidArea, s_errorInvalidAreaMsg); | ||
703 | return QString(); | 695 | return QString(); | ||
704 | } | 696 | } | ||
▲ Show 20 Lines • Show All 120 Lines • Show Last 20 Lines |
But this is not a wayland interface, is it? :/