diff --git a/CMakeLists.txt b/CMakeLists.txt index bbce6f7..61596c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,122 +1,124 @@ # KDE Application Version, managed by release script set(KDE_APPLICATIONS_VERSION_MAJOR "19") set(KDE_APPLICATIONS_VERSION_MINOR "07") set(KDE_APPLICATIONS_VERSION_MICRO "70") set(KDE_APPLICATIONS_VERSION "${KDE_APPLICATIONS_VERSION_MAJOR}.${KDE_APPLICATIONS_VERSION_MINOR}.${KDE_APPLICATIONS_VERSION_MICRO}") set(SPECTACLE_VERSION ${KDE_APPLICATIONS_VERSION}) # minimum requirements cmake_minimum_required (VERSION 3.5 FATAL_ERROR) # Spectacle project project(Spectacle VERSION ${SPECTACLE_VERSION}) set(QT_MIN_VERSION "5.10.0") set(KF5_MIN_VERSION "5.53.0") set(PLASMA_MIN_VERSION "5.12.0") find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE) set( CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ) # require c++14 set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) # set up kf5 include(KDEInstallDirs) include(KDECMakeSettings) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(ECMInstallIcons) include(ECMSetupVersion) include(FeatureSummary) include(ECMQtDeclareLoggingCategory) include(ECMAddTests) find_package( Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED Core Widgets DBus PrintSupport Test ) find_package( KF5 ${KF5_MIN_VERSION} REQUIRED CoreAddons WidgetsAddons DBusAddons Notifications Config I18n KIO WindowSystem DocTools NewStuff + GlobalAccel + XmlGui ) # optional components find_package(KF5Kipi) if (KF5Kipi_FOUND) set(KIPI_FOUND 1) endif () find_package(KF5Purpose) if (KF5Purpose_FOUND) set(PURPOSE_FOUND 1) endif() find_package(XCB COMPONENTS XFIXES IMAGE UTIL CURSOR) set(XCB_COMPONENTS_ERRORS FALSE) if (XCB_FOUND) find_package(Qt5X11Extras ${QT_MIN_VERSION} REQUIRED) endif() set(XCB_COMPONENTS_FOUND TRUE) if(NOT XCB_XFIXES_FOUND) set(XCB_COMPONENTS_ERRORS "${XCB_COMPONENTS_ERRORS} XCB-XFIXES ") set(XCB_COMPONENTS_FOUND FALSE) endif() if(NOT XCB_IMAGE_FOUND) set(XCB_COMPONENTS_ERRORS "${XCB_COMPONENTS_ERRORS} XCB-IMAGE ") set(XCB_COMPONENTS_FOUND FALSE) endif() if(NOT XCB_UTIL_FOUND) set(XCB_COMPONENTS_ERRORS "${XCB_COMPONENTS_ERRORS} XCB-UTIL ") set(XCB_COMPONENTS_FOUND FALSE) endif() if(NOT XCB_CURSOR_FOUND) set(XCB_COMPONENTS_ERRORS "${XCB_COMPONENTS_ERRORS} XCB-CURSOR ") set(XCB_COMPONENTS_FOUND FALSE) endif() # fail build if none of the platform backends can be found if (NOT XCB_FOUND OR NOT XCB_COMPONENTS_FOUND) message(FATAL_ERROR "No suitable backend platform was found. Currently supported platforms are: XCB Components Required: ${XCB_COMPONENTS_ERRORS}") endif() # hand off to subdirectories add_subdirectory(src) add_subdirectory(dbus) add_subdirectory(desktop) add_subdirectory(icons) add_subdirectory(doc) add_subdirectory(tests) if (${ECM_VERSION} STRGREATER "5.58.0") install(FILES spectacle.categories DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR}) else() install(FILES spectacle.categories DESTINATION ${KDE_INSTALL_CONFDIR}) endif() # summaries feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/ExtraDesktop.sh b/ExtraDesktop.sh deleted file mode 100644 index 07a5fd8..0000000 --- a/ExtraDesktop.sh +++ /dev/null @@ -1,4 +0,0 @@ -#! /bin/sh -#This file outputs in a separate line each file with a .desktop syntax -#that needs to be translated but has a non .desktop extension -find -name \*.khotkeys -print diff --git a/desktop/CMakeLists.txt b/desktop/CMakeLists.txt index 2c3a37c..e45c97c 100644 --- a/desktop/CMakeLists.txt +++ b/desktop/CMakeLists.txt @@ -1,21 +1,32 @@ # install the .desktop and rc files in the correct place install( PROGRAMS org.kde.spectacle.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} ) +install( DIRECTORY DESTINATION "${KDE_INSTALL_FULL_DATAROOTDIR}/kglobalaccel" ) install( - FILES spectacle.notifyrc - DESTINATION ${KNOTIFYRC_INSTALL_DIR} + CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" -E create_symlink \"${KDE_INSTALL_FULL_APPDIR}/org.kde.dolphin.desktop\" \"\$ENV{DESTDIR}${KDE_INSTALL_FULL_DATAROOTDIR}/kglobalaccel/org.kde.dolphin.desktop\")" ) install( - FILES spectacle.khotkeys - DESTINATION ${DATA_INSTALL_DIR}/khotkeys + FILES spectacle.notifyrc + DESTINATION ${KNOTIFYRC_INSTALL_DIR} ) install( FILES org.kde.spectacle.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR} ) + +install( + FILES spectacle_shortcuts.upd + DESTINATION ${KDE_INSTALL_KCONFUPDATEDIR} +) +add_executable(spectacle-migrate-shortcuts MigrateShortcuts.cpp) +target_link_libraries(spectacle-migrate-shortcuts Qt5::DBus KF5::GlobalAccel KF5::ConfigCore KF5::XmlGui KF5::I18n) +install( + TARGETS spectacle-migrate-shortcuts + DESTINATION ${KDE_INSTALL_LIBDIR}/kconf_update_bin +) diff --git a/desktop/MigrateShortcuts.cpp b/desktop/MigrateShortcuts.cpp new file mode 100644 index 0000000..8b0735f --- /dev/null +++ b/desktop/MigrateShortcuts.cpp @@ -0,0 +1,115 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + QDBusInterface khotkeys(QStringLiteral("org.kde.kded5"), QStringLiteral("/modules/khotkeys"), + QStringLiteral("org.kde.khotkeys")); + KConfig khotkeysrc(QStringLiteral("khotkeysrc"), KConfig::SimpleConfig); + int dataCount = KConfigGroup(&khotkeysrc, "Data").readEntry("DataCount", 0); + bool found_spectacle = false; + int spectacleIndex; + for (int i = 1; i <= dataCount; ++i) { + if( KConfigGroup(&khotkeysrc, QStringLiteral("Data_%1").arg(i)).readEntry("ImportId", QString()) == QStringLiteral("spectacle")) { + found_spectacle = true; + spectacleIndex = i; + break; + } + } + QList launchKey; + QList fullScreenKey; + QList regionKey; + QList activeWindowKey; + QStringList ids; + if (found_spectacle) { + for (int i = 1; i <= 4; ++i) { + QString groupName = QStringLiteral("Data_%1_%2").arg(spectacleIndex).arg(i); + QString method = KConfigGroup(&khotkeysrc, groupName + QStringLiteral("Actions0")).readEntry("Call"); + QString id = KConfigGroup(&khotkeysrc, groupName + QStringLiteral("Triggers0")).readEntry("Uuid"); + QList shortcut = KGlobalAccel::self()->globalShortcut(QStringLiteral("khotkeys"), id); + ids.append(id); + /* Name and Comment field are translated but we can find out which action is which by looking at the called + * D-Bus Method */ + if (method == QStringLiteral("StartAgent")) { + launchKey = shortcut; + } else if (method == QStringLiteral("FullScreen")) { + fullScreenKey = shortcut; + } else if (method == QStringLiteral("ActiveWindow")) { + activeWindowKey = shortcut; + } else if (method == QStringLiteral("RectangularRegion")) { + regionKey = shortcut; + } + // Delete the groups from khotkeysrc + khotkeysrc.deleteGroup(groupName); + khotkeysrc.deleteGroup(groupName + QStringLiteral("Actions")); + khotkeysrc.deleteGroup(groupName + QStringLiteral("Actions0")); + khotkeysrc.deleteGroup(groupName + QStringLiteral("Conditions")); + khotkeysrc.deleteGroup(groupName + QStringLiteral("Triggers")); + khotkeysrc.deleteGroup(groupName + QStringLiteral("Triggers0")); + } + khotkeysrc.deleteGroup(QStringLiteral("Data_%1").arg(spectacleIndex)); + khotkeysrc.deleteGroup(QStringLiteral("Data_%1Conditions").arg(spectacleIndex)); + khotkeysrc.sync(); + } + QDBusInterface kglobalaccel(QStringLiteral("org.kde.kglobalaccel"), QStringLiteral("/kglobalaccel"), + QStringLiteral("org.kde.KGlobalAccel")); + // Unregister the khotkeysActions from globalAccel, removeAll didn't Work, so using D-Bus + for(const QString &action : ids) { + kglobalaccel.call(QStringLiteral("unregister"), QStringLiteral("khotkeys"), action); + } + //Setup the default Shortcuts + KActionCollection shortCutActions(static_cast(nullptr)); + shortCutActions.setComponentName(QStringLiteral("org.kde.spectacle.desktop")); + shortCutActions.setComponentDisplayName(QStringLiteral("Spectacle")); + { + QAction *action = new QAction(i18n("Launch Spectacle")); + action->setObjectName(QStringLiteral("_launch")); + shortCutActions.addAction(action->objectName(), action); + } + { + QAction *action = new QAction(i18n("Capture Entire Desktop")); + action->setObjectName(QStringLiteral("FullScreenScreenShot")); + shortCutActions.addAction(action->objectName(), action); + } + { + QAction *action = new QAction(i18n("Capture Current Monitor")); + action->setObjectName(QStringLiteral("CurrentMonitorScreenShot")); + shortCutActions.addAction(action->objectName(), action); + } + { + QAction *action = new QAction(i18n("Capture Active Window")); + action->setObjectName(QStringLiteral("ActiveWindowScreenShot")); + shortCutActions.addAction(action->objectName(), action); + } + { + QAction *action = new QAction(i18n("Capture Rectangular Region")); + action->setObjectName(QStringLiteral("RectangularRegionScreenShot")); + shortCutActions.addAction(action->objectName(), action); + } + QAction* openAction = shortCutActions.action(QStringLiteral("_launch")); + KGlobalAccel::self()->setDefaultShortcut(openAction, {Qt::Key_Print}); + QAction* fullScreenAction = shortCutActions.action(QStringLiteral("FullScreenScreenShot")); + KGlobalAccel::self()->setDefaultShortcut(fullScreenAction, {Qt::SHIFT + Qt::Key_Print}); + QAction* currentScreenAction = shortCutActions.action(QStringLiteral("CurrentMonitorScreenShot")); + QAction* activeWindowAction = shortCutActions.action(QStringLiteral("ActiveWindowScreenShot")); + KGlobalAccel::self()->setDefaultShortcut(activeWindowAction, {Qt::META + Qt::Key_Print}); + QAction* regionAction = shortCutActions.action(QStringLiteral("RectangularRegionScreenShot")); + KGlobalAccel::self()->setDefaultShortcut(regionAction, {Qt::META + Qt::SHIFT + Qt::Key_Print}); + // Finally reinstate the old shortcuts + if (found_spectacle) { + KGlobalAccel::self()->setShortcut(openAction, launchKey, KGlobalAccel::NoAutoloading); + KGlobalAccel::self()->setShortcut(fullScreenAction, fullScreenKey, KGlobalAccel::NoAutoloading); + KGlobalAccel::self()->setShortcut(activeWindowAction, activeWindowKey, KGlobalAccel::NoAutoloading); + KGlobalAccel::self()->setShortcut(regionAction, regionKey, KGlobalAccel::NoAutoloading); + } +} diff --git a/desktop/org.kde.spectacle.desktop b/desktop/org.kde.spectacle.desktop index 324cf8b..5f43e91 100644 --- a/desktop/org.kde.spectacle.desktop +++ b/desktop/org.kde.spectacle.desktop @@ -1,291 +1,296 @@ [Desktop Entry] GenericName=Screenshot Capture Utility GenericName[ar]=أداة لأخذ اللقطات GenericName[bg]=Инструмент за заснемане на екрана GenericName[ca]=Utilitat per prendre captures de pantalla GenericName[ca@valencia]=Utilitat per prendre captures de pantalla GenericName[cs]=Nástroj na snímání obrazovky GenericName[da]=Værktøj til skærmbilleder GenericName[de]=Dienstprogramm für Bildschirmfotos GenericName[el]=Εργαλείο λήψης στιγμιοτύπων οθόνης GenericName[en_GB]=Screenshot Capture Utility GenericName[es]=Utilidad de capturas de pantalla GenericName[et]=Ekraani pildistamise tööriist GenericName[eu]=Pantaila-argazkiak atzemateko baliagarritasuna GenericName[fi]=Kuvankaappausohjelma GenericName[fr]=Utilitaire de capture d'écran GenericName[gl]=Utilidade para facer capturas de pantalla GenericName[he]=כלי לצילום מסך GenericName[ia]=Utilitate de captura de instantaneo de schermo GenericName[id]=Utilitas Tangkapan Screenshot GenericName[it]=Accessorio per catturare schermate GenericName[ko]=화면 캡처 유틸리티 GenericName[lt]=KDE ekranvaizdžių paveikslavimas GenericName[nl]=Hulpmiddel voor het maken van een schermafdruk GenericName[nn]=Verktøy for å lagra skjermbilete GenericName[pl]=Narzędzie do przechwytywania ekranu GenericName[pt]=Utilitário de Captura de Imagens GenericName[pt_BR]=Utilitário de captura de tela GenericName[ro]=Utilitar de capturare a ecranului GenericName[ru]=Создание снимков экрана GenericName[sk]=Nástroj na snímanie obrazovky GenericName[sl]=Pripomoček za zajem zaslona GenericName[sr]=Алатка за хватање снимака екрана GenericName[sr@ijekavian]=Алатка за хватање снимака екрана GenericName[sr@ijekavianlatin]=Alatka za hvatanje snimaka ekrana GenericName[sr@latin]=Alatka za hvatanje snimaka ekrana GenericName[sv]=Verktyg för att ta skärmbilder GenericName[tr]=Ekran Görüntüsü Yakalama Aracı GenericName[uk]=Програма для створення знімків екрана GenericName[x-test]=xxScreenshot Capture Utilityxx GenericName[zh_CN]=截图抓取工具 GenericName[zh_TW]=畫面擷取工具 Name=Spectacle Name[ca]=Spectacle Name[ca@valencia]=Spectacle Name[cs]=Spectacle Name[da]=Spectacle Name[de]=Spectacle Name[el]=Spectacle Name[en_GB]=Spectacle Name[es]=Spectacle Name[et]=Spectacle Name[eu]=Spectacle Name[fi]=Spectacle Name[fr]=Spectacle Name[gl]=Spectacle Name[ia]=Spectacle Name[id]=Spectacle Name[it]=Spectacle Name[ko]=Spectacle Name[lt]=Spectacle Name[nl]=Spectacle Name[nn]=Spectacle Name[pl]=Spectacle Name[pt]=Spectacle Name[pt_BR]=Spectacle Name[ru]=Spectacle Name[sk]=Spectacle Name[sl]=Spectacle Name[sr]=Спектакл Name[sr@ijekavian]=Спектакл Name[sr@ijekavianlatin]=Spectacle Name[sr@latin]=Spectacle Name[sv]=Spectacle Name[tr]=Spectacle Name[uk]=Spectacle Name[x-test]=xxSpectaclexx Name[zh_CN]=Spectacle Name[zh_TW]=Spectacle Comment=Screenshot capture utility Comment[ca]=Utilitat per prendre captures de pantalla Comment[ca@valencia]=Utilitat per prendre captures de pantalla Comment[es]=Utilidad de captura de pantalla Comment[it]=Accessorio per catturare schermate Comment[ko]=화면 캡처 유틸리티 Comment[nl]=Hulpmiddel voor het maken van een schermafdruk Comment[pt]=Utilitário de captura de imagens do ecrã Comment[pt_BR]=Utilitário de captura de tela Comment[sv]=Verktyg för att ta skärmbilder Comment[uk]=Програма для створення знімків екрана Comment[x-test]=xxScreenshot capture utilityxx Comment[zh_TW]=畫面擷取工具 Categories=Qt;KDE;Utility; Keywords=snapshot;capture;print;screenshot;snipping;snip; Keywords[ca]=captura de pantalla;captura;imprimeix;impressió; Keywords[ca@valencia]=captura de pantalla;captura;imprimeix;impressió; Keywords[en_GB]=snapshot;capture;print;screenshot;snipping;snip; Keywords[es]=captura;capturar;imprimir;captura de pantalla; Keywords[fi]=kuvakaappaus;kaappaa;tulosta;ruutukaappaus;leike; Keywords[fr]=instantané;capture;impression;capture d'écran;découpage;découpe; Keywords[gl]=captura;capturar;imprimir;captura de pantalla;recorte;recortar; Keywords[it]=schermata;cattura;stampa;screenshot;ritagliare;ritaglio; Keywords[ko]=snapshot;capture;print;screenshot;snipping;snip;스냅샷;캡처;인쇄;스크린샷;스냅; Keywords[nl]=momentopname;vangen;afdrukken;schermafdruk;bezig met knippen;knip; Keywords[nn]=skjermbilete;skjermskot;utskrift;print;screenshot;utklipp; Keywords[pl]=zrzut;migawka;przechwycenie;drukowanie;wycinek; Keywords[pt]=fotografia;captura;imprimir;imagem;fotografia;foto; Keywords[pt_BR]=snapshot;captura;imprimir;captura de tala;recortar;cortar; Keywords[ru]=snapshot;capture;print;screenshot;snipping;snip;снимок;захват;печать;снимок экрана;скриншот Keywords[sk]=snímka;zachytiť;tlačiť;snímka obrazovky;strihanie;strihať Keywords[sv]=ta;skriva ut;skärmbild;klippa ut;klippa; Keywords[uk]=знімок;захоплення;друк;знімок вікна;вікно;знімок екрана;екран;snapshot;capture;print;screenshot;snipping;snip; Keywords[x-test]=xxsnapshotxx;xxcapturexx;xxprintxx;xxscreenshotxx;xxsnippingxx;xxsnipxx; Keywords[zh_CN]=snapshot;capture;print;screenshot;snipping;snip;快照;截图;抓取;屏幕截图; Keywords[zh_TW]=snapshot;capture;print;screenshot;snipping;snip;截圖;擷取;截圖程式 Exec=qdbus org.kde.Spectacle / StartAgent Icon=spectacle Type=Application Terminal=false StartupNotify=false Actions=FullScreenScreenShot;CurrentMonitorScreenShot;ActiveWindowScreenShot;RectangularRegionScreenShot; X-DBUS-StartupType=Multi X-DBUS-ServiceName=org.kde.Spectacle +X-KDE-Shortcuts=Print [Desktop Action FullScreenScreenShot] Name=Capture Entire Desktop Name[ar]=التقط سطح المكتب بالكامل Name[ca]=Captura l'escriptori sencer Name[ca@valencia]=Captura l'escriptori sencer Name[cs]=Zachytit celou plochu Name[da]=Indfang hele skrivebordet Name[de]=Die gesamte Arbeitsfläche aufnehmen Name[el]=Λήψη όλης της επιφάνειας εργασίας Name[en_GB]=Capture Entire Desktop Name[es]=Capturar todo el escritorio Name[et]=Kogu töölaua pildistamine Name[eu]=Atzeman mahaigain osoa Name[fi]=Kaappaa koko työpöytä Name[fr]=Capturer le bureau entier Name[gl]=Capturar todo o escritorio Name[he]=צילום כל שולחן עבודה Name[ia]=Captura le scriptorio integre Name[id]=Tangkap Seluruh Desktop Name[it]=Cattura l'intero desktop Name[ko]=전체 데스크톱 찍기 Name[lt]=Paveiksluoti visą darbalaukį Name[nl]=Gehele bureaublad opnemen Name[nn]=Ta bilete av heile skrivebordet Name[pl]=Przechwyć cały pulpit Name[pt]=Capturar Todo o Ecrã Name[pt_BR]=Capturar toda a área de trabalho Name[ru]=Сделать снимок всех экранов Name[sk]=Zachytiť celú plochu Name[sl]=Zajemi celotno namizje Name[sr]=Сними целу површ Name[sr@ijekavian]=Сними целу површ Name[sr@ijekavianlatin]=Snimi celu površ Name[sr@latin]=Snimi celu površ Name[sv]=Ta en bild av hela skrivbordet Name[tr]=Tam Masaüstünü Yakala Name[uk]=Захопити зображення усієї стільниці Name[x-test]=xxCapture Entire Desktopxx Name[zh_CN]=抓取整个桌面 Name[zh_TW]=擷取整個桌面 Exec=qdbus org.kde.Spectacle / FullScreen false +X-KDE-Shortcuts=Shift+Print [Desktop Action CurrentMonitorScreenShot] Name=Capture Current Monitor Name[ar]=التقط الشّاشة الحاليّة Name[ca]=Captura el monitor actual Name[ca@valencia]=Captura el monitor actual Name[cs]=Zachytit současný monitor Name[da]=Indfang den aktuelle skærm Name[de]=Den aktuellen Bildschirm aufnehmen Name[el]=Λήψη της τρέχουσας οθόνης Name[en_GB]=Capture Current Monitor Name[es]=Capturar el monitor actual Name[et]=Aktiivse monitori pildistamine Name[eu]=Atzeman uneko monitorea Name[fi]=Kaappaa nykyinen näyttö Name[fr]=Capturer le moniteur courant Name[gl]=Capturar o monitor actual Name[he]=צילום המסך הנוכחי Name[ia]=Captura mnitor currente Name[id]=Tangkap Pemantau Saat Ini Name[it]=Cattura il monitor attuale Name[ko]=현재 모니터 찍기 Name[lt]=Paveiksluoti šio monitoriaus vaizdą Name[nl]=Huidige monitor opnemen Name[nn]=Ta bilete av gjeldande skjerm Name[pl]=Przechwyć bieżący monitor Name[pt]=Capturar o Monitor Actual Name[pt_BR]=Capturar do monitor atual Name[ru]=Сделать снимок текущего экрана Name[sk]=Zachytiť aktuálny monitor Name[sl]=Zajemi trenutni zaslon Name[sr]=Сними тренутни монитор Name[sr@ijekavian]=Сними тренутни монитор Name[sr@ijekavianlatin]=Snimi trenutni monitor Name[sr@latin]=Snimi trenutni monitor Name[sv]=Ta en bild av aktuell bildskärm Name[tr]=Geçerli Ekranı Yakala Name[uk]=Захопити зображення на моніторі Name[x-test]=xxCapture Current Monitorxx Name[zh_CN]=抓取当前显示器 Name[zh_TW]=擷取目前螢幕 Exec=qdbus org.kde.Spectacle / CurrentScreen false + [Desktop Action ActiveWindowScreenShot] Name=Capture Active Window Name[ar]=التقط النّافذة النّشطة Name[ca]=Captura la finestra activa Name[ca@valencia]=Captura la finestra activa Name[cs]=Zachytit aktivní okno Name[da]=Indfang det aktive vindue Name[de]=Das aktive Fenster aufnehmen Name[el]=Λήψη του ενεργού παραθύρου Name[en_GB]=Capture Active Window Name[es]=Capturar la ventana activa Name[et]=Aktiivse akna pildistamine Name[eu]=Atzeman leiho aktiboa Name[fi]=Kaappaa aktiivinen ikkuna Name[fr]=Capturer la fenêtre active Name[gl]=Capturar a xanela activa Name[he]=צילום החלון הפעיל Name[ia]=Captura fenestra active Name[id]=Tangkap Window Aktif Name[it]=Cattura la finestra attiva Name[ko]=활성 창 찍기 Name[lt]=Paveiksluoti veikiamąjį langą Name[nl]=Actieve venster opnemen Name[nn]=Ta bilete av aktivt vindauge Name[pl]=Przechwyć aktywne okno Name[pt]=Capturar a Janela Activa Name[pt_BR]=Capturar a janela ativa Name[ru]=Сделать снимок активного окна Name[sk]=Zachytiť aktuálne okno Name[sl]=Zajemi dejavno okno Name[sr]=Сними активни прозор Name[sr@ijekavian]=Сними активни прозор Name[sr@ijekavianlatin]=Snimi aktivni prozor Name[sr@latin]=Snimi aktivni prozor Name[sv]=Ta en bild av aktivt fönster Name[tr]=Etkin Pencereyi Yakala Name[uk]=Захопити зображення активного вікна Name[x-test]=xxCapture Active Windowxx Name[zh_CN]=抓取当前活动窗口 Name[zh_TW]=擷取作用中的視窗 Exec=qdbus org.kde.Spectacle / ActiveWindow true false +X-KDE-Shortcuts=Meta+Print [Desktop Action RectangularRegionScreenShot] Name=Capture Rectangular Region Name[ar]=التقط منطقة مستطيلة Name[ca]=Captura una regió rectangular Name[ca@valencia]=Captura una regió rectangular Name[cs]=Zachytit obdélníkový výběr na obrazovce Name[da]=Indfang firkantet område Name[de]=Einen rechteckigen Bereich aufnehmen Name[el]=Λήψη ορθογώνιας περιοχής Name[en_GB]=Capture Rectangular Region Name[es]=Capturar una región rectangular Name[et]=Ristkülikukujulise ala pildistamine Name[eu]=Atzeman eskualde laukizuzena Name[fi]=Kaappaa suorakulmainen alue Name[fr]=Capturer une région rectangulaire Name[gl]=Capturar unha rexión rectangular Name[he]=צילון מלבן Name[ia]=Captura area rectangular Name[id]=Tangkap Bidang Persegi Name[it]=Cattura una regione rettangolare Name[ko]=화면의 사각형 영역 찍기 Name[lt]=Paveiksluoti stačiakampę ekrano sritį Name[nl]=Rechthoekig gebied opnemen Name[nn]=Ta bilete av skjermutsnitt Name[pl]=Przechwyć obszar prostokątny Name[pt]=Capturar uma Região Rectangular Name[pt_BR]=Capturar uma região retangular Name[ru]=Сделать снимок прямоугольной области экрана Name[sk]=Zachytiť pravouhlú oblasť Name[sl]=Zajemi pravokotno območje Name[sr]=Сними правоугаону зону Name[sr@ijekavian]=Сними правоугаону зону Name[sr@ijekavianlatin]=Snimi pravougaonu zonu Name[sr@latin]=Snimi pravougaonu zonu Name[sv]=Ta en bild av ett rektangulärt område Name[tr]=Dikdörtgen Bölge Yakala Name[uk]=Захопити прямокутну область екрана Name[x-test]=xxCapture Rectangular Regionxx Name[zh_CN]=抓取方形区域 Name[zh_TW]=擷取矩形區域 Exec=qdbus org.kde.Spectacle / RectangularRegion true +X-KDE-Shortcuts=Meta+Shift+Print diff --git a/desktop/spectacle.khotkeys b/desktop/spectacle.khotkeys deleted file mode 100644 index 7d31cff..0000000 --- a/desktop/spectacle.khotkeys +++ /dev/null @@ -1,620 +0,0 @@ -[Main] -ImportId=spectacle -Version=2 - -[Data] -DataCount=1 - -[Data_1] -Comment=Shortcuts for taking screenshots -Comment[ca]=Dreceres per a prendre captures de pantalla -Comment[ca@valencia]=Dreceres per a prendre captures de pantalla -Comment[cs]=Zkratky pro pořizování snímků obrazovky -Comment[da]=Genveje til at tage skærmbilleder -Comment[de]=Kurzbefehle für die Aufnahme von Bildschirmfotos -Comment[el]=Συντομεύσεις για τη λήψη στιγμιοτύπων οθόνης -Comment[en_GB]=Shortcuts for taking screenshots -Comment[es]=Accesos rápidos para realizar capturas de pantalla -Comment[et]=Kiirklahvid ekraanipildi tegemiseks -Comment[eu]=Pantaila-argazkiak hartzeko lasterbideak -Comment[fi]=Kuvakaappausten ottamisen pikanäppäimet -Comment[fr]=Raccourcis pour prendre des captures d'écran -Comment[gl]=Atallos para facer capturas de pantalla. -Comment[he]=קיצור דרך לצילום מסך -Comment[ia]=Vias breve per prender instantaneo de schermo -Comment[id]=Pintasan keyboard untuk mengambil screenshot -Comment[it]=Scorciatoia per acquisire schermate -Comment[ko]=화면 스크린샷 찍기 단축키 -Comment[nl]=Sneltoetsen voor het maken van schermafdrukken -Comment[nn]=Snarvegar for å ta bilete av skjermen -Comment[pl]=Skróty do zrzucania ekranu -Comment[pt]=Atalhos para tirar fotografias -Comment[pt_BR]=Atalhos para capturar imagens da tela -Comment[ru]=Комбинации клавиш для создания снимков экрана -Comment[sk]=Skratky na tvorbu snímok -Comment[sl]=Bližnjice za zajemanje zaslonskih slik -Comment[sr]=Пречице за хватање снимака екрана -Comment[sr@ijekavian]=Пречице за хватање снимака екрана -Comment[sr@ijekavianlatin]=Prečice za hvatanje snimaka ekrana -Comment[sr@latin]=Prečice za hvatanje snimaka ekrana -Comment[sv]=Genvägar för att ta skärmbilder -Comment[tr]=Ekran görüntüsü alabilmek için kısayollar -Comment[uk]=Клавіатурні скорочення для створення знімків -Comment[x-test]=xxShortcuts for taking screenshotsxx -Comment[zh_CN]=截图快捷键 -Comment[zh_TW]=螢幕快照的快捷鍵 -DataCount=4 -Enabled=true -Name=Screenshots -Name[ca]=Captures de pantalla -Name[ca@valencia]=Captures de pantalla -Name[cs]=Snímky obrazovky -Name[da]=Skærmbilleder -Name[de]=Bildschirmfotos -Name[el]=Στιγμιότυπα οθόνης -Name[en_GB]=Screenshots -Name[es]=Capturas de pantalla -Name[et]=Ekraanipildid -Name[eu]=Pantaila-argazkiak -Name[fi]=Kuvakaappaukset -Name[fr]=Captures d'écran -Name[gl]=Capturas de pantalla -Name[he]=צילומי מסך -Name[ia]=Instantaneo de schermo -Name[id]=Screenshot -Name[it]=Schermate -Name[ko]=스크린샷 -Name[nl]=Schermafdrukken -Name[nn]=Skjermbilete -Name[pl]=Zrzuty ekranu -Name[pt]=Fotografias -Name[pt_BR]=Captura de tela -Name[ru]=Снимки экрана -Name[sk]=Zachytené obrazovky -Name[sl]=Zaslonske slike -Name[sr]=Снимци екрана -Name[sr@ijekavian]=Снимци екрана -Name[sr@ijekavianlatin]=Snimci ekrana -Name[sr@latin]=Snimci ekrana -Name[sv]=Skärmbilder -Name[tr]=Ekran görüntüleri -Name[uk]=Знімки екрана -Name[x-test]=xxScreenshotsxx -Name[zh_CN]=截图 -Name[zh_TW]=螢幕快照 -SystemGroup=0 -Type=ACTION_DATA_GROUP - -[Data_1Conditions] -Comment= -ConditionsCount=0 - -[Data_1_1] -Comment=Start the screenshot tool and show the GUI -Comment[ca]=Inicia l'eina de captura de pantalla i mostra la IGU -Comment[ca@valencia]=Inicia l'eina de captura de pantalla i mostra la IGU -Comment[da]=Start skærmbilledeværktøjet og vis den grafiske brugerflade -Comment[de]=Startet das Programm und zeigt die graphische Bedienungsoberfläche an -Comment[el]=Εκκίνηση του εργαλείου στιγμιοτύπων και εμφάνιση του γραφικού περιβάλλοντος -Comment[en_GB]=Start the screenshot tool and show the GUI -Comment[es]=Iniciar la herramienta de captura de pantalla y mostrar su interfaz -Comment[et]=Ekraani pildistamise tööriista käivitamine ja graafilise kasutajaliidese näitamine -Comment[eu]=Abiarazi pantaila-argazki tresna eta erakutsi interfaze grafikoa -Comment[fi]=Käynnistä kuvankaappausohjelma ja näytä käyttöliittymä -Comment[fr]=Démarrer l'outil de capture d'écran et afficher l'interface utilisateur -Comment[gl]=Iniciar a ferramenta de captura de pantalla e mostrar a súa interface. -Comment[he]=הפעל את כלי צילום המסך והראה את הממשק הגרפי -Comment[ia]=Initia le instrumento de instantaneo de schermo e monstra le GUI -Comment[id]=Mulaikan alat screenshot dan tampilkan GUI -Comment[it]=Avvia lo strumento per le schermate e ne mostra l'interfaccia -Comment[ko]=스크린샷 도구를 시작하고 GUI 보이기 -Comment[nl]=Start het hulpmiddel voor schermafdrukken en toon de GUI -Comment[nn]=Start skjermbiletverktøyet og vis grafisk grensesnitt -Comment[pl]=Wywołaj narzędzie zrzutów ekranu i pokaż graficzny interfejs -Comment[pt]=Iniciar a ferramenta de fotografias e mostrar a interface -Comment[pt_BR]=Inicia a ferramenta gráfica para captura de telas -Comment[ru]=Запустить утилиту создания снимков экрана и показать её окно -Comment[sk]=Spustí nástroj na snímky a zobrazí GUI -Comment[sl]=Zaženi orodje za zaslonske slike in prikaži grafični uporabniški vmesnik -Comment[sr]=Покрени алатку за снимке екрана са графичким сучељем -Comment[sr@ijekavian]=Покрени алатку за снимке екрана са графичким сучељем -Comment[sr@ijekavianlatin]=Pokreni alatku za snimke ekrana sa grafičkim sučeljem -Comment[sr@latin]=Pokreni alatku za snimke ekrana sa grafičkim sučeljem -Comment[sv]=Starta skärmbildsverktyget och visa det grafiska användargränssnittet -Comment[tr]=Ekran görüntüsü aracını başlat ve arayüzü göster -Comment[uk]=Запустити інструмент створення знімків і показати графічний інтерфейс -Comment[x-test]=xxStart the screenshot tool and show the GUIxx -Comment[zh_CN]=启动截图工具并显示界面 -Comment[zh_TW]=啟動螢幕快照工具並顯示使用者介面 -Enabled=true -Name=Start Screenshot Tool -Name[ca]=Inicia l'eina de captura de pantalla -Name[ca@valencia]=Inicia l'eina de captura de pantalla -Name[cs]=Spustit nástroj na zachytávání snímků obrazovky -Name[da]=Start skærmebilledeværktøjet -Name[de]=Bildschirmfoto-Programm starten -Name[el]=Εκκίνηση του εργαλείου στιγμιοτύπων -Name[en_GB]=Start Screenshot Tool -Name[es]=Iniciar la herramienta de captura de pantalla -Name[et]=Ekraani pildistamise tööriista käivitamine -Name[eu]=Abiarazi pantaila-argazki tresna -Name[fi]=Käynnistä kuvankaappausohjelma -Name[fr]=Démarrer l'outil de capture d'écran -Name[gl]=Iniciar a ferramenta de captura de pantalla -Name[he]=הפעל את כלי צילום המסך -Name[ia]=Initia le instrumento de instantaneo de schermo -Name[id]=Mulaikan Alat Screenshot -Name[it]=Avvia lo strumento per le schermate -Name[ko]=스크린샷 도구 시작하기 -Name[nl]=Het hulpmiddel voor schermafdrukken starten -Name[nn]=Skjermbiletverktøyet -Name[pl]=Wywołaj narzędzie zrzutów ekranu -Name[pt]=Iniciar a Ferramenta de Fotografias -Name[pt_BR]=Iniciar a ferramenta de captura de tela -Name[ru]=Запустить утилиту создания снимков экрана -Name[sk]=Spustiť nástroj snímok -Name[sl]=Zaženi orodje za zaslonske slike -Name[sr]=Покрени алатку за снимке екрана -Name[sr@ijekavian]=Покрени алатку за снимке екрана -Name[sr@ijekavianlatin]=Pokreni alatku za snimke ekrana -Name[sr@latin]=Pokreni alatku za snimke ekrana -Name[sv]=Starta skärmbildsverktyg -Name[tr]=Ekran Görüntüsü Aracını Başlat -Name[uk]=Запустити інструмент створення знімків -Name[x-test]=xxStart Screenshot Toolxx -Name[zh_CN]=启动截图工具 -Name[zh_TW]=啟動螢幕快照工具 -Type=SIMPLE_ACTION_DATA - -[Data_1_1Actions] -ActionsCount=1 - -[Data_1_1Actions0] -Arguments= -Call=StartAgent -RemoteApp=org.kde.Spectacle -RemoteObj=/ -Type=DBUS - -[Data_1_1Conditions] -Comment= -ConditionsCount=0 - -[Data_1_1Triggers] -Comment=Simple_action -Comment[ca]=Acció_senzilla -Comment[ca@valencia]=Acció_senzilla -Comment[cs]=Jednoduchá činnost -Comment[da]=Simpel_handling -Comment[de]=Einfache Aktion -Comment[el]=Απλή_ενέργεια -Comment[en_GB]=Simple_action -Comment[es]=Acción_sencilla -Comment[et]=Lihtne toiming -Comment[eu]=Ekintza_erraza -Comment[fi]=Yksinkertainen_toiminto -Comment[fr]=Action simple -Comment[gl]=Acción_sinxela -Comment[ia]=Simple_action -Comment[id]=Tindakan_sederhana -Comment[it]=Azione_semplice -Comment[ko]=Simple_action -Comment[nl]=Eenvoudige_handeling -Comment[nn]=Enkel_handling -Comment[pl]=Proste_działanie -Comment[pt]=Acção Simples -Comment[pt_BR]=Ação simples -Comment[ru]=Действие -Comment[sk]=Jednoduchá akcia -Comment[sl]=Preprosto_dejanje -Comment[sr]=Једноставна радња -Comment[sr@ijekavian]=Једноставна радња -Comment[sr@ijekavianlatin]=Jednostavna radnja -Comment[sr@latin]=Jednostavna radnja -Comment[sv]=Enkel-åtgärd -Comment[tr]=Basit_eylem -Comment[uk]=Проста_дія -Comment[x-test]=xxSimple_actionxx -Comment[zh_CN]=简单动作 -Comment[zh_TW]=簡易動作 -TriggersCount=1 - -[Data_1_1Triggers0] -Key=Print -Type=SHORTCUT - -[Data_1_2] -Comment=Take a full screen (all monitors) screenshot and save it -Comment[ca]=Pren una captura de pantalla completa (tots els monitors) i la desa -Comment[ca@valencia]=Pren una captura de pantalla completa (tots els monitors) i la guarda -Comment[da]=Tag skærmbillede af hele skærmen (alle skærme) og gem det -Comment[de]=Bildschirmfoto des ganzen Bildschirms aller Monitore aufnehmen und speichern -Comment[el]=Λήψη ενός πλήρους στιγμιοτύπου οθόνης (όλες οι οθόνες) και αποθήκευσή του -Comment[en_GB]=Take a full screen (all monitors) screenshot and save it -Comment[es]=Hacer una captura de pantalla completa (de todos los monitores) y guardarla -Comment[et]=Täisekraani (kõik monitorid) pildistamine ja salvestamine -Comment[eu]=Hartu pantaila osoko (monitore guztiak) pantaila-argazkia eta gorde -Comment[fi]=Ota koko näytön (kaikkien näyttöjen) kuvakaappaus ja tallenna se -Comment[fr]=Prendre une capture d'écran en plein écran (tous les moniteurs) et l'enregistrer -Comment[gl]=Facer unha captura de pantalla completa (todos os monitores) e gardala. -Comment[ia]=Prende un instantaneo de schermo plen (omne monitors) e salveguarda lo -Comment[id]=Ambil sebuah screenshot layar penuh (semua monitor) dan menyimpannya -Comment[it]=Cattura una schermata a tutto schermo (tutti i monitor) e la salva -Comment[ko]=모든 모니터의 스크린샷을 찍고 저장하기 -Comment[nl]=Een volledige schermafdruk maken (alle monitoren) en deze opslaan -Comment[nn]=Ta eit fullskjermbilete (alle skjermar) og lagra det -Comment[pl]=Wykonaj zrzut całego ekranu (wszystkie monitory) i zapisz go -Comment[pt]=Capturar o ecrã por inteiro (todos os monitores) e gravar a imagem -Comment[pt_BR]=Captura e salva a tela inteira (todos os monitores) -Comment[ru]=Сделать снимок всех экранов и сохранить его -Comment[sk]=Vytvoriť snímku celej obrazovky (všetkých monitorov) a uložiť ju -Comment[sl]=Zajemi celozaslonsko sliko (vsi zasloni) in jo shrani -Comment[sr]=Ухвати снимак целог екрана (сви монитори) и сачувај га -Comment[sr@ijekavian]=Ухвати снимак целог екрана (сви монитори) и сачувај га -Comment[sr@ijekavianlatin]=Uhvati snimak celog ekrana (svi monitori) i sačuvaj ga -Comment[sr@latin]=Uhvati snimak celog ekrana (svi monitori) i sačuvaj ga -Comment[sv]=Ta en skärmbild av hela skärmen (alla bildskärmar) och spara den -Comment[tr]=Tam ekran ekran görüntüsü (tüm ekranlar) al ve kaydet -Comment[uk]=Зробити знімок усього екрана (усіх моніторів) і зберегти його -Comment[x-test]=xxTake a full screen (all monitors) screenshot and save itxx -Comment[zh_CN]=对全屏 (所有显示器) 截图并保存 -Comment[zh_TW]=取得全螢幕(所有螢幕)快照並儲存 -Enabled=true -Name=Take Full Screen Screenshot -Name[ca]=Pren una captura de pantalla completa -Name[ca@valencia]=Pren una captura de pantalla completa -Name[cs]=Zachytit snímek celé obrazovky -Name[da]=Tag skærmbillede af hele skærmen -Name[de]=Bildschirmfoto des ganzen Bildschirms aufnehmen -Name[el]=Λήψη πλήρους στιγμιοτύπου οθόνης -Name[en_GB]=Take Full Screen Screenshot -Name[es]=Hacer una captura de pantalla completa -Name[et]=Täisekraanipildi tegemine -Name[eu]=Hartu pantaila osoko pantaila-argazkia -Name[fi]=Ota koko näytön kuvakaappaus -Name[fr]=Prendre une capture d'écran en plein écran -Name[gl]=Capturar todas as pantallas -Name[ia]=Prende un instantaneo a schermo plen -Name[id]=Ambil Screenshot Layar Penuh -Name[it]=Cattura l'intero schermo -Name[ko]=전체 화면 스크린샷 찍기 -Name[nl]=Schermafdruk van Volledig scherm maken -Name[nn]=Ta fullskjermsbilete -Name[pl]=Wykonaj zrzut całego ekranu -Name[pt]=Tirar uma Imagem do Ecrã Inteiro -Name[pt_BR]=Capturar a tela inteira -Name[ru]=Сделать снимок всех экранов -Name[sk]=Vytvoriť snímku celej obrazovky -Name[sl]=Zajemi celozaslonsko sliko -Name[sr]=Ухвати снимак целог екрана -Name[sr@ijekavian]=Ухвати снимак целог екрана -Name[sr@ijekavianlatin]=Uhvati snimak celog ekrana -Name[sr@latin]=Uhvati snimak celog ekrana -Name[sv]=Ta en skärmbild av hela skärmen -Name[tr]=Tam Ekran Ekran Görüntüsü Al -Name[uk]=Зробити знімок усього екрана -Name[x-test]=xxTake Full Screen Screenshotxx -Name[zh_CN]=对全屏截图 -Name[zh_TW]=取得全螢幕快照 -Type=SIMPLE_ACTION_DATA - -[Data_1_2Actions] -ActionsCount=1 - -[Data_1_2Actions0] -Arguments=false -Call=FullScreen -RemoteApp=org.kde.Spectacle -RemoteObj=/ -Type=DBUS - -[Data_1_2Conditions] -Comment= -ConditionsCount=0 - -[Data_1_2Triggers] -Comment=Simple_action -Comment[ca]=Acció_senzilla -Comment[ca@valencia]=Acció_senzilla -Comment[cs]=Jednoduchá činnost -Comment[da]=Simpel_handling -Comment[de]=Einfache Aktion -Comment[el]=Απλή_ενέργεια -Comment[en_GB]=Simple_action -Comment[es]=Acción_sencilla -Comment[et]=Lihtne toiming -Comment[eu]=Ekintza_erraza -Comment[fi]=Yksinkertainen_toiminto -Comment[fr]=Action simple -Comment[gl]=Acción_sinxela -Comment[ia]=Simple_action -Comment[id]=Tindakan_sederhana -Comment[it]=Azione_semplice -Comment[ko]=Simple_action -Comment[nl]=Eenvoudige_handeling -Comment[nn]=Enkel_handling -Comment[pl]=Proste_działanie -Comment[pt]=Acção Simples -Comment[pt_BR]=Ação simples -Comment[ru]=Действие -Comment[sk]=Jednoduchá akcia -Comment[sl]=Preprosto_dejanje -Comment[sr]=Једноставна радња -Comment[sr@ijekavian]=Једноставна радња -Comment[sr@ijekavianlatin]=Jednostavna radnja -Comment[sr@latin]=Jednostavna radnja -Comment[sv]=Enkel-åtgärd -Comment[tr]=Basit_eylem -Comment[uk]=Проста_дія -Comment[x-test]=xxSimple_actionxx -Comment[zh_CN]=简单动作 -Comment[zh_TW]=簡易動作 -TriggersCount=1 - -[Data_1_2Triggers0] -Key=Shift+Print -Type=SHORTCUT - -[Data_1_3] -Comment=Take a screenshot of the currently active window and save it -Comment[ca]=Pren una captura de pantalla de la finestra activa i la desa -Comment[ca@valencia]=Pren una captura de pantalla de la finestra activa i la guarda -Comment[da]=Tag skærmbillede af det aktuelt aktive vindue og gem det -Comment[de]=Erstellt ein Bildschirmfoto des aktuell aktiven Fensters und speichert es -Comment[el]=Λήψη ενός στιγμιοτύπου του ενεργού παραθύρου και αποθήκευσή του -Comment[en_GB]=Take a screenshot of the currently active window and save it -Comment[es]=Hacer una captura de la ventana activa actualmente y guardarla -Comment[et]=Aktiivse akna pildistamine ja salvestamine -Comment[eu]=Hartu pantaila-argazki bat uneko leiho aktiboarena eta gorde -Comment[fi]=Ota kuvakaappaus aktiivisesta ikkunasta ja tallenna se -Comment[fr]=Prendre une capture d'écran de la fenêtre active et l'enregistrer -Comment[gl]=Capturar a xanela activa e gardar a captura. -Comment[ia]=Prende un instantaneo defenestra currentemente active e salveguarda lo -Comment[id]=Ambil sebuah screenshot pada window yang aktif saat ini dan menyimpannya -Comment[it]=Cattura una schermata della finestra attiva e la salva -Comment[ko]=현재 활성 창 스크린샷을 찍고 저장하기 -Comment[nl]=Een schermafdruk van het huidige actieve venster maken en het opslaan -Comment[nn]=Ta skjermbilete frå det aktive vindauget og lagra det -Comment[pl]=Wykonaj zrzut obecnie aktywnego okna i zapisz go -Comment[pt]=Capturar uma imagem da janela activa de momento e gravá-la -Comment[pt_BR]=Captura e salva a imagem da janela ativa -Comment[ru]=Сделать снимок активного окна и сохранить его -Comment[sk]=Vytvoriť snímku aktuálne aktívneho okna a uložiť ju -Comment[sl]=Zajemi zaslonsko sliko trenutno dejavnega okna in jo shrani -Comment[sr]=Ухвати снимак тренутно активног прозора и сачувај га -Comment[sr@ijekavian]=Ухвати снимак тренутно активног прозора и сачувај га -Comment[sr@ijekavianlatin]=Uhvati snimak trenutno aktivnog prozora i sačuvaj ga -Comment[sr@latin]=Uhvati snimak trenutno aktivnog prozora i sačuvaj ga -Comment[sv]=Ta en skärmbild av nuvarande aktiva fönster och spara den -Comment[tr]=Geçerli pencerenin ekran görüntüsünü al ve kaydet -Comment[uk]=Зробити знімок поточного активного вікна і зберегти його -Comment[x-test]=xxTake a screenshot of the currently active window and save itxx -Comment[zh_CN]=对当前活动窗口截图并保存 -Comment[zh_TW]=取得目前作用中視窗的快照並儲存 -Enabled=true -Name=Take Active Window Screenshot -Name[ca]=Pren una captura de pantalla de la finestra activa -Name[ca@valencia]=Pren una captura de pantalla de la finestra activa -Name[cs]=Zachytit snímek aktivního okna -Name[da]=Tag skærmbillede af det aktive vindue -Name[de]=Bildschirmfoto des aktiven Fensters -Name[el]=Λήψη στιγμιοτύπου ενεργού παραθύρου -Name[en_GB]=Take Active Window Screenshot -Name[es]=Hacer una captura de la ventana activa -Name[et]=Aktiivse akna pildistamine -Name[eu]=Hartu leiho aktiboaren pantaila-argazkia -Name[fi]=Ota kuvakaappaus aktiivisesta ikkunasta -Name[fr]=Prendre une capture d'écran de la fenêtre active -Name[gl]=Capturar a xanela activa -Name[ia]=Prende instantaneo de schermo de fenestra active -Name[id]=Ambil Screenshot Window Aktif -Name[it]=Cattura la finestra attiva -Name[ko]=활성 창 스크린샷 찍기 -Name[nl]=Schermafdruk van actieve venster maken -Name[nn]=Ta skjermbilete av aktivt vindauge -Name[pl]=Wykonaj zrzut obecnie aktywnego okna -Name[pt]=Tirar uma Fotografia da Janela Activa -Name[pt_BR]=Capturar a imagem da janela ativa -Name[ru]=Сделать снимок активного окна -Name[sk]=Zachytiť snímku aktuálneho okna -Name[sl]=Zajemi zaslonsko sliko dejavnega okna -Name[sr]=Ухвати снимак активног прозора -Name[sr@ijekavian]=Ухвати снимак активног прозора -Name[sr@ijekavianlatin]=Uhvati snimak aktivnog prozora -Name[sr@latin]=Uhvati snimak aktivnog prozora -Name[sv]=Ta en skärmbild av aktivt fönster -Name[tr]=Geçerli Pencere Ekran Görüntüsü Al -Name[uk]=Зробити знімок активного вікна -Name[x-test]=xxTake Active Window Screenshotxx -Name[zh_CN]=对活动窗口截图 -Name[zh_TW]=取得目前視窗快照 -Type=SIMPLE_ACTION_DATA - -[Data_1_3Actions] -ActionsCount=1 - -[Data_1_3Actions0] -Arguments=true false -Call=ActiveWindow -RemoteApp=org.kde.Spectacle -RemoteObj=/ -Type=DBUS - -[Data_1_3Conditions] -Comment= -ConditionsCount=0 - -[Data_1_3Triggers] -Comment=Simple_action -Comment[ca]=Acció_senzilla -Comment[ca@valencia]=Acció_senzilla -Comment[cs]=Jednoduchá činnost -Comment[da]=Simpel_handling -Comment[de]=Einfache Aktion -Comment[el]=Απλή_ενέργεια -Comment[en_GB]=Simple_action -Comment[es]=Acción_sencilla -Comment[et]=Lihtne toiming -Comment[eu]=Ekintza_erraza -Comment[fi]=Yksinkertainen_toiminto -Comment[fr]=Action simple -Comment[gl]=Acción_sinxela -Comment[ia]=Simple_action -Comment[id]=Tindakan_sederhana -Comment[it]=Azione_semplice -Comment[ko]=Simple_action -Comment[nl]=Eenvoudige_handeling -Comment[nn]=Enkel_handling -Comment[pl]=Proste_działanie -Comment[pt]=Acção Simples -Comment[pt_BR]=Ação simples -Comment[ru]=Действие -Comment[sk]=Jednoduchá akcia -Comment[sl]=Preprosto_dejanje -Comment[sr]=Једноставна радња -Comment[sr@ijekavian]=Једноставна радња -Comment[sr@ijekavianlatin]=Jednostavna radnja -Comment[sr@latin]=Jednostavna radnja -Comment[sv]=Enkel-åtgärd -Comment[tr]=Basit_eylem -Comment[uk]=Проста_дія -Comment[x-test]=xxSimple_actionxx -Comment[zh_CN]=简单动作 -Comment[zh_TW]=簡易動作 -TriggersCount=1 - -[Data_1_3Triggers0] -Key=Meta+Print -Type=SHORTCUT - -[Data_1_4] -Comment=Take a screenshot of a rectangular region you specify and save it -Comment[ca]=Pren una captura de pantalla d'una regió rectangular i la desa -Comment[ca@valencia]=Pren una captura de pantalla d'una regió rectangular i la guarda -Comment[da]=Tag skærmbillede af et firkantet område som du angiver og gem det -Comment[de]=Erstellt ein Bildschirmfoto eines rechteckigen Bereichs und speichert es -Comment[el]=Λήψη στιγμιοτύπου μιας καθορισμένης ορθογώνιας περιοχής και αποθήκευσή του -Comment[en_GB]=Take a screenshot of a rectangular region you specify and save it -Comment[es]=Hacer una captura de la región rectangular indicada y guardarla -Comment[et]=Määratava ristkülikukujulise ala pildistamine ja salvestamine -Comment[eu]=Hartu pantaila-argazki bat zuk zehatutako eskualde laukizuzenarena eta gorde -Comment[fi]=Ota kuvakaappaus annetusta suorakulmaisesta alueesta ja tallenna se -Comment[fr]=Prendre une capture d'écran d'une région rectangulaire que vous avez spécifié et l'enregistrer -Comment[gl]=Capturar unha rexión rectangular indicada e gardar a captura. -Comment[ia]=Prende un instantaneo del region rectangular que tu specificava e salveguarda lo -Comment[id]=Ambil sebuah screenshot pada bidang persegi yang Anda tetapkan dan menyimpannya -Comment[it]=Cattura una schermata di una regione rettangolare a piacere e la salva -Comment[ko]=지정한 사각형 영역의 스크린샷을 찍고 저장하기 -Comment[nl]=Een schermafdruk van een rechthoekig gebied dat u specificeert maken en het opslaan -Comment[nn]=Ta rektangulært skjermutsnitt og lagra det -Comment[pl]=Wykonaj zrzut podanego przez ciebie prostokątnego obszaru i zapisz go -Comment[pt]=Capturar uma imagem de uma região rectangular à sua escolha e gravá-la -Comment[pt_BR]=Captura e salva a imagem de uma região retangular -Comment[ru]=Сделать снимок прямоугольной области экрана и сохранить его -Comment[sk]=Vytvoriť snímku pravouhlej oblasti, ktorú určíte, a uložiť ju -Comment[sl]=Zajemi zaslonsko sliko pravokotnega območja in jo shrani -Comment[sr]=Ухвати снимак задате правоугаоне зоне и сачувај га -Comment[sr@ijekavian]=Ухвати снимак задате правоугаоне зоне и сачувај га -Comment[sr@ijekavianlatin]=Uhvati snimak zadate pravougaone zone i sačuvaj ga -Comment[sr@latin]=Uhvati snimak zadate pravougaone zone i sačuvaj ga -Comment[sv]=Ta en skärmbild av ett angivet rektangulärt område och spara den -Comment[tr]=Belirtilen diktörtgen bölgenin ekran görüntüsünü al ve kaydet -Comment[uk]=Зробити знімок вказаної прямокутної ділянки і зберегти його -Comment[x-test]=xxTake a screenshot of a rectangular region you specify and save itxx -Comment[zh_CN]=对指定矩形区域截图并保存 -Comment[zh_TW]=取得您指定的矩形區域的快照並儲存 -Enabled=true -Name=Take Rectangular Region Screenshot -Name[ca]=Pren una captura de pantalla d'una regió rectangular -Name[ca@valencia]=Pren una captura de pantalla d'una regió rectangular -Name[cs]=Zachytit snímek obdélníkové oblasti -Name[da]=Tag skærmbillede af et firkantet område -Name[de]=Bildschirmfoto eines rechteckigen Bereichs -Name[el]=Λήψη στιγμιοτύπου ορθογώνιας περιοχής -Name[en_GB]=Take Rectangular Region Screenshot -Name[es]=Hacer una captura de una región rectangular -Name[et]=Ristkülikukujulise ala pildistamine -Name[eu]=Hartu eskualde laukizuzenaren pantaila-argazkia -Name[fi]=Ota kuvakaappaus suorakulmaisesta alueesta -Name[fr]=Prendre une capture d'écran d'une région rectangulaire -Name[gl]=Capturar unha rexión rectangular -Name[ia]=Prende un instantaneo de schermo de region rectangular -Name[id]=Ambil Screenshot Bidang Persegi -Name[it]=Cattura una regione rettangolare -Name[ko]=사각형 영역 스크린샷 찍기 -Name[nl]=Schermafdruk van rechthoekig gebied maken -Name[nn]=Ta rektangulært skjermutsnitt -Name[pl]=Wykonaj zrzut prostokątnego obszaru -Name[pt]=Tirar uma Fotografia de uma Região Rectangular -Name[pt_BR]=Capturar a imagem de uma região retangular -Name[ru]=Сделать снимок прямоугольной области экрана -Name[sk]=Zachytiť snímku pravouhlej oblasti -Name[sl]=Zajemi zaslonsko sliko pravokotnega območja -Name[sr]=Ухвати снимак правоугаоне зоне -Name[sr@ijekavian]=Ухвати снимак правоугаоне зоне -Name[sr@ijekavianlatin]=Uhvati snimak pravougaone zone -Name[sr@latin]=Uhvati snimak pravougaone zone -Name[sv]=Ta en skärmbild av ett rektangulärt område -Name[tr]=Dikdörtgen Bölge Ekran Görüntüsü Al -Name[uk]=Зробити знімок прямокутної ділянки -Name[x-test]=xxTake Rectangular Region Screenshotxx -Name[zh_CN]=对矩形区域截图 -Name[zh_TW]=取得矩形區域快照 -Type=SIMPLE_ACTION_DATA - -[Data_1_4Actions] -ActionsCount=1 - -[Data_1_4Actions0] -Arguments=true -Call=RectangularRegion -RemoteApp=org.kde.Spectacle -RemoteObj=/ -Type=DBUS - -[Data_1_4Conditions] -Comment= -ConditionsCount=0 - -[Data_1_4Triggers] -Comment=Simple_action -Comment[ca]=Acció_senzilla -Comment[ca@valencia]=Acció_senzilla -Comment[cs]=Jednoduchá činnost -Comment[da]=Simpel_handling -Comment[de]=Einfache Aktion -Comment[el]=Απλή_ενέργεια -Comment[en_GB]=Simple_action -Comment[es]=Acción_sencilla -Comment[et]=Lihtne toiming -Comment[eu]=Ekintza_erraza -Comment[fi]=Yksinkertainen_toiminto -Comment[fr]=Action simple -Comment[gl]=Acción_sinxela -Comment[ia]=Simple_action -Comment[id]=Tindakan_sederhana -Comment[it]=Azione_semplice -Comment[ko]=Simple_action -Comment[nl]=Eenvoudige_handeling -Comment[nn]=Enkel_handling -Comment[pl]=Proste_działanie -Comment[pt]=Acção Simples -Comment[pt_BR]=Ação simples -Comment[ru]=Действие -Comment[sk]=Jednoduchá akcia -Comment[sl]=Preprosto_dejanje -Comment[sr]=Једноставна радња -Comment[sr@ijekavian]=Једноставна радња -Comment[sr@ijekavianlatin]=Jednostavna radnja -Comment[sr@latin]=Jednostavna radnja -Comment[sv]=Enkel-åtgärd -Comment[tr]=Basit_eylem -Comment[uk]=Проста_дія -Comment[x-test]=xxSimple_actionxx -Comment[zh_CN]=简单动作 -Comment[zh_TW]=簡易動作 -TriggersCount=1 - -[Data_1_4Triggers0] -Key=Meta+Shift+Print -Type=SHORTCUT diff --git a/desktop/spectacle_shortcuts.upd b/desktop/spectacle_shortcuts.upd new file mode 100644 index 0000000..05385df --- /dev/null +++ b/desktop/spectacle_shortcuts.upd @@ -0,0 +1,4 @@ +Version=5 +Id=spectacle-migrate-shortcuts +File=khotkeysrc +Script=spectacle-migrate-shortcuts diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6442d81..feeefaf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,110 +1,113 @@ # common - configure file and version definitions configure_file(Config.h.in ${CMAKE_CURRENT_BINARY_DIR}/Config.h) set(CMAKE_AUTORCC 1) # target if(XCB_FOUND) set( SPECTACLE_SRCS_PLATFORM_XCB Platforms/PlatformXcb.cpp ) endif() set( SPECTACLE_SRCS_PLATFORM Platforms/PlatformLoader.cpp Platforms/Platform.cpp Platforms/PlatformNull.cpp Platforms/PlatformKWinWayland.cpp ${SPECTACLE_SRCS_PLATFORM_XCB} ) set( SPECTACLE_SRCS_DEFAULT Main.cpp ExportManager.cpp SpectacleCore.cpp SpectacleConfig.cpp SpectacleDBusAdapter.cpp ${SPECTACLE_SRCS_PLATFORM} Gui/KSMainWindow.cpp Gui/KSWidget.cpp Gui/KSImageWidget.cpp Gui/ExportMenu.cpp Gui/SmartSpinBox.cpp Gui/SettingsDialog/SettingsDialog.cpp Gui/SettingsDialog/SettingsPage.cpp Gui/SettingsDialog/SaveOptionsPage.cpp Gui/SettingsDialog/GeneralOptionsPage.cpp + Gui/SettingsDialog/ShortcutsOptionsPage.cpp QuickEditor/QuickEditor.cpp ) ecm_qt_declare_logging_category(SPECTACLE_SRCS_DEFAULT HEADER spectacle_core_debug.h IDENTIFIER SPECTACLE_CORE_LOG CATEGORY_NAME org.kde.spectacle.core) ecm_qt_declare_logging_category(SPECTACLE_SRCS_DEFAULT HEADER spectacle_gui_debug.h IDENTIFIER SPECTACLE_GUI_LOG CATEGORY_NAME org.kde.spectacle.gui) if(KIPI_FOUND) set( SPECTACLE_SRCS_KIPI KipiInterface/KSGKipiInterface.cpp KipiInterface/KSGKipiInfoShared.cpp KipiInterface/KSGKipiImageCollectionShared.cpp KipiInterface/KSGKipiImageCollectionSelector.cpp ) endif() set( SPECTACLE_SRCS_ALL ${SPECTACLE_SRCS_DEFAULT} ${SPECTACLE_SRCS_KIPI} ) add_executable( spectacle ${SPECTACLE_SRCS_ALL} ) # link libraries target_link_libraries( spectacle Qt5::DBus Qt5::PrintSupport KF5::CoreAddons KF5::DBusAddons KF5::WidgetsAddons KF5::Notifications KF5::ConfigCore KF5::I18n KF5::KIOWidgets KF5::WindowSystem KF5::NewStuff + KF5::GlobalAccel + KF5::XmlGui ) if(XCB_FOUND) target_link_libraries( spectacle XCB::XFIXES XCB::IMAGE XCB::CURSOR XCB::UTIL Qt5::X11Extras ) endif() if(KIPI_FOUND) target_link_libraries ( spectacle KF5::Kipi ) endif() if(PURPOSE_FOUND) target_link_libraries ( spectacle KF5::PurposeWidgets ) endif() install(TARGETS spectacle ${INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/src/Gui/SettingsDialog/SettingsDialog.cpp b/src/Gui/SettingsDialog/SettingsDialog.cpp index 137f488..4fb9cd8 100644 --- a/src/Gui/SettingsDialog/SettingsDialog.cpp +++ b/src/Gui/SettingsDialog/SettingsDialog.cpp @@ -1,86 +1,94 @@ /* * Copyright (C) 2015 Boudhayan Gupta * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "SettingsDialog.h" #include "GeneralOptionsPage.h" #include "SaveOptionsPage.h" +#include "ShortcutsOptionsPage.h" #include +#include #include #include SettingsDialog::SettingsDialog(QWidget *parent) : KPageDialog(parent) { // set up window options and geometry setWindowTitle(i18nc("@title:window", "Configure")); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); resize(600, 550); // init all pages QMetaObject::invokeMethod(this, "initPages", Qt::QueuedConnection); } void SettingsDialog::initPages() { KPageWidgetItem *generalOptions = new KPageWidgetItem(new GeneralOptionsPage(this), i18n("General")); generalOptions->setHeader(i18n("General")); generalOptions->setIcon(QIcon::fromTheme(QStringLiteral("view-preview"))); // This is what Dolphin uses for the icon on its General page... addPage(generalOptions); mPages.insert(generalOptions); KPageWidgetItem *saveOptions = new KPageWidgetItem(new SaveOptionsPage(this), i18n("Save")); saveOptions->setHeader(i18n("Save")); saveOptions->setIcon(QIcon::fromTheme(QStringLiteral("document-save"))); addPage(saveOptions); mPages.insert(saveOptions); + KPageWidgetItem *shortcutOptions = new KPageWidgetItem(new ShortcutsOptionsPage(this), i18n("Shortcuts")); + shortcutOptions->setHeader(i18n("Shortcuts")); + shortcutOptions->setIcon(QIcon::fromTheme(QStringLiteral("preferences-desktop-keyboard"))); + addPage(shortcutOptions); + mPages.insert(shortcutOptions); + connect(this, &SettingsDialog::currentPageChanged, this, &SettingsDialog::onPageChanged); } void SettingsDialog::accept() { Q_FOREACH(auto page, mPages) { SettingsPage *pageWidget = dynamic_cast(page->widget()); if (pageWidget) { pageWidget->saveChanges(); } } done(QDialog::Accepted); } void SettingsDialog::onPageChanged(KPageWidgetItem *current, KPageWidgetItem *before) { Q_UNUSED(current); SettingsPage *pageWidget = dynamic_cast(before->widget()); if (pageWidget && (pageWidget->changesMade())) { QMessageBox::StandardButton response = QMessageBox::question(this, i18n("Apply Unsaved Changes"), i18n("You have made changes to the settings in this tab. Do you want to apply those changes?")); if (response == QMessageBox::Yes) { pageWidget->saveChanges(); } else { pageWidget->resetChanges(); } } } diff --git a/src/Gui/SettingsDialog/ShortcutsOptionsPage.cpp b/src/Gui/SettingsDialog/ShortcutsOptionsPage.cpp new file mode 100644 index 0000000..f54a2a9 --- /dev/null +++ b/src/Gui/SettingsDialog/ShortcutsOptionsPage.cpp @@ -0,0 +1,44 @@ +#include "ShortcutsOptionsPage.h" + +#include "SpectacleConfig.h" + +#include +#include + +#include +#include +#include + +ShortcutsOptionsPage::ShortcutsOptionsPage(QWidget* parent) : SettingsPage(parent) +{ + QVBoxLayout *mainLayout = new QVBoxLayout(this); + setLayout(mainLayout); + + mEditor = new KShortcutsEditor(SpectacleConfig::instance()->shortCutActions, this, KShortcutsEditor::ActionType::GlobalAction); + mainLayout->addWidget(mEditor); + connect(mEditor, &KShortcutsEditor::keyChange, this, &ShortcutsOptionsPage::markDirty); +} + +ShortcutsOptionsPage::~ShortcutsOptionsPage() +{ + mEditor->undoChanges(); +} + + +void ShortcutsOptionsPage::resetChanges() +{ + mEditor->undoChanges(); + mChangesMade = false; +} + +void ShortcutsOptionsPage::saveChanges() +{ + mEditor->commit(); + mChangesMade = false; +} + +void ShortcutsOptionsPage::markDirty() +{ + mChangesMade = true; +} + diff --git a/src/Gui/SettingsDialog/ShortcutsOptionsPage.h b/src/Gui/SettingsDialog/ShortcutsOptionsPage.h new file mode 100644 index 0000000..dbf80c3 --- /dev/null +++ b/src/Gui/SettingsDialog/ShortcutsOptionsPage.h @@ -0,0 +1,31 @@ +#ifndef SHORTCUTSOPTIONSPAGE_H +#define SHORTCUTSOPTIONSPAGE_H + +#include "SettingsPage.h" + +class KShortcutsEditor; + +class ShortcutsOptionsPage : public SettingsPage +{ + Q_OBJECT + + public: + + explicit ShortcutsOptionsPage ( QWidget* parent ); + ~ShortcutsOptionsPage(); + + public Q_SLOTS: + + void saveChanges() override; + void resetChanges() override; + + private Q_SLOTS: + + void markDirty(); + + private: + + KShortcutsEditor* mEditor; +}; + +#endif // SHORTCUTSOPTIONSPAGE_H diff --git a/src/SpectacleConfig.cpp b/src/SpectacleConfig.cpp index c3da1af..ddd86e3 100644 --- a/src/SpectacleConfig.cpp +++ b/src/SpectacleConfig.cpp @@ -1,365 +1,406 @@ /* * Copyright (C) 2015 Boudhayan Gupta * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "SpectacleConfig.h" +#include #include +#include + +#include + SpectacleConfig::SpectacleConfig(QObject *parent) : QObject(parent) { mConfig = KSharedConfig::openConfig(QStringLiteral("spectaclerc")); mGeneralConfig = KConfigGroup(mConfig, "General"); mGuiConfig = KConfigGroup(mConfig, "GuiConfig"); + + shortCutActions = new KActionCollection(this); + + //everything here is named to match the jumplist actions in our .desktop file + shortCutActions->setComponentName(QStringLiteral("org.kde.spectacle.desktop")); + //qdbus org.kde.kglobalaccel /component/org_kde_spectacle_desktop org.kde.kglobalaccel.Component.shortcutNames + // ActiveWindowScreenShot + // CurrentMonitorScreenShot + // RectangularRegionScreenShot + // FullScreenScreenShot + // _launch + { + QAction *action = new QAction(i18n("Launch Spectacle")); + action->setObjectName(QStringLiteral("_launch")); + shortCutActions->addAction(action->objectName(), action); + } + { + QAction *action = new QAction(i18n("Capture Entire Desktop")); + action->setObjectName(QStringLiteral("FullScreenScreenShot")); + shortCutActions->addAction(action->objectName(), action); + } + { + QAction *action = new QAction(i18n("Capture Current Monitor")); + action->setObjectName(QStringLiteral("CurrentMonitorScreenShot")); + shortCutActions->addAction(action->objectName(), action); + } + { + QAction *action = new QAction(i18n("Capture Active Window")); + action->setObjectName(QStringLiteral("ActiveWindowScreenShot")); + shortCutActions->addAction(action->objectName(), action); + } + { + QAction *action = new QAction(i18n("Capture Rectangular Region")); + action->setObjectName(QStringLiteral("RectangularRegionScreenShot")); + shortCutActions->addAction(action->objectName(), action); + } } SpectacleConfig::~SpectacleConfig() {} SpectacleConfig* SpectacleConfig::instance() { static SpectacleConfig instance; return &instance; } QString SpectacleConfig::defaultFilename() const { return QStringLiteral("Screenshot"); } QString SpectacleConfig::defaultTimestampTemplate() const { // includes separator at the front return QStringLiteral("_%Y%M%D_%H%m%S"); } // lastSaveAsLocation QUrl SpectacleConfig::lastSaveAsFile() const { return mGeneralConfig.readEntry(QStringLiteral("lastSaveAsFile"), this->defaultSaveLocation()); } void SpectacleConfig::setLastSaveAsFile(const QUrl &location) { mGeneralConfig.writeEntry(QStringLiteral("lastSaveAsFile"), location); mGeneralConfig.sync(); } QUrl SpectacleConfig::lastSaveAsLocation() const { return this->lastSaveAsFile().adjusted(QUrl::RemoveFilename); } // lastSaveLocation QUrl SpectacleConfig::lastSaveFile() const { return mGeneralConfig.readEntry(QStringLiteral("lastSaveFile"), this->defaultSaveLocation()); } void SpectacleConfig::setLastSaveFile(const QUrl &location) { mGeneralConfig.writeEntry(QStringLiteral("lastSaveFile"), location); mGeneralConfig.sync(); } QUrl SpectacleConfig::lastSaveLocation() const { return this->lastSaveFile().adjusted(QUrl::RemoveFilename); } // cropRegion QRect SpectacleConfig::cropRegion() const { return mGuiConfig.readEntry(QStringLiteral("cropRegion"), QRect()); } void SpectacleConfig::setCropRegion(const QRect ®ion) { mGuiConfig.writeEntry(QStringLiteral("cropRegion"), region); mGuiConfig.sync(); } // onclick bool SpectacleConfig::onClickChecked() const { return mGuiConfig.readEntry(QStringLiteral("onClickChecked"), false); } void SpectacleConfig::setOnClickChecked(bool enabled) { mGuiConfig.writeEntry(QStringLiteral("onClickChecked"), enabled); mGuiConfig.sync(); } // include pointer bool SpectacleConfig::includePointerChecked() const { return mGuiConfig.readEntry(QStringLiteral("includePointer"), true); } void SpectacleConfig::setIncludePointerChecked(bool enabled) { mGuiConfig.writeEntry(QStringLiteral("includePointer"), enabled); mGuiConfig.sync(); } // include decorations bool SpectacleConfig::includeDecorationsChecked() const { return mGuiConfig.readEntry(QStringLiteral("includeDecorations"), true); } void SpectacleConfig::setIncludeDecorationsChecked(bool enabled) { mGuiConfig.writeEntry(QStringLiteral("includeDecorations"), enabled); mGuiConfig.sync(); } // capture transient window only bool SpectacleConfig::captureTransientWindowOnlyChecked() const { return mGuiConfig.readEntry(QStringLiteral("transientOnly"), false); } void SpectacleConfig::setCaptureTransientWindowOnlyChecked(bool enabled) { mGuiConfig.writeEntry(QStringLiteral("transientOnly"), enabled); mGuiConfig.sync(); } // quit after saving, copying, or exporting the image bool SpectacleConfig::quitAfterSaveOrCopyChecked() const { return mGuiConfig.readEntry(QStringLiteral("quitAfterSaveCopyExport"), false); } void SpectacleConfig::setQuitAfterSaveOrCopyChecked(bool enabled) { mGuiConfig.writeEntry(QStringLiteral("quitAfterSaveCopyExport"), enabled); mGuiConfig.sync(); } // show magnifier bool SpectacleConfig::showMagnifierChecked() const { return mGuiConfig.readEntry(QStringLiteral("showMagnifier"), false); } void SpectacleConfig::setShowMagnifierChecked(bool enabled) { mGuiConfig.writeEntry(QStringLiteral("showMagnifier"), enabled); mGuiConfig.sync(); } // release mouse-button to capture bool SpectacleConfig::useReleaseToCapture() const { return mGuiConfig.readEntry(QStringLiteral("useReleaseToCapture"), false); } void SpectacleConfig::setUseReleaseToCaptureChecked(bool enabled) { mGuiConfig.writeEntry(QStringLiteral("useReleaseToCapture"), enabled); mGuiConfig.sync(); } // capture delay qreal SpectacleConfig::captureDelay() const { return mGuiConfig.readEntry(QStringLiteral("captureDelay"), 0.0); } void SpectacleConfig::setCaptureDelay(qreal delay) { mGuiConfig.writeEntry(QStringLiteral("captureDelay"), delay); mGuiConfig.sync(); } // capture mode int SpectacleConfig::captureMode() const { return std::max(0, mGuiConfig.readEntry(QStringLiteral("captureModeIndex"), 0)); } void SpectacleConfig::setCaptureMode(int index) { mGuiConfig.writeEntry(QStringLiteral("captureModeIndex"), index); mGuiConfig.sync(); } // remember last rectangular region bool SpectacleConfig::rememberLastRectangularRegion() const { return mGuiConfig.readEntry(QStringLiteral("rememberLastRectangularRegion"), true); } void SpectacleConfig::setRememberLastRectangularRegion(bool enabled) { mGuiConfig.writeEntry(QStringLiteral("rememberLastRectangularRegion"), enabled); mGuiConfig.sync(); } bool SpectacleConfig::alwaysRememberRegion() const { // Default Value is for compatibility reasons as the old behavior was always to remember across restarts bool useOldBehavior = mGuiConfig.readEntry(QStringLiteral("rememberLastRectangularRegion"), false); return mGuiConfig.readEntry(QStringLiteral("alwaysRememberRegion"), useOldBehavior); } void SpectacleConfig::setAlwaysRememberRegion (bool enabled) { mGuiConfig.writeEntry(QStringLiteral("alwaysRememberRegion"), enabled); mGuiConfig.sync(); } // use light region mask colour bool SpectacleConfig::useLightRegionMaskColour() const { return mGuiConfig.readEntry(QStringLiteral("useLightMaskColour"), false); } void SpectacleConfig::setUseLightRegionMaskColour(bool enabled) { mGuiConfig.writeEntry(QStringLiteral("useLightMaskColour"), enabled); mGuiConfig.sync(); } // compression quality setting int SpectacleConfig::compressionQuality() const { return mGuiConfig.readEntry(QStringLiteral("compressionQuality"), 90); } void SpectacleConfig::setCompressionQuality(int value) { mGuiConfig.writeEntry(QStringLiteral("compressionQuality"), value); mGuiConfig.sync(); } // last used save mode SaveMode SpectacleConfig::lastUsedSaveMode() const { switch (mGuiConfig.readEntry(QStringLiteral("lastUsedSaveMode"), 0)) { default: case 0: return SaveMode::SaveAs; case 1: return SaveMode::Save; } } void SpectacleConfig::setLastUsedSaveMode(SaveMode mode) { mGuiConfig.writeEntry(QStringLiteral("lastUsedSaveMode"), static_cast(mode)); mGuiConfig.sync(); } // autosave filename format QString SpectacleConfig::autoSaveFilenameFormat() const { const QString sff = mGeneralConfig.readEntry(QStringLiteral("save-filename-format"), QString(defaultFilename() + defaultTimestampTemplate())); return sff.isEmpty() ? QStringLiteral("%d") : sff; } void SpectacleConfig::setAutoSaveFilenameFormat(const QString &format) { mGeneralConfig.writeEntry(QStringLiteral("save-filename-format"), format); mGeneralConfig.sync(); } // autosave location QUrl SpectacleConfig::defaultSaveLocation() const { QString path = mGeneralConfig.readPathEntry(QStringLiteral("default-save-location"), (QStandardPaths::writableLocation(QStandardPaths::PicturesLocation))); if (! path.endsWith(QLatin1Char('/'))) { path += QLatin1Char('/'); } return QUrl::fromUserInput(path); } void SpectacleConfig::setDefaultSaveLocation(const QUrl &location) { mGeneralConfig.writePathEntry(QStringLiteral("default-save-location"), location.toString()); mGeneralConfig.sync(); } // copy file location to clipboard after saving bool SpectacleConfig::copySaveLocationToClipboard() const { return mGeneralConfig.readEntry(QStringLiteral("copySaveLocation"), false); } void SpectacleConfig::setCopySaveLocationToClipboard(bool enabled) { mGeneralConfig.writeEntry(QStringLiteral("copySaveLocation"), enabled); mGeneralConfig.sync(); } // autosave image format QString SpectacleConfig::saveImageFormat() const { return mGeneralConfig.readEntry(QStringLiteral("default-save-image-format"), QStringLiteral("png")); } void SpectacleConfig::setSaveImageFormat(const QString &saveFmt) { mGeneralConfig.writeEntry(QStringLiteral("default-save-image-format"), saveFmt); mGeneralConfig.sync(); } SpectacleConfig::PrintKeyActionRunning SpectacleConfig::printKeyActionRunning() const { mConfig->reparseConfiguration(); int newScreenshotAction = static_cast(SpectacleConfig::PrintKeyActionRunning::TakeNewScreenshot); int readValue = mGuiConfig.readEntry(QStringLiteral("printKeyActionRunning"), newScreenshotAction); if ((KWindowSystem::isPlatformWayland() || qstrcmp(qgetenv("XDG_SESSION_TYPE"), "wayland") == 0 ) && readValue == SpectacleConfig::PrintKeyActionRunning::FocusWindow) { return SpectacleConfig::PrintKeyActionRunning::TakeNewScreenshot; } return static_cast(readValue); } void SpectacleConfig::setPrintKeyActionRunning (SpectacleConfig::PrintKeyActionRunning action) { mGuiConfig.writeEntry(QStringLiteral("printKeyActionRunning"), static_cast(action)); mGuiConfig.sync(); } diff --git a/src/SpectacleConfig.h b/src/SpectacleConfig.h index b18b25d..99e1e3a 100644 --- a/src/SpectacleConfig.h +++ b/src/SpectacleConfig.h @@ -1,142 +1,146 @@ /* * Copyright (C) 2015 Boudhayan Gupta * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef SPECTACLECONFIG_H #define SPECTACLECONFIG_H +#include #include #include #include +#include #include #include enum class SaveMode { SaveAs, Save }; class SpectacleConfig : public QObject { Q_OBJECT // singleton-ize the class public: static SpectacleConfig* instance(); QString defaultFilename() const; QString defaultTimestampTemplate() const; QUrl lastSaveAsLocation() const; QUrl lastSaveLocation() const; enum PrintKeyActionRunning : int { TakeNewScreenshot = 0, StartNewInstance, FocusWindow }; + KActionCollection* shortCutActions; + private: explicit SpectacleConfig(QObject *parent = nullptr); virtual ~SpectacleConfig(); SpectacleConfig(SpectacleConfig const&) = delete; void operator= (SpectacleConfig const&) = delete; // everything else public Q_SLOTS: QUrl lastSaveAsFile() const; void setLastSaveAsFile(const QUrl &location); QUrl lastSaveFile() const; void setLastSaveFile(const QUrl &location); QRect cropRegion() const; void setCropRegion(const QRect ®ion); bool onClickChecked() const; void setOnClickChecked(bool enabled); bool includePointerChecked() const; void setIncludePointerChecked(bool enabled); bool includeDecorationsChecked() const; void setIncludeDecorationsChecked(bool enabled); bool captureTransientWindowOnlyChecked() const; void setCaptureTransientWindowOnlyChecked(bool enabled); bool quitAfterSaveOrCopyChecked() const; void setQuitAfterSaveOrCopyChecked(bool enabled); bool showMagnifierChecked() const; void setShowMagnifierChecked(bool enabled); bool useReleaseToCapture() const; void setUseReleaseToCaptureChecked(bool enabled); qreal captureDelay() const; void setCaptureDelay(qreal delay); int captureMode() const; void setCaptureMode(int index); bool rememberLastRectangularRegion() const; void setRememberLastRectangularRegion(bool enabled); bool alwaysRememberRegion() const; void setAlwaysRememberRegion(bool enabled); bool useLightRegionMaskColour() const; void setUseLightRegionMaskColour(bool enabled); int compressionQuality() const; void setCompressionQuality(int value); SaveMode lastUsedSaveMode() const; void setLastUsedSaveMode(SaveMode mode); QString autoSaveFilenameFormat() const; void setAutoSaveFilenameFormat(const QString &format); QUrl defaultSaveLocation() const; void setDefaultSaveLocation(const QUrl &location); bool copySaveLocationToClipboard() const; void setCopySaveLocationToClipboard(bool enabled); QString saveImageFormat() const; void setSaveImageFormat(const QString &saveFmt); PrintKeyActionRunning printKeyActionRunning() const; void setPrintKeyActionRunning (PrintKeyActionRunning action); private: KSharedConfigPtr mConfig; KConfigGroup mGeneralConfig; KConfigGroup mGuiConfig; }; #endif // SPECTACLECONFIG_H diff --git a/src/SpectacleCore.cpp b/src/SpectacleCore.cpp index 8a9885f..0f30443 100644 --- a/src/SpectacleCore.cpp +++ b/src/SpectacleCore.cpp @@ -1,378 +1,401 @@ /* * Copyright (C) 2015 Boudhayan Gupta * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "SpectacleCore.h" #include "spectacle_core_debug.h" #include "Config.h" +#include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include SpectacleCore::SpectacleCore(StartMode theStartMode, Spectacle::CaptureMode theCaptureMode, QString &theSaveFileName, qint64 theDelayMsec, bool theNotifyOnGrab, bool theCopyToClipboard, QObject *parent) : QObject(parent), mStartMode(theStartMode), mNotify(theNotifyOnGrab), mPlatform(loadPlatform()), mMainWindow(nullptr), mIsGuiInited(false), mCopyToClipboard(theCopyToClipboard) { auto lConfig = KSharedConfig::openConfig(QStringLiteral("spectaclerc")); KConfigGroup lGuiConfig(lConfig, "GuiConfig"); if (!(theSaveFileName.isEmpty() || theSaveFileName.isNull())) { if (QDir::isRelativePath(theSaveFileName)) { theSaveFileName = QDir::current().absoluteFilePath(theSaveFileName); } setFilename(theSaveFileName); } // essential connections connect(this, &SpectacleCore::errorMessage, this, &SpectacleCore::showErrorMessage); connect(mPlatform.get(), &Platform::newScreenshotTaken, this, &SpectacleCore::screenshotUpdated); connect(mPlatform.get(), &Platform::newScreenshotFailed, this, &SpectacleCore::screenshotFailed); auto lImmediateAvailable = mPlatform->supportedShutterModes().testFlag(Platform::ShutterMode::Immediate); auto lOnClickAvailable = mPlatform->supportedShutterModes().testFlag(Platform::ShutterMode::OnClick); if ((!lOnClickAvailable) && (theDelayMsec < 0)) { theDelayMsec = 0; } // reset last region if it should not be remembered across restarts auto lSpectacleConfig = SpectacleConfig::instance(); if(!lSpectacleConfig->alwaysRememberRegion()) { lSpectacleConfig->setCropRegion(QRect()); } // set up the export manager auto lExportManager = ExportManager::instance(); lExportManager->setCaptureMode(theCaptureMode); connect(lExportManager, &ExportManager::errorMessage, this, &SpectacleCore::showErrorMessage); connect(lExportManager, &ExportManager::imageSaved, this, &SpectacleCore::doCopyPath); connect(lExportManager, &ExportManager::forceNotify, this, &SpectacleCore::doNotify); connect(mPlatform.get(), &Platform::windowTitleChanged, lExportManager, &ExportManager::setWindowTitle); switch (theStartMode) { case StartMode::DBus: break; case StartMode::Background: { auto lMsec = (KWindowSystem::compositingActive() ? 200 : 50) + theDelayMsec; auto lShutterMode = lImmediateAvailable ? Platform::ShutterMode::Immediate : Platform::ShutterMode::OnClick; auto lIncludePointer = lGuiConfig.readEntry("includePointer", true); auto lIncludeDecorations = lGuiConfig.readEntry("includeDecorations", true); const Platform::GrabMode lCaptureMode = toPlatformGrabMode(theCaptureMode); QTimer::singleShot(lMsec, [ this, lCaptureMode, lShutterMode, lIncludePointer, lIncludeDecorations ]() { mPlatform->doGrab(lShutterMode, lCaptureMode, lIncludePointer, lIncludeDecorations); }); } break; case StartMode::Gui: initGui(lGuiConfig.readEntry("includePointer", true), lGuiConfig.readEntry("includeDecorations", true)); break; } + setUpShortcuts(); +} + +void SpectacleCore::setUpShortcuts() +{ + SpectacleConfig* config = SpectacleConfig::instance(); + + QAction* openAction = config->shortCutActions->action(QStringLiteral("_launch")); + KGlobalAccel::self()->setGlobalShortcut(openAction, Qt::Key_Print); + + QAction* fullScreenAction = config->shortCutActions->action(QStringLiteral("FullScreenScreenShot")); + KGlobalAccel::self()->setGlobalShortcut(fullScreenAction, Qt::SHIFT + Qt::Key_Print); + + QAction* activeWindowAction = config->shortCutActions->action(QStringLiteral("ActiveWindowScreenShot")); + KGlobalAccel::self()->setGlobalShortcut(activeWindowAction, Qt::META + Qt::Key_Print); + + QAction* regionAction = config->shortCutActions->action(QStringLiteral("RectangularRegionScreenShot")); + KGlobalAccel::self()->setGlobalShortcut(regionAction, Qt::META + Qt::SHIFT + Qt::Key_Print); } QString SpectacleCore::filename() const { return mFileNameString; } void SpectacleCore::setFilename(const QString &filename) { mFileNameString = filename; mFileNameUrl = QUrl::fromUserInput(filename); } // Slots void SpectacleCore::dbusStartAgent() { qApp->setQuitOnLastWindowClosed(true); auto lConfig = KSharedConfig::openConfig(QStringLiteral("spectaclerc")); KConfigGroup lGuiConfig(lConfig, "GuiConfig"); auto lIncludePointer = lGuiConfig.readEntry("includePointer", true); auto lIncludeDecorations = lGuiConfig.readEntry("includeDecorations", true); if (!(mStartMode == StartMode::Gui)) { mStartMode = StartMode::Gui; initGui(lIncludePointer, lIncludeDecorations); } else { using Actions = SpectacleConfig::PrintKeyActionRunning; switch (SpectacleConfig::instance()->printKeyActionRunning()) { case Actions::TakeNewScreenshot: { auto lShutterMode = mPlatform->supportedShutterModes().testFlag(Platform::ShutterMode::Immediate) ? Platform::ShutterMode::Immediate : Platform::ShutterMode::OnClick; auto lGrabMode = toPlatformGrabMode(ExportManager::instance()->captureMode()); QTimer::singleShot(KWindowSystem::compositingActive() ? 200 : 50, [this, lShutterMode, lGrabMode, lIncludePointer, lIncludeDecorations]() { mPlatform->doGrab(lShutterMode, lGrabMode, lIncludePointer, lIncludeDecorations); }); break; } case Actions::FocusWindow: - KWindowSystem::forceActiveWindow(mMainWindow->winId()); + if (mMainWindow->isMinimized()) { + mMainWindow->setWindowState(mMainWindow->windowState() & ~Qt::WindowMinimized); + } + mMainWindow->activateWindow(); break; case Actions::StartNewInstance: QProcess newInstance; newInstance.setProgram(QStringLiteral("spectacle")); newInstance.startDetached(); break; } } } void SpectacleCore::takeNewScreenshot(Spectacle::CaptureMode theCaptureMode, int theTimeout, bool theIncludePointer, bool theIncludeDecorations) { ExportManager::instance()->setCaptureMode(theCaptureMode); auto lGrabMode = toPlatformGrabMode(theCaptureMode); if (theTimeout < 0) { mPlatform->doGrab(Platform::ShutterMode::OnClick, lGrabMode, theIncludePointer, theIncludeDecorations); return; } // when compositing is enabled, we need to give it enough time for the window // to disappear and all the effects are complete before we take the shot. there's // no way of knowing how long the disappearing effects take, but as per default // settings (and unless the user has set an extremely slow effect), 200 // milliseconds is a good amount of wait time. auto lMsec = KWindowSystem::compositingActive() ? 200 : 50; QTimer::singleShot(theTimeout + lMsec, [this, lGrabMode, theIncludePointer, theIncludeDecorations]() { mPlatform->doGrab(Platform::ShutterMode::Immediate, lGrabMode, theIncludePointer, theIncludeDecorations); }); } void SpectacleCore::showErrorMessage(const QString &theErrString) { qCDebug(SPECTACLE_CORE_LOG) << "ERROR: " << theErrString; if (mStartMode == StartMode::Gui) { KMessageBox::error(nullptr, theErrString); } } void SpectacleCore::screenshotUpdated(const QPixmap &thePixmap) { auto lExportManager = ExportManager::instance(); // if we were running in rectangular crop mode, now would be // the time to further process the image if (lExportManager->captureMode() == Spectacle::CaptureMode::RectangularRegion) { if(!mQuickEditor) { mQuickEditor = std::make_unique(thePixmap); connect(mQuickEditor.get(), &QuickEditor::grabDone, this, &SpectacleCore::screenshotUpdated); connect(mQuickEditor.get(), &QuickEditor::grabCancelled, this, &SpectacleCore::screenshotFailed); mQuickEditor->showFullScreen(); return; } else { mQuickEditor->hide(); mQuickEditor.reset(nullptr); } } lExportManager->setPixmap(thePixmap); lExportManager->updatePixmapTimestamp(); switch (mStartMode) { case StartMode::Background: case StartMode::DBus: { if (mNotify) { connect(lExportManager, &ExportManager::imageSaved, this, &SpectacleCore::doNotify); } if (mCopyToClipboard) { lExportManager->doCopyToClipboard(mNotify); } else { QUrl lSavePath = (mStartMode == StartMode::Background && mFileNameUrl.isValid() && mFileNameUrl.isLocalFile()) ? mFileNameUrl : QUrl(); lExportManager->doSave(lSavePath); } // if we notify, we emit allDone only if the user either dismissed the notification or pressed // the "Open" button, otherwise the app closes before it can react to it. if (!mNotify) { emit allDone(); } } break; case StartMode::Gui: mMainWindow->setScreenshotAndShow(thePixmap); } } void SpectacleCore::screenshotFailed() { if (ExportManager::instance()->captureMode() == Spectacle::CaptureMode::RectangularRegion && mQuickEditor) { mQuickEditor->hide(); mQuickEditor.reset(nullptr); } switch (mStartMode) { case StartMode::Background: showErrorMessage(i18n("Screenshot capture canceled or failed")); emit allDone(); return; case StartMode::DBus: emit grabFailed(); emit allDone(); return; case StartMode::Gui: mMainWindow->show(); } } void SpectacleCore::doNotify(const QUrl &theSavedAt) { KNotification *lNotify = new KNotification(QStringLiteral("newScreenshotSaved")); switch(ExportManager::instance()->captureMode()) { case Spectacle::CaptureMode::AllScreens: lNotify->setTitle(i18nc("The entire screen area was captured, heading", "Full Screen Captured")); break; case Spectacle::CaptureMode::CurrentScreen: lNotify->setTitle(i18nc("The current screen was captured, heading", "Current Screen Captured")); break; case Spectacle::CaptureMode::ActiveWindow: lNotify->setTitle(i18nc("The active window was captured, heading", "Active Window Captured")); break; case Spectacle::CaptureMode::WindowUnderCursor: case Spectacle::CaptureMode::TransientWithParent: lNotify->setTitle(i18nc("The window under the mouse was captured, heading", "Window Under Cursor Captured")); break; case Spectacle::CaptureMode::RectangularRegion: lNotify->setTitle(i18nc("A rectangular region was captured, heading", "Rectangular Region Captured")); break; case Spectacle::CaptureMode::InvalidChoice: break; } // a speaking message is prettier than a URL, special case for copy to clipboard and the default pictures location const QString &lSavePath = theSavedAt.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).path(); if (mCopyToClipboard) { lNotify->setText(i18n("A screenshot was saved to your clipboard.")); } else if (lSavePath == QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)) { lNotify->setText(i18nc("Placeholder is filename", "A screenshot was saved as '%1' to your Pictures folder.", theSavedAt.fileName())); } else { lNotify->setText(i18n("A screenshot was saved as '%1' to '%2'.", theSavedAt.fileName(), lSavePath)); } if (!mCopyToClipboard) { lNotify->setUrls({theSavedAt}); lNotify->setDefaultAction(i18nc("Open the screenshot we just saved", "Open")); connect(lNotify, QOverload::of(&KNotification::activated), this, [this, theSavedAt](uint index) { if (index == 0) { new KRun(theSavedAt, nullptr); QTimer::singleShot(250, this, &SpectacleCore::allDone); } }); } connect(lNotify, &QObject::destroyed, this, &SpectacleCore::allDone); lNotify->sendEvent(); } void SpectacleCore::doCopyPath(const QUrl &savedAt) { if (SpectacleConfig::instance()->copySaveLocationToClipboard()) { qApp->clipboard()->setText(savedAt.toLocalFile()); } } void SpectacleCore::doStartDragAndDrop() { auto lExportManager = ExportManager::instance(); QUrl lTempFile = lExportManager->tempSave(); if (!lTempFile.isValid()) { return; } auto lMimeData = new QMimeData; lMimeData->setUrls(QList { lTempFile }); lMimeData->setData(QStringLiteral("application/x-kde-suggestedfilename"), QFile::encodeName(lTempFile.fileName())); auto lDragHandler = new QDrag(this); lDragHandler->setMimeData(lMimeData); lDragHandler->setPixmap(lExportManager->pixmap().scaled(256, 256, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation)); lDragHandler->exec(Qt::CopyAction); } // Private Platform::GrabMode SpectacleCore::toPlatformGrabMode(Spectacle::CaptureMode theCaptureMode) { switch(theCaptureMode) { case Spectacle::CaptureMode::InvalidChoice: return Platform::GrabMode::InvalidChoice; case Spectacle::CaptureMode::AllScreens: case Spectacle::CaptureMode::RectangularRegion: return Platform::GrabMode::AllScreens; case Spectacle::CaptureMode::TransientWithParent: return Platform::GrabMode::TransientWithParent; case Spectacle::CaptureMode::CurrentScreen: return Platform::GrabMode::CurrentScreen; case Spectacle::CaptureMode::ActiveWindow: return Platform::GrabMode::ActiveWindow; case Spectacle::CaptureMode::WindowUnderCursor: return Platform::GrabMode::WindowUnderCursor; } return Platform::GrabMode::InvalidChoice; } void SpectacleCore::initGui(bool theIncludePointer, bool theIncludeDecorations) { if (!mIsGuiInited) { mMainWindow = std::make_unique(mPlatform->supportedGrabModes(), mPlatform->supportedShutterModes()); connect(mMainWindow.get(), &KSMainWindow::newScreenshotRequest, this, &SpectacleCore::takeNewScreenshot); connect(mMainWindow.get(), &KSMainWindow::dragAndDropRequest, this, &SpectacleCore::doStartDragAndDrop); mIsGuiInited = true; auto lShutterMode = mPlatform->supportedShutterModes().testFlag(Platform::ShutterMode::Immediate) ? Platform::ShutterMode::Immediate : Platform::ShutterMode::OnClick; auto lGrabMode = toPlatformGrabMode(ExportManager::instance()->captureMode()); QTimer::singleShot(0, [this, lShutterMode, lGrabMode, theIncludePointer, theIncludeDecorations]() { mPlatform->doGrab(lShutterMode, lGrabMode, theIncludePointer, theIncludeDecorations); }); } } diff --git a/src/SpectacleCore.h b/src/SpectacleCore.h index b1b8b8e..d85b014 100644 --- a/src/SpectacleCore.h +++ b/src/SpectacleCore.h @@ -1,92 +1,94 @@ /* This file is part of Spectacle, the KDE screenshot utility * Copyright (C) 2019 Boudhayan Gupta * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * SPDX-License-Identifier: LGPL-2.0-or-later */ #pragma once #include #include "ExportManager.h" #include "Gui/KSMainWindow.h" #include "QuickEditor/QuickEditor.h" #include "Platforms/PlatformLoader.h" #include using MainWindowPtr = std::unique_ptr; using EditorPtr = std::unique_ptr; class SpectacleCore: public QObject { Q_OBJECT public: enum class StartMode { Gui = 0, DBus = 1, Background = 2 }; explicit SpectacleCore(StartMode theStartMode, Spectacle::CaptureMode theCaptureMode, QString &theSaveFileName, qint64 theDelayMsec, bool theNotifyOnGrab, bool theCopyToClipboard, QObject *parent = nullptr); virtual ~SpectacleCore() = default; QString filename() const; void setFilename(const QString &filename); Q_SIGNALS: void errorMessage(const QString &errString); void allDone(); void filenameChanged(const QString &filename); void grabFailed(); public Q_SLOTS: void takeNewScreenshot(Spectacle::CaptureMode theCaptureMode, int theTimeout, bool theIncludePointer, bool theIncludeDecorations); void showErrorMessage(const QString &theErrString); void screenshotUpdated(const QPixmap &thePixmap); void screenshotFailed(); void dbusStartAgent(); void doStartDragAndDrop(); void doNotify(const QUrl &theSavedAt); void doCopyPath(const QUrl &savedAt); private: + void initGui(bool theIncludePointer, bool theIncludeDecorations); Platform::GrabMode toPlatformGrabMode(Spectacle::CaptureMode theCaptureMode); + void setUpShortcuts(); StartMode mStartMode; bool mNotify; QString mFileNameString; QUrl mFileNameUrl; PlatformPtr mPlatform; MainWindowPtr mMainWindow; EditorPtr mQuickEditor; bool mIsGuiInited; bool mCopyToClipboard; }; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7f75ce3..d85daae 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,9 +1,9 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../src) include_directories(${CMAKE_CURRENT_BINARY_DIR}) ecm_add_test(FilenameTest.cpp ../src/ExportManager.cpp ../src/SpectacleConfig.cpp ../src/Platforms/Platform.cpp TEST_NAME "filename_test" LINK_LIBRARIES Qt5::Test - Qt5::PrintSupport KF5::I18n KF5::ConfigCore KF5::KIOCore KF5::WindowSystem + Qt5::PrintSupport KF5::I18n KF5::ConfigCore KF5::GlobalAccel KF5::KIOCore KF5::WindowSystem KF5::XmlGui )