diff --git a/CMakeLists.txt b/CMakeLists.txt index 837e39df..35146f3f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -588,6 +588,11 @@ message("") message(" musrview (ROOT7 web graphics):") if (MUSRVIEW_HAS_QT6WEB) message(" embedded window (ROOT qt6web) : yes") + if (MUSRVIEW_HAS_QT_APP_ICON) + message(" application icon (Qt6Widgets) : yes") + else () + message(" application icon (Qt6Widgets) : no, Qt6Widgets not found") + endif () else () message(" embedded window (ROOT qt6web) : no, will use the standard browser") endif () diff --git a/cmake/CPackOptions.cmake.in b/cmake/CPackOptions.cmake.in index 63ae75bb..e76f9f78 100644 --- a/cmake/CPackOptions.cmake.in +++ b/cmake/CPackOptions.cmake.in @@ -17,7 +17,7 @@ set (CPACK_RESOURCE_FILE_LICENSE "@PROJECT_SOURCE_DIR@/COPYING") set (CPACK_RESOURCE_FILE_README "@PROJECT_SOURCE_DIR@/README.md") set (CPACK_RESOURCE_FILE_WELCOME "@PROJECT_SOURCE_DIR@/cmake/welcome.txt") -set (CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "@CMAKE_INSTALL_PREFIX@;@CMAKE_INSTALL_PREFIX@/bin;@CMAKE_INSTALL_PREFIX@/include;@CMAKE_INSTALL_PREFIX@/share;@CMAKE_INSTALL_PREFIX@/lib64;@CMAKE_INSTALL_PREFIX@/lib;@CMAKE_INSTALL_PREFIX@/pkgconfig;@CMAKE_INSTALL_PREFIX@/share/applications;@CMAKE_INSTALL_PREFIX@/share/icons;@CMAKE_INSTALL_PREFIX@/share/icons/hicolor;@CMAKE_INSTALL_PREFIX@/share/icons/hicolor/48x48;@CMAKE_INSTALL_PREFIX@/share/icons/hicolor/48x48/apps") +set (CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "@CMAKE_INSTALL_PREFIX@;@CMAKE_INSTALL_PREFIX@/bin;@CMAKE_INSTALL_PREFIX@/include;@CMAKE_INSTALL_PREFIX@/share;@CMAKE_INSTALL_PREFIX@/lib64;@CMAKE_INSTALL_PREFIX@/lib;@CMAKE_INSTALL_PREFIX@/pkgconfig;@CMAKE_INSTALL_PREFIX@/share/applications;@CMAKE_INSTALL_PREFIX@/share/icons;@CMAKE_INSTALL_PREFIX@/share/icons/hicolor;@CMAKE_INSTALL_PREFIX@/share/icons/hicolor/48x48;@CMAKE_INSTALL_PREFIX@/share/icons/hicolor/48x48/apps;@CMAKE_INSTALL_PREFIX@/share/icons/hicolor/512x512;@CMAKE_INSTALL_PREFIX@/share/icons/hicolor/512x512/apps;@CMAKE_INSTALL_PREFIX@/share/icons/hicolor/scalable;@CMAKE_INSTALL_PREFIX@/share/icons/hicolor/scalable/apps") # we do not have any absolute paths, so do not need DESTDIR set (CPACK_SET_DESTDIR "OFF") diff --git a/cmake/musrfit-root6.spec.in b/cmake/musrfit-root6.spec.in index 85657332..a45888b6 100644 --- a/cmake/musrfit-root6.spec.in +++ b/cmake/musrfit-root6.spec.in @@ -93,6 +93,10 @@ rm -rf $RPM_BUILD_ROOT %doc %_prefix/share/doc/musrfit %{_datadir}/applications/musredit.desktop %{_datadir}/icons/hicolor/48x48/apps/musredit.png +%{_datadir}/applications/musrview.desktop +%{_datadir}/icons/hicolor/512x512/apps/musrview.png +%{_datadir}/icons/hicolor/scalable/apps/musrview.svg +%_prefix/share/musrfit diff --git a/cmake/musrview.desktop b/cmake/musrview.desktop new file mode 100644 index 00000000..7951308c --- /dev/null +++ b/cmake/musrview.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Name=musrview +Comment=viewer for musrfit data and fit results +GenericName=musrfit viewer +Exec=musrview %f +Icon=musrview +Terminal=false +Type=Application +NoDisplay=true +StartupWMClass=musrview +Categories=Science;DataVisualization; +Keywords=muSR;fitting;musrfit;physics;muon; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 58c7058a..8af496df 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -141,10 +141,61 @@ target_link_libraries(musrview FFTW3::FFTW3 ${ROOT_LIBRARIES} ROOT::ROOTWebDispl #--- MUSRVIEW_WEB_DIR (see src/classes/CMakeLists.txt) points here. During #--- development the environment variable MUSRFIT_WEB_DIR overrides it. ------- install( - FILES ${CMAKE_SOURCE_DIR}/src/musrview_web/musrview.html + FILES + ${CMAKE_SOURCE_DIR}/src/musrview_web/musrview.html + ${CMAKE_SOURCE_DIR}/src/musrview_web/musrview.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/musrfit/musrview ) +#--- application icon of the embedded window: ROOT creates the QApplication, +#--- musrview only sets its icon, hence it has to use the very same Qt6 ROOT's +#--- qt6web display links against. Without it macOS shows the generic 'exec'. +if (MUSRVIEW_HAS_QT6WEB) + find_package(Qt6 COMPONENTS Widgets QUIET) + if (TARGET Qt6::Widgets) + # QT_NO_KEYWORDS: Qt's emit/signals/slots macros break ROOT's TGButton.h (PMsgBox) + target_compile_definitions(musrview PRIVATE MUSRVIEW_QT_APP_ICON QT_NO_KEYWORDS) + target_link_libraries(musrview Qt6::Widgets) + set(MUSRVIEW_HAS_QT_APP_ICON TRUE CACHE INTERNAL "musrview sets the icon of its embedded window") + else () + set(MUSRVIEW_HAS_QT_APP_ICON FALSE CACHE INTERNAL "musrview sets the icon of its embedded window") + endif () +endif () + +#--- macOS: musrview is a plain executable, not an application bundle. An +#--- Info.plist embedded into the binary nevertheless gives it a proper name +#--- (Dock, app menu) and bundle identifier. ---------------------------------- +if (APPLE) + configure_file( + ${CMAKE_SOURCE_DIR}/src/musrview_web/musrview-Info.plist.in + ${CMAKE_CURRENT_BINARY_DIR}/musrview-Info.plist + @ONLY + ) + target_link_options(musrview PRIVATE + "LINKER:-sectcreate,__TEXT,__info_plist,${CMAKE_CURRENT_BINARY_DIR}/musrview-Info.plist") + set_property(TARGET musrview APPEND PROPERTY + LINK_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/musrview-Info.plist) +endif () + +#--- Linux: on Wayland the compositor ignores the icon a window sets and takes +#--- it from the .desktop file matching the app-id instead (musrview.cpp sets +#--- it via setDesktopFileName). NoDisplay keeps it out of the launchers, since +#--- musrview needs an msr-file to start with. -------------------------------- +if (UNIX AND NOT APPLE) + install( + FILES ${CMAKE_SOURCE_DIR}/cmake/musrview.desktop + DESTINATION ${CMAKE_INSTALL_DATADIR}/applications + ) + install( + FILES ${CMAKE_SOURCE_DIR}/src/musrview_web/musrview.png + DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/512x512/apps + ) + install( + FILES ${CMAKE_SOURCE_DIR}/src/musrview_web/musrview.svg + DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps + ) +endif () + add_executable(write_musrRoot_runHeader write_musrRoot_runHeader.cpp) target_compile_options(write_musrRoot_runHeader BEFORE PRIVATE "-DHAVE_CONFIG_H" "${HAVE_GIT_REV_H}") target_include_directories(write_musrRoot_runHeader diff --git a/src/classes/PMusrWebCanvas.cpp b/src/classes/PMusrWebCanvas.cpp index c8ceb078..2a9f04f0 100644 --- a/src/classes/PMusrWebCanvas.cpp +++ b/src/classes/PMusrWebCanvas.cpp @@ -1097,6 +1097,20 @@ void PMusrWebCanvas::ProcessMessage(unsigned connid, const std::string &msg) } } +//-------------------------------------------------------------------------- +// WebDir (public, static) +//-------------------------------------------------------------------------- +/** + *

Locates the directory holding the musrview web assets, i.e. the page + * and the application icon, see WebDirCandidates() for the search order. + * + * \return the directory, or an empty string if none was found + */ +std::string PMusrWebCanvas::WebDir() +{ + return FindWebDir(); +} + //-------------------------------------------------------------------------- // Show (public) //-------------------------------------------------------------------------- diff --git a/src/include/PMusrWebCanvas.h b/src/include/PMusrWebCanvas.h index 8f94b76e..23403a77 100644 --- a/src/include/PMusrWebCanvas.h +++ b/src/include/PMusrWebCanvas.h @@ -113,6 +113,9 @@ class PMusrWebCanvas /// Opens the window. \p where is "" (standard browser), "qt6", "chrome", ... Bool_t Show(const std::string &where); + /// Directory holding the musrview web assets (page, application icon), + /// empty if none was found. + static std::string WebDir(); /// True once the user has closed the window. Bool_t IsDone() const { return fDone; } /// Closes the window and drops the connection. Needed so that musrview can diff --git a/src/musrview.cpp b/src/musrview.cpp index 82261155..a64a35c8 100644 --- a/src/musrview.cpp +++ b/src/musrview.cpp @@ -49,6 +49,11 @@ #include +#ifdef MUSRVIEW_QT_APP_ICON +#include +#include +#endif + #ifdef HAVE_GIT_REV_H #include "git-revision.h" #endif @@ -151,6 +156,41 @@ std::string musrview_select_display(const std::string &requested) return std::string(); } +//-------------------------------------------------------------------------- +/** + *

Gives the embedded window a proper application name and icon. + * + *

The QApplication behind the embedded display is created by ROOT the + * moment the first window is shown, and nobody sets an icon on it. Since + * musrview is a plain executable rather than an application bundle, macOS + * then shows the generic 'exec' icon in the Dock and the window switcher. + * QApplication::setWindowIcon() replaces the Dock icon as well. Hence this + * has to be called after the first PMusrWebCanvas::Show("qt6"). + * + *

On X11 the window icon is all it takes. Wayland compositors ignore it and + * take the icon from the .desktop file matching the app-id instead, which is + * what setDesktopFileName() provides (cmake/musrview.desktop). + */ +void musrview_set_app_icon() +{ +#ifdef MUSRVIEW_QT_APP_ICON + if (QApplication::instance() == nullptr) + return; + + QApplication::setApplicationName("musrview"); + QApplication::setApplicationDisplayName("musrview"); + QApplication::setDesktopFileName("musrview"); + + const std::string webDir = musrview::PMusrWebCanvas::WebDir(); + if (webDir.empty()) + return; + + const QIcon icon(QString::fromStdString(webDir + "/musrview.png")); + if (!icon.isNull()) + QApplication::setWindowIcon(icon); +#endif +} + //-------------------------------------------------------------------------- /** *

The musrview program is used to show muSR fit results in graphical form. @@ -486,6 +526,9 @@ int main(int argc, char *argv[]) } } + if (ok && (where == "qt6")) + musrview_set_app_icon(); + if (ok) { // run until every window has been closed, or until the timeout expired const auto start = std::chrono::steady_clock::now(); diff --git a/src/musrview_web/musrview-Info.plist.in b/src/musrview_web/musrview-Info.plist.in new file mode 100644 index 00000000..b1ed9d89 --- /dev/null +++ b/src/musrview_web/musrview-Info.plist.in @@ -0,0 +1,27 @@ + + + + + + CFBundleName + musrview + CFBundleDisplayName + musrview + CFBundleExecutable + musrview + CFBundleIdentifier + ch.psi.lmu.musrview + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleShortVersionString + @PROJECT_VERSION@ + CFBundleVersion + @PROJECT_VERSION@ + NSHumanReadableCopyright + Andreas Suter + NSHighResolutionCapable + + + diff --git a/src/musrview_web/musrview.png b/src/musrview_web/musrview.png new file mode 100644 index 00000000..d35f5420 Binary files /dev/null and b/src/musrview_web/musrview.png differ diff --git a/src/musrview_web/musrview.svg b/src/musrview_web/musrview.svg new file mode 100644 index 00000000..71688605 --- /dev/null +++ b/src/musrview_web/musrview.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + VIEW +