Changeset View
Changeset View
Standalone View
Standalone View
effects/screenshot/screenshot.cpp
Show All 34 Lines | |||||
35 | #include <KLocalizedString> | 35 | #include <KLocalizedString> | ||
36 | #include <KNotification> | 36 | #include <KNotification> | ||
37 | 37 | | |||
38 | #include <unistd.h> | 38 | #include <unistd.h> | ||
39 | 39 | | |||
40 | namespace KWin | 40 | namespace KWin | ||
41 | { | 41 | { | ||
42 | 42 | | |||
43 | const static QString s_errorAlreadyTaking = QStringLiteral("org.kde.kwin.Screenshot.Error.AlreadyTaking"); | ||||
44 | const static QString s_errorAlreadyTakingMsg = QStringLiteral("A screenshot is already been taken"); | ||||
45 | const static QString s_errorFd = QStringLiteral("org.kde.kwin.Screenshot.Error.FileDescriptor"); | ||||
46 | const static QString s_errorFdMsg = QStringLiteral("No valid file descriptor"); | ||||
47 | const static QString s_errorCancelled = QStringLiteral("org.kde.kwin.Screenshot.Error.Cancelled"); | ||||
48 | const static QString s_errorCancelledMsg = QStringLiteral("Screenshot got cancelled"); | ||||
49 | const static QString s_errorInvalidArea = QStringLiteral("org.kde.kwin.Screenshot.Error.InvalidArea"); | ||||
50 | const static QString s_errorInvalidAreaMsg = QStringLiteral("Invalid area requested"); | ||||
51 | const static QString s_errorInvalidScreen = QStringLiteral("org.kde.kwin.Screenshot.Error.InvalidScreen"); | ||||
52 | const static QString s_errorInvalidScreenMsg = QStringLiteral("Invalid screen requested"); | ||||
53 | | ||||
43 | bool ScreenShotEffect::supported() | 54 | bool ScreenShotEffect::supported() | ||
44 | { | 55 | { | ||
45 | return effects->compositingType() == XRenderCompositing || | 56 | return effects->compositingType() == XRenderCompositing || | ||
46 | (effects->isOpenGLCompositing() && GLRenderTarget::supported()); | 57 | (effects->isOpenGLCompositing() && GLRenderTarget::supported()); | ||
47 | } | 58 | } | ||
48 | 59 | | |||
49 | ScreenShotEffect::ScreenShotEffect() | 60 | ScreenShotEffect::ScreenShotEffect() | ||
50 | : m_scheduledScreenshot(0) | 61 | : m_scheduledScreenshot(0) | ||
51 | , m_replyConnection(QDBusConnection::sessionBus()) | | |||
52 | { | 62 | { | ||
53 | connect ( effects, SIGNAL(windowClosed(KWin::EffectWindow*)), SLOT(windowClosed(KWin::EffectWindow*)) ); | 63 | connect ( effects, SIGNAL(windowClosed(KWin::EffectWindow*)), SLOT(windowClosed(KWin::EffectWindow*)) ); | ||
54 | QDBusConnection::sessionBus().registerObject(QStringLiteral("/Screenshot"), this, QDBusConnection::ExportScriptableContents); | 64 | QDBusConnection::sessionBus().registerObject(QStringLiteral("/Screenshot"), this, QDBusConnection::ExportScriptableContents); | ||
55 | QDBusConnection::sessionBus().registerService(QStringLiteral("org.kde.kwin.Screenshot")); | 65 | QDBusConnection::sessionBus().registerService(QStringLiteral("org.kde.kwin.Screenshot")); | ||
56 | } | 66 | } | ||
57 | 67 | | |||
58 | ScreenShotEffect::~ScreenShotEffect() | 68 | ScreenShotEffect::~ScreenShotEffect() | ||
59 | { | 69 | { | ||
▲ Show 20 Lines • Show All 200 Lines • ▼ Show 20 Line(s) | 268 | if (file.open(fd, QIODevice::WriteOnly, QFileDevice::AutoCloseHandle)) { | |||
260 | ds << img; | 270 | ds << img; | ||
261 | file.close(); | 271 | file.close(); | ||
262 | } else { | 272 | } else { | ||
263 | close(fd); | 273 | close(fd); | ||
264 | } | 274 | } | ||
265 | }, m_fd, img); | 275 | }, m_fd, img); | ||
266 | m_fd = -1; | 276 | m_fd = -1; | ||
267 | } else { | 277 | } else { | ||
268 | m_replyConnection.send(m_replyMessage.createReply(saveTempImage(img))); | 278 | QDBusConnection::sessionBus().send(m_replyMessage.createReply(saveTempImage(img))); | ||
269 | } | 279 | } | ||
270 | m_scheduledGeometry = QRect(); | 280 | m_scheduledGeometry = QRect(); | ||
271 | m_multipleOutputsImage = QImage(); | 281 | m_multipleOutputsImage = QImage(); | ||
272 | m_multipleOutputsRendered = QRegion(); | 282 | m_multipleOutputsRendered = QRegion(); | ||
273 | m_captureCursor = false; | 283 | m_captureCursor = false; | ||
274 | m_windowMode = WindowMode::NoCapture; | 284 | m_windowMode = WindowMode::NoCapture; | ||
275 | } | 285 | } | ||
276 | 286 | | |||
Show All 13 Lines | 299 | KNotification::event(KNotification::Notification, | |||
290 | i18nc("Notification caption that a screenshot got saved to file", "Screenshot"), | 300 | i18nc("Notification caption that a screenshot got saved to file", "Screenshot"), | ||
291 | i18nc("Notification with path to screenshot file", "Screenshot saved to %1", temp.fileName()), | 301 | i18nc("Notification with path to screenshot file", "Screenshot saved to %1", temp.fileName()), | ||
292 | QStringLiteral("spectacle")); | 302 | QStringLiteral("spectacle")); | ||
293 | return temp.fileName(); | 303 | return temp.fileName(); | ||
294 | } | 304 | } | ||
295 | 305 | | |||
296 | void ScreenShotEffect::screenshotWindowUnderCursor(int mask) | 306 | void ScreenShotEffect::screenshotWindowUnderCursor(int mask) | ||
297 | { | 307 | { | ||
308 | if (isTakingScreenshot()) { | ||||
309 | sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg); | ||||
310 | return; | ||||
311 | } | ||||
298 | m_type = (ScreenShotType)mask; | 312 | m_type = (ScreenShotType)mask; | ||
299 | const QPoint cursor = effects->cursorPos(); | 313 | const QPoint cursor = effects->cursorPos(); | ||
300 | EffectWindowList order = effects->stackingOrder(); | 314 | EffectWindowList order = effects->stackingOrder(); | ||
301 | EffectWindowList::const_iterator it = order.constEnd(), first = order.constBegin(); | 315 | EffectWindowList::const_iterator it = order.constEnd(), first = order.constBegin(); | ||
302 | while( it != first ) { | 316 | while( it != first ) { | ||
303 | m_scheduledScreenshot = *(--it); | 317 | m_scheduledScreenshot = *(--it); | ||
304 | if (m_scheduledScreenshot->isOnCurrentDesktop() && | 318 | if (m_scheduledScreenshot->isOnCurrentDesktop() && | ||
305 | !m_scheduledScreenshot->isMinimized() && !m_scheduledScreenshot->isDeleted() && | 319 | !m_scheduledScreenshot->isMinimized() && !m_scheduledScreenshot->isDeleted() && | ||
Show All 17 Lines | 330 | { | |||
323 | } | 337 | } | ||
324 | } | 338 | } | ||
325 | 339 | | |||
326 | QString ScreenShotEffect::interactive(int mask) | 340 | QString ScreenShotEffect::interactive(int mask) | ||
327 | { | 341 | { | ||
328 | if (!calledFromDBus()) { | 342 | if (!calledFromDBus()) { | ||
329 | return QString(); | 343 | return QString(); | ||
330 | } | 344 | } | ||
331 | if (!m_scheduledGeometry.isNull() || m_windowMode != WindowMode::NoCapture) { | 345 | if (isTakingScreenshot()) { | ||
332 | sendErrorReply(QDBusError::Failed, "A screenshot is already been taken"); | 346 | sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg); | ||
333 | return QString(); | 347 | return QString(); | ||
334 | } | 348 | } | ||
335 | m_type = (ScreenShotType) mask; | 349 | m_type = (ScreenShotType) mask; | ||
336 | m_windowMode = WindowMode::File; | 350 | m_windowMode = WindowMode::File; | ||
337 | m_replyConnection = connection(); | | |||
338 | m_replyMessage = message(); | 351 | m_replyMessage = message(); | ||
339 | setDelayedReply(true); | 352 | setDelayedReply(true); | ||
340 | effects->startInteractiveWindowSelection( | 353 | effects->startInteractiveWindowSelection( | ||
341 | [this] (EffectWindow *w) { | 354 | [this] (EffectWindow *w) { | ||
342 | hideInfoMessage(); | 355 | hideInfoMessage(); | ||
343 | if (!w) { | 356 | if (!w) { | ||
344 | m_replyConnection.send(m_replyMessage.createErrorReply(QDBusError::Failed, "Screenshot got cancelled")); | 357 | QDBusConnection::sessionBus().send(m_replyMessage.createErrorReply(s_errorCancelled, s_errorCancelledMsg)); | ||
345 | m_windowMode = WindowMode::NoCapture; | 358 | m_windowMode = WindowMode::NoCapture; | ||
346 | return; | 359 | return; | ||
347 | } else { | 360 | } else { | ||
348 | m_scheduledScreenshot = w; | 361 | m_scheduledScreenshot = w; | ||
349 | m_scheduledScreenshot->addRepaintFull(); | 362 | m_scheduledScreenshot->addRepaintFull(); | ||
350 | } | 363 | } | ||
351 | }); | 364 | }); | ||
352 | 365 | | |||
353 | showInfoMessage(InfoMessageMode::Window); | 366 | showInfoMessage(InfoMessageMode::Window); | ||
354 | return QString(); | 367 | return QString(); | ||
355 | } | 368 | } | ||
356 | 369 | | |||
357 | void ScreenShotEffect::interactive(QDBusUnixFileDescriptor fd, int mask) | 370 | void ScreenShotEffect::interactive(QDBusUnixFileDescriptor fd, int mask) | ||
358 | { | 371 | { | ||
359 | if (!calledFromDBus()) { | 372 | if (!calledFromDBus()) { | ||
360 | return; | 373 | return; | ||
361 | } | 374 | } | ||
362 | if (!m_scheduledGeometry.isNull() || m_windowMode != WindowMode::NoCapture) { | 375 | if (isTakingScreenshot()) { | ||
363 | sendErrorReply(QDBusError::Failed, "A screenshot is already been taken"); | 376 | sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg); | ||
364 | return; | 377 | return; | ||
365 | } | 378 | } | ||
366 | m_fd = dup(fd.fileDescriptor()); | 379 | m_fd = dup(fd.fileDescriptor()); | ||
367 | if (m_fd == -1) { | 380 | if (m_fd == -1) { | ||
368 | sendErrorReply(QDBusError::Failed, "No valid file descriptor"); | 381 | sendErrorReply(s_errorFd, s_errorFdMsg); | ||
369 | return; | 382 | return; | ||
370 | } | 383 | } | ||
371 | m_type = (ScreenShotType) mask; | 384 | m_type = (ScreenShotType) mask; | ||
372 | m_windowMode = WindowMode::FileDescriptor; | 385 | m_windowMode = WindowMode::FileDescriptor; | ||
373 | 386 | | |||
374 | effects->startInteractiveWindowSelection( | 387 | effects->startInteractiveWindowSelection( | ||
375 | [this] (EffectWindow *w) { | 388 | [this] (EffectWindow *w) { | ||
376 | hideInfoMessage(); | 389 | hideInfoMessage(); | ||
Show All 38 Lines | 427 | { | |||
415 | m_infoFrame.reset(); | 428 | m_infoFrame.reset(); | ||
416 | } | 429 | } | ||
417 | 430 | | |||
418 | QString ScreenShotEffect::screenshotFullscreen(bool captureCursor) | 431 | QString ScreenShotEffect::screenshotFullscreen(bool captureCursor) | ||
419 | { | 432 | { | ||
420 | if (!calledFromDBus()) { | 433 | if (!calledFromDBus()) { | ||
421 | return QString(); | 434 | return QString(); | ||
422 | } | 435 | } | ||
423 | if (!m_scheduledGeometry.isNull()) { | 436 | if (isTakingScreenshot()) { | ||
424 | sendErrorReply(QDBusError::Failed, "A screenshot is already been taken"); | 437 | sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg); | ||
425 | return QString(); | 438 | return QString(); | ||
426 | } | 439 | } | ||
427 | m_replyConnection = connection(); | | |||
428 | m_replyMessage = message(); | 440 | m_replyMessage = message(); | ||
429 | setDelayedReply(true); | 441 | setDelayedReply(true); | ||
430 | m_scheduledGeometry = effects->virtualScreenGeometry(); | 442 | m_scheduledGeometry = effects->virtualScreenGeometry(); | ||
431 | m_captureCursor = captureCursor; | 443 | m_captureCursor = captureCursor; | ||
432 | effects->addRepaintFull(); | 444 | effects->addRepaintFull(); | ||
433 | return QString(); | 445 | return QString(); | ||
434 | } | 446 | } | ||
435 | 447 | | |||
436 | void ScreenShotEffect::screenshotFullscreen(QDBusUnixFileDescriptor fd, bool captureCursor) | 448 | void ScreenShotEffect::screenshotFullscreen(QDBusUnixFileDescriptor fd, bool captureCursor) | ||
437 | { | 449 | { | ||
438 | if (!calledFromDBus()) { | 450 | if (!calledFromDBus()) { | ||
439 | return; | 451 | return; | ||
440 | } | 452 | } | ||
441 | if (!m_scheduledGeometry.isNull()) { | 453 | if (isTakingScreenshot()) { | ||
442 | sendErrorReply(QDBusError::Failed, "A screenshot is already been taken"); | 454 | sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg); | ||
443 | return; | 455 | return; | ||
444 | } | 456 | } | ||
445 | m_fd = dup(fd.fileDescriptor()); | 457 | m_fd = dup(fd.fileDescriptor()); | ||
446 | if (m_fd == -1) { | 458 | if (m_fd == -1) { | ||
447 | sendErrorReply(QDBusError::Failed, "No valid file descriptor"); | 459 | sendErrorReply(s_errorFd, s_errorFdMsg); | ||
448 | return; | 460 | return; | ||
449 | } | 461 | } | ||
450 | m_captureCursor = captureCursor; | 462 | m_captureCursor = captureCursor; | ||
451 | 463 | | |||
452 | showInfoMessage(InfoMessageMode::Screen); | 464 | showInfoMessage(InfoMessageMode::Screen); | ||
453 | effects->startInteractivePositionSelection( | 465 | effects->startInteractivePositionSelection( | ||
454 | [this] (const QPoint &p) { | 466 | [this] (const QPoint &p) { | ||
455 | hideInfoMessage(); | 467 | hideInfoMessage(); | ||
Show All 9 Lines | |||||
465 | ); | 477 | ); | ||
466 | } | 478 | } | ||
467 | 479 | | |||
468 | QString ScreenShotEffect::screenshotScreen(int screen, bool captureCursor) | 480 | QString ScreenShotEffect::screenshotScreen(int screen, bool captureCursor) | ||
469 | { | 481 | { | ||
470 | if (!calledFromDBus()) { | 482 | if (!calledFromDBus()) { | ||
471 | return QString(); | 483 | return QString(); | ||
472 | } | 484 | } | ||
473 | if (!m_scheduledGeometry.isNull()) { | 485 | if (isTakingScreenshot()) { | ||
474 | sendErrorReply(QDBusError::Failed, "A screenshot is already been taken"); | 486 | sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg); | ||
475 | return QString(); | 487 | return QString(); | ||
476 | } | 488 | } | ||
477 | m_scheduledGeometry = effects->clientArea(FullScreenArea, screen, 0); | 489 | m_scheduledGeometry = effects->clientArea(FullScreenArea, screen, 0); | ||
478 | if (m_scheduledGeometry.isNull()) { | 490 | if (m_scheduledGeometry.isNull()) { | ||
479 | sendErrorReply(QDBusError::Failed, "Invalid screen requested"); | 491 | sendErrorReply(s_errorInvalidScreen, s_errorInvalidScreenMsg); | ||
480 | return QString(); | 492 | return QString(); | ||
481 | } | 493 | } | ||
482 | m_captureCursor = captureCursor; | 494 | m_captureCursor = captureCursor; | ||
483 | m_replyConnection = connection(); | | |||
484 | m_replyMessage = message(); | 495 | m_replyMessage = message(); | ||
485 | setDelayedReply(true); | 496 | setDelayedReply(true); | ||
486 | effects->addRepaint(m_scheduledGeometry); | 497 | effects->addRepaint(m_scheduledGeometry); | ||
487 | return QString(); | 498 | return QString(); | ||
488 | } | 499 | } | ||
489 | 500 | | |||
490 | void ScreenShotEffect::screenshotScreen(QDBusUnixFileDescriptor fd, bool captureCursor) | 501 | void ScreenShotEffect::screenshotScreen(QDBusUnixFileDescriptor fd, bool captureCursor) | ||
491 | { | 502 | { | ||
492 | if (!calledFromDBus()) { | 503 | if (!calledFromDBus()) { | ||
493 | return; | 504 | return; | ||
494 | } | 505 | } | ||
495 | if (!m_scheduledGeometry.isNull()) { | 506 | if (isTakingScreenshot()) { | ||
496 | sendErrorReply(QDBusError::Failed, "A screenshot is already been taken"); | 507 | sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg); | ||
497 | return; | 508 | return; | ||
498 | } | 509 | } | ||
499 | m_fd = dup(fd.fileDescriptor()); | 510 | m_fd = dup(fd.fileDescriptor()); | ||
500 | if (m_fd == -1) { | 511 | if (m_fd == -1) { | ||
501 | sendErrorReply(QDBusError::Failed, "No valid file descriptor"); | 512 | sendErrorReply(s_errorFd, s_errorFdMsg); | ||
502 | return; | 513 | return; | ||
503 | } | 514 | } | ||
504 | m_captureCursor = captureCursor; | 515 | m_captureCursor = captureCursor; | ||
505 | 516 | | |||
506 | showInfoMessage(InfoMessageMode::Screen); | 517 | showInfoMessage(InfoMessageMode::Screen); | ||
507 | effects->startInteractivePositionSelection( | 518 | effects->startInteractivePositionSelection( | ||
508 | [this] (const QPoint &p) { | 519 | [this] (const QPoint &p) { | ||
509 | hideInfoMessage(); | 520 | hideInfoMessage(); | ||
Show All 14 Lines | |||||
524 | ); | 535 | ); | ||
525 | } | 536 | } | ||
526 | 537 | | |||
527 | QString ScreenShotEffect::screenshotArea(int x, int y, int width, int height, bool captureCursor) | 538 | QString ScreenShotEffect::screenshotArea(int x, int y, int width, int height, bool captureCursor) | ||
528 | { | 539 | { | ||
529 | if (!calledFromDBus()) { | 540 | if (!calledFromDBus()) { | ||
530 | return QString(); | 541 | return QString(); | ||
531 | } | 542 | } | ||
532 | if (!m_scheduledGeometry.isNull()) { | 543 | if (isTakingScreenshot()) { | ||
533 | sendErrorReply(QDBusError::Failed, "A screenshot is already been taken"); | 544 | sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg); | ||
534 | return QString(); | 545 | return QString(); | ||
535 | } | 546 | } | ||
536 | m_scheduledGeometry = QRect(x, y, width, height); | 547 | m_scheduledGeometry = QRect(x, y, width, height); | ||
537 | if (m_scheduledGeometry.isNull() || m_scheduledGeometry.isEmpty()) { | 548 | if (m_scheduledGeometry.isNull() || m_scheduledGeometry.isEmpty()) { | ||
538 | m_scheduledGeometry = QRect(); | 549 | m_scheduledGeometry = QRect(); | ||
539 | sendErrorReply(QDBusError::Failed, "Invalid area requested"); | 550 | sendErrorReply(s_errorInvalidArea, s_errorInvalidAreaMsg); | ||
540 | return QString(); | 551 | return QString(); | ||
541 | } | 552 | } | ||
542 | m_captureCursor = captureCursor; | 553 | m_captureCursor = captureCursor; | ||
543 | m_replyConnection = connection(); | | |||
544 | m_replyMessage = message(); | 554 | m_replyMessage = message(); | ||
545 | setDelayedReply(true); | 555 | setDelayedReply(true); | ||
546 | effects->addRepaint(m_scheduledGeometry); | 556 | effects->addRepaint(m_scheduledGeometry); | ||
547 | return QString(); | 557 | return QString(); | ||
548 | } | 558 | } | ||
549 | 559 | | |||
550 | QImage ScreenShotEffect::blitScreenshot(const QRect &geometry) | 560 | QImage ScreenShotEffect::blitScreenshot(const QRect &geometry) | ||
551 | { | 561 | { | ||
▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Line(s) | |||||
637 | void ScreenShotEffect::windowClosed( EffectWindow* w ) | 647 | void ScreenShotEffect::windowClosed( EffectWindow* w ) | ||
638 | { | 648 | { | ||
639 | if (w == m_scheduledScreenshot) { | 649 | if (w == m_scheduledScreenshot) { | ||
640 | m_scheduledScreenshot = NULL; | 650 | m_scheduledScreenshot = NULL; | ||
641 | screenshotWindowUnderCursor(m_type); | 651 | screenshotWindowUnderCursor(m_type); | ||
642 | } | 652 | } | ||
643 | } | 653 | } | ||
644 | 654 | | |||
655 | bool ScreenShotEffect::isTakingScreenshot() const | ||||
656 | { | ||||
657 | if (!m_scheduledGeometry.isNull()) { | ||||
658 | return true; | ||||
659 | } | ||||
660 | if (m_windowMode != WindowMode::NoCapture) { | ||||
661 | return true; | ||||
662 | } | ||||
663 | if (m_fd != -1) { | ||||
664 | return true; | ||||
665 | } | ||||
666 | return false; | ||||
667 | } | ||||
668 | | ||||
645 | } // namespace | 669 | } // namespace |