diff options
| author | handsome_feng <445865575@qq.com> | 2016-02-16 15:34:40 +0800 |
|---|---|---|
| committer | handsome_feng <445865575@qq.com> | 2016-02-16 15:34:40 +0800 |
| commit | 6c196ee11bef2824087a30bd5e17404d4e8f5e6b (patch) | |
| tree | a42464f28ccc2505fa1626e2019ac4ca8c69c3e4 | |
| parent | a8c2ece5c22827045a35ef52f5df83a3a5d1bfd2 (diff) | |
| parent | 825b78974ef8ad629f5dc0c55b586700ec610d3c (diff) | |
merge trunk
(bzr r4067.4.6)
107 files changed, 3384 insertions, 1476 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index d8da80363..c74a35f24 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 2.8.9) include (cmake/Documentation.cmake) include (cmake/pch.cmake) +include (GNUInstallDirs) # # Base bits @@ -38,6 +39,12 @@ option( ON ) +option( + ENABLE_NETWORKAREAREGION_PLUGIN + "Enable Unity Network Area region Plugin" + OFF +) + if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64" OR ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv7l" OR ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64") set (PIC_FLAGS "-fPIC") endif() @@ -74,7 +81,7 @@ if (CMAKE_BUILD_TYPE MATCHES coverage) message(FATAL_ERROR "Cannot enable coverage targets because gcovr was not found.") else () message (STATUS "Enabling XML coverage report") - add_custom_target (coverage-xml + add_custom_target (coverage-xml COMMAND "${GCOVR_EXECUTABLE}" --exclude="tests.*" --exclude="obj-.*" -x -r "${CMAKE_SOURCE_DIR}" -o "${COVERAGE_XML_FILE}") endif() @@ -87,7 +94,7 @@ if (CMAKE_BUILD_TYPE MATCHES coverage) # message(FATAL_ERROR "Cannot enable coverage targets because genhtml was not found.") # else () # message (STATUS "Enabling HTML coverage report") -# add_custom_target (coverage-html +# add_custom_target (coverage-html # COMMAND "${LCOV_EXECUTABLE}" --directory "${CMAKE_BINARY_DIR}" --capture --output-file "${COVERAGE_INFO_FILE}" # COMMAND "${GENHTML_EXECUTABLE}" --output-directory "${COVERAGE_HTML_DIR}" "${COVERAGE_INFO_FILE}") # endif() @@ -149,15 +156,16 @@ add_dependencies (release distcheck) # # config.h # -set (PREFIXDIR "${CMAKE_INSTALL_PREFIX}") -set (DATADIR "${CMAKE_INSTALL_PREFIX}/share") -set (PKGDATADIR "${DATADIR}/unity/icons") -set (SOURCEDATADIR "${CMAKE_CURRENT_SOURCE_DIR}/resources") -set (GETTEXT_PACKAGE "unity") -set (LOCALE_DIR "${DATADIR}/locale") set (VERSION "${UNITY_VERSION}") +set (PREFIXPATH "${CMAKE_INSTALL_PREFIX}") +set (UNITYLIBDIR "${CMAKE_INSTALL_FULL_LIBDIR}/${PROJECT_NAME}") +set (UNITYDATADIR "${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT_NAME}") +set (PKGDATADIR "${UNITYDATADIR}/icons") +set (SOURCEDATADIR "${CMAKE_CURRENT_SOURCE_DIR}/resources") set (BUILDDIR "${CMAKE_BINARY_DIR}") set (TESTDATADIR "${CMAKE_CURRENT_SOURCE_DIR}/tests/data") +set (LOCALE_DIR "${CMAKE_INSTALL_FULL_LOCALEDIR}") +set (GETTEXT_PACKAGE "${PROJECT_NAME}") find_package (PkgConfig) execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} gtk+-3.0 --variable prefix OUTPUT_VARIABLE GTK_PREFIX OUTPUT_STRIP_TRAILING_WHITESPACE) @@ -165,7 +173,7 @@ execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} unity --variable lensesdir OUT execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} indicator3-0.4 --variable indicatordir OUTPUT_VARIABLE INDICATORDIR OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} indicator3-0.4 --variable iconsdir OUTPUT_VARIABLE INDICATORICONDIR OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} indicator3-0.4 --variable prefix OUTPUT_VARIABLE INDICATORPREFIX OUTPUT_STRIP_TRAILING_WHITESPACE) -set (INDICATOR_SERVICE_DIR "${INDICATORPREFIX}/share/unity/indicators") +set (INDICATOR_SERVICE_DIR "${INDICATORPREFIX}/share/${PROJECT_NAME}/indicators") configure_file (${CMAKE_SOURCE_DIR}/config.h.cmake ${CMAKE_BINARY_DIR}/config.h) @@ -177,8 +185,8 @@ find_package (Gettext REQUIRED) set (COMPIZ_I18N_DIR ${CMAKE_SOURCE_DIR}/po) -add_custom_command (OUTPUT ${CMAKE_SOURCE_DIR}/po/unity.pot - COMMAND xgettext -c --from-code=UTF-8 --files-from ${CMAKE_SOURCE_DIR}/po/POTFILES.in --keyword=_ -o ${CMAKE_SOURCE_DIR}/po/unity.pot --copyright-holder="Canonical Ltd" --msgid-bugs-address="ayatana-dev@lists.launchpad.net" --no-wrap --no-location +add_custom_command (OUTPUT ${CMAKE_SOURCE_DIR}/po/${PROJECT_NAME}.pot + COMMAND xgettext -c --from-code=UTF-8 --files-from ${CMAKE_SOURCE_DIR}/po/POTFILES.in --keyword=_ -o ${CMAKE_SOURCE_DIR}/po/${PROJECT_NAME}.pot --copyright-holder="Canonical Ltd" --msgid-bugs-address="ayatana-dev@lists.launchpad.net" --no-wrap --no-location WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ) @@ -274,11 +282,15 @@ if (ENABLE_X_SUPPORT) add_subdirectory(panel) add_subdirectory(decorations) add_subdirectory(plugins/unityshell) - add_subdirectory(plugins/networkarearegion) add_subdirectory(plugins/unity-mt-grab-handles) add_subdirectory(shortcuts) add_subdirectory(shutdown) add_subdirectory(unity-standalone) + + if (ENABLE_NETWORKAREAREGION_PLUGIN) + add_subdirectory(plugins/networkarearegion) + endif (ENABLE_NETWORKAREAREGION_PLUGIN) + endif () add_subdirectory(doc) @@ -355,7 +367,7 @@ SET (UNITY_TEST_SCHEMAS "external.gschema.xml") # Have an option to not install the schema into where GLib is option (GSETTINGS_LOCALINSTALL "Install GSettings Schemas locally instead of to the GLib prefix" OFF) if (GSETTINGS_LOCALINSTALL) - SET (GSETTINGS_DIR "${CMAKE_INSTALL_PREFIX}/share/glib-2.0/schemas/") + SET (GSETTINGS_DIR "${CMAKE_INSTALL_DATADIR}/glib-2.0/schemas/") else (GSETTINGS_LOCALINSTALL) execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} glib-2.0 --variable prefix OUTPUT_VARIABLE _glib_prefix OUTPUT_STRIP_TRAILING_WHITESPACE) SET (GSETTINGS_DIR "${_glib_prefix}/share/glib-2.0/schemas/") @@ -376,7 +388,7 @@ install (CODE "message (STATUS \"Compiling GSettings schemas\")") install (CODE "execute_process (COMMAND ${_glib_comple_schemas} ${GSETTINGS_DIR})") # Resources -install (FILES resources/dash-widgets.json DESTINATION ${CMAKE_INSTALL_PREFIX}/share/unity/themes) +install (FILES resources/dash-widgets.json DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/themes) file (GLOB _datafiles "${CMAKE_CURRENT_SOURCE_DIR}/resources/*") install (FILES ${_datafiles} DESTINATION ${PKGDATADIR}) diff --git a/UnityCore/CMakeLists.txt b/UnityCore/CMakeLists.txt index f055790d3..0693f7e67 100644 --- a/UnityCore/CMakeLists.txt +++ b/UnityCore/CMakeLists.txt @@ -149,22 +149,22 @@ set_target_properties(${CORE_LIB_NAME} PROPERTIES add_pch(pch/unitycore_pch.hh ${CORE_LIB_NAME}) install (TARGETS ${CORE_LIB_NAME} - RUNTIME DESTINATION bin - ARCHIVE DESTINATION lib - LIBRARY DESTINATION lib + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ) # # Headers # -install (FILES ${CORE_HEADERS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/Unity-${UNITY_API_VERSION}/UnityCore) +install (FILES ${CORE_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/Unity-${UNITY_API_VERSION}/UnityCore) # # PkgConfig file # -set (EXEC_PREFIX "${CMAKE_INSTALL_PREFIX}") -set (LIBDIR "${CMAKE_INSTALL_PREFIX}/lib") -set (INCLUDEDIR "${CMAKE_INSTALL_PREFIX}/include") +set (EXEC_PREFIX "${CMAKE_INSTALL_LIBEXECDIR}") +set (LIBDIR "${CMAKE_INSTALL_LIBDIR}") +set (INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}") configure_file (unity-core.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/${CORE_LIB_NAME}.pc @ONLY) -install (FILES ${CMAKE_CURRENT_BINARY_DIR}/${CORE_LIB_NAME}.pc DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig) +install (FILES ${CMAKE_CURRENT_BINARY_DIR}/${CORE_LIB_NAME}.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) diff --git a/UnityCore/DBusIndicators.cpp b/UnityCore/DBusIndicators.cpp index b890124c3..6021418f2 100644 --- a/UnityCore/DBusIndicators.cpp +++ b/UnityCore/DBusIndicators.cpp @@ -123,7 +123,7 @@ void DBusIndicators::Impl::CheckLocalService() // This is obviously hackish, but this part of the code is mostly hackish... // Let's attempt to run it from where we expect it to be - std::string cmd = PREFIXDIR + std::string("/lib/unity/unity-panel-service"); + std::string cmd = UNITYLIBDIR"/" + std::string("unity-panel-service"); LOG_WARN(logger) << "Couldn't load panel from installed services, " << "so trying to load panel from known location: " << cmd; diff --git a/UnityCore/DesktopUtilities.cpp b/UnityCore/DesktopUtilities.cpp index a9a41c5e7..5b841cd0d 100644 --- a/UnityCore/DesktopUtilities.cpp +++ b/UnityCore/DesktopUtilities.cpp @@ -90,6 +90,11 @@ std::string DesktopUtilities::GetUserRuntimeDirectory() return ""; } +std::string DesktopUtilities::GetUserTrashDirectory() +{ + return GetUserDataDirectory().append(G_DIR_SEPARATOR_S "Trash" G_DIR_SEPARATOR_S "files" G_DIR_SEPARATOR_S); +} + std::vector<std::string> DesktopUtilities::GetSystemDataDirectories() { const char* const* system_dirs = g_get_system_data_dirs(); diff --git a/UnityCore/DesktopUtilities.h b/UnityCore/DesktopUtilities.h index 203603ea1..5c0488eaf 100644 --- a/UnityCore/DesktopUtilities.h +++ b/UnityCore/DesktopUtilities.h @@ -33,6 +33,7 @@ public: static std::string GetUserCacheDirectory(); static std::string GetUserRuntimeDirectory(); static std::string GetUserConfigDirectory(); + static std::string GetUserTrashDirectory(); static std::vector<std::string> GetSystemDataDirectories(); static std::vector<std::string> GetDataDirectories(); diff --git a/UnityCore/GLibDBusProxy.cpp b/UnityCore/GLibDBusProxy.cpp index 1cd6f4d3d..7e89f6ddf 100644 --- a/UnityCore/GLibDBusProxy.cpp +++ b/UnityCore/GLibDBusProxy.cpp @@ -301,7 +301,7 @@ void DBusProxy::Impl::OnPropertyChanged(GDBusProxy* proxy, GVariant* changed_pro } } - g_variant_iter_free (iter); + g_variant_iter_free(iter); } for (const gchar *property_name = *invalidated; property_name; property_name = *(++invalidated)) @@ -624,7 +624,7 @@ void DBusProxy::GetProperty(std::string const& name, ReplyCallback const& callba [] (GObject *source, GAsyncResult *res, gpointer user_data) { glib::Error err; std::unique_ptr<ReplyCallback> callback(static_cast<ReplyCallback*>(user_data)); - Variant result(g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &err)); + Variant result(g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &err), StealRef()); if (err) { @@ -660,7 +660,7 @@ void DBusProxy::SetProperty(std::string const& name, GVariant* value) nullptr, G_DBUS_CALL_FLAGS_NONE, -1, pimpl->cancellable_, [] (GObject *source, GAsyncResult *res, gpointer user_data) { glib::Error err; - Variant result(g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &err)); + Variant result(g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &err), StealRef()); if (err) { LOG_ERROR(logger) << "Impossible to set property: " << err; diff --git a/UnityCore/GnomeSessionManager.cpp b/UnityCore/GnomeSessionManager.cpp index 0702b9433..ad1b7cb24 100644 --- a/UnityCore/GnomeSessionManager.cpp +++ b/UnityCore/GnomeSessionManager.cpp @@ -155,6 +155,13 @@ GnomeManager::Impl::Impl(GnomeManager* manager, bool test_mode) }); } + { + dm_seat_proxy_ = std::make_shared<glib::DBusProxy>("org.freedesktop.Accounts", + ("/org/freedesktop/Accounts/User" + std::to_string(getuid())).c_str(), + "org.freedesktop.Accounts.User", + G_BUS_TYPE_SYSTEM); + } + CallLogindMethod("CanHibernate", nullptr, [this] (GVariant* variant, glib::Error const& err) { if (err) { @@ -429,6 +436,22 @@ void GnomeManager::Impl::CallConsoleKitMethod(std::string const& method, GVarian }); } +void GnomeManager::Impl::CallDisplayManagerSeatMethod(std::string const& method, GVariant* parameters) +{ + const char* xdg_seat_path = test_mode_ ? "/org/freedesktop/DisplayManager/Seat0" : g_getenv("XDG_SEAT_PATH"); + + auto proxy = std::make_shared<glib::DBusProxy>(test_mode_ ? testing::DBUS_NAME : "org.freedesktop.DisplayManager", + glib::gchar_to_string(xdg_seat_path), + "org.freedesktop.DisplayManager.Seat", + test_mode_ ? G_BUS_TYPE_SESSION : G_BUS_TYPE_SYSTEM); + proxy->CallBegin(method, parameters, [this, proxy] (GVariant*, glib::Error const& e) { + if (e) + { + LOG_ERROR(logger) << "DisplayManager Seat call failed: " << e.Message(); + } + }); +} + void GnomeManager::Impl::LockScreen(bool prompt) { EnsureCancelPendingAction(); @@ -490,6 +513,13 @@ bool GnomeManager::Impl::HasInhibitors() return inhibitors.GetBool(); } +void GnomeManager::Impl::UserIconFile(std::function<void(std::string const&)> const& callback) +{ + dm_seat_proxy_->GetProperty("IconFile", [this, callback] (GVariant *value) { + callback(glib::Variant(value).GetString()); + }); +} + bool GnomeManager::Impl::IsUserInGroup(std::string const& user_name, std::string const& group_name) { auto group = getgrnam(group_name.c_str()); @@ -535,6 +565,11 @@ std::string GnomeManager::HostName() const return glib::gchar_to_string(g_get_host_name()); } +void GnomeManager::UserIconFile(std::function<void(std::string const&)> const& callback) const +{ + impl_->UserIconFile(callback); +} + void GnomeManager::ScreenSaverActivate() { screensaver_requested.emit(true); @@ -665,6 +700,11 @@ void GnomeManager::Hibernate() }); } +void GnomeManager::SwitchToGreeter() +{ + impl_->CallDisplayManagerSeatMethod("SwitchToGreeter"); +} + bool GnomeManager::CanLock() const { if (is_locked()) diff --git a/UnityCore/GnomeSessionManager.h b/UnityCore/GnomeSessionManager.h index df7df1178..c0894b087 100644 --- a/UnityCore/GnomeSessionManager.h +++ b/UnityCore/GnomeSessionManager.h @@ -36,6 +36,7 @@ public: std::string RealName() const; std::string UserName() const; std::string HostName() const; + void UserIconFile(std::function<void(std::string const&)> const&) const; void ScreenSaverActivate(); void ScreenSaverDeactivate(); @@ -46,6 +47,7 @@ public: void Shutdown(); void Suspend(); void Hibernate(); + void SwitchToGreeter(); bool CanLock() const; bool CanShutdown() const; diff --git a/UnityCore/GnomeSessionManagerImpl.h b/UnityCore/GnomeSessionManagerImpl.h index ee26c3171..88b0dd5c0 100644 --- a/UnityCore/GnomeSessionManagerImpl.h +++ b/UnityCore/GnomeSessionManagerImpl.h @@ -54,6 +54,7 @@ struct GnomeManager::Impl bool HasInhibitors(); void EnsureCancelPendingAction(); void LockScreen(bool prompt); + void UserIconFile(std::function<void(std::string const&)> const& callback); GVariant* OnShellMethodCall(std::string const& method, GVariant* parameters); void CallGnomeSessionMethod(std::string const& method, GVariant* parameters = nullptr, @@ -61,6 +62,7 @@ struct GnomeManager::Impl void CallUPowerMethod(std::string const& method, glib::DBusProxy::ReplyCallback const& cb = nullptr); void CallLogindMethod(std::string const& method, GVariant* parameters = nullptr, glib::DBusProxy::CallFinishedCallback const& cb = nullptr); void CallConsoleKitMethod(std::string const& method, GVariant* parameters = nullptr); + void CallDisplayManagerSeatMethod(std::string const& method, GVariant* parameters = nullptr); bool InteractiveMode(); void UpdateHaveOtherOpenSessions(); @@ -78,6 +80,7 @@ struct GnomeManager::Impl glib::DBusProxy::Ptr login_proxy_; glib::DBusProxy::Ptr presence_proxy_; glib::DBusProxy::Ptr dm_proxy_; + glib::DBusProxy::Ptr dm_seat_proxy_; int open_sessions_; }; diff --git a/UnityCore/SessionManager.h b/UnityCore/SessionManager.h index f6a0d6933..7523d7ebd 100644 --- a/UnityCore/SessionManager.h +++ b/UnityCore/SessionManager.h @@ -44,6 +44,7 @@ public: virtual std::string RealName() const = 0; virtual std::string UserName() const = 0; virtual std::string HostName() const = 0; + virtual void UserIconFile(std::function<void(std::string const&)> const&) const = 0; virtual void ScreenSaverActivate() = 0; virtual void ScreenSaverDeactivate() = 0; @@ -54,6 +55,7 @@ public: virtual void Shutdown() = 0; virtual void Suspend() = 0; virtual void Hibernate() = 0; + virtual void SwitchToGreeter() = 0; virtual bool CanLock() const = 0; virtual bool CanShutdown() const = 0; diff --git a/com.canonical.Unity.gschema.xml b/com.canonical.Unity.gschema.xml index a31ac04b2..c13604a75 100644 --- a/com.canonical.Unity.gschema.xml +++ b/com.canonical.Unity.gschema.xml @@ -13,6 +13,10 @@ <value nick="Left" value="0"/> <value nick="Bottom" value="1"/> </enum> + <enum id="desktop-type-enum"> + <value nick="Ubuntu" value="0" /> + <value nick="UbuntuKylin" value="1" /> + </enum> <schema path="/com/canonical/unity/" id="com.canonical.Unity" gettext-domain="unity"> <key enum="form-factor-enum" name="form-factor"> @@ -25,6 +29,11 @@ <summary>Whether the home screen should be expanded.</summary> <description>Whether the home screen should be expanded.</description> </key> + <key enum="desktop-type-enum" name="desktop-type"> + <default>"Ubuntu"</default> + <summary>The current desktop name.</summary> + <description>The current desktop name.</description> + </key> <key type="i" name="minimize-count"> <default>0</default> <summary>Number of times a normal window has been minimized.</summary> diff --git a/config.h.cmake b/config.h.cmake index 75f2a49de..11dfa0e5f 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -1,8 +1,9 @@ #ifndef CONFIG_H #define CONFIG_H -#cmakedefine PREFIXDIR "@PREFIXDIR@" -#cmakedefine DATADIR "@DATADIR@" +#cmakedefine PREFIXPATH "@PREFIXPATH@" +#cmakedefine UNITYDATADIR "@UNITYDATADIR@" +#cmakedefine UNITYLIBDIR "@UNITYLIBDIR@" #cmakedefine PKGDATADIR "@PKGDATADIR@" #cmakedefine LOCALE_DIR "@LOCALE_DIR@" #cmakedefine VERSION "@VERSION@" diff --git a/dash/previews/StandaloneApplicationPreview.cpp b/dash/previews/StandaloneApplicationPreview.cpp index e4431b3b5..e24f5acaa 100644 --- a/dash/previews/StandaloneApplicationPreview.cpp +++ b/dash/previews/StandaloneApplicationPreview.cpp @@ -17,7 +17,8 @@ * Authored by: Nick Dedekind <nick.dedekind@canonical.com> * */ -#include <gtk/gtk.h> + +#include "config.h" #include "Nux/Nux.h" #include "Nux/VLayout.h" @@ -165,23 +166,23 @@ void TestRunner::Init () description << "Application description " << i << std::endl; // creates a generic preview object - glib::Object<GIcon> iconHint1(g_icon_new_for_string("/usr/share/unity/icons/lens-nav-music.svg", NULL)); - glib::Object<GIcon> iconHint2(g_icon_new_for_string("/usr/share/unity/icons/lens-nav-home.svg", NULL)); - glib::Object<GIcon> iconHint3(g_icon_new_for_string("/usr/share/unity/icons/lens-nav-people.svg", NULL)); + glib::Object<GIcon> iconHint1(g_icon_new_for_string(PKGDATADIR"/lens-nav-music.svg", NULL)); + glib::Object<GIcon> iconHint2(g_icon_new_for_string(PKGDATADIR"/lens-nav-home.svg", NULL)); + glib::Object<GIcon> iconHint3(g_icon_new_for_string(PKGDATADIR"/lens-nav-people.svg", NULL)); GHashTable* action_hints1(g_hash_table_new(g_direct_hash, g_direct_equal)); g_hash_table_insert (action_hints1, g_strdup ("extra-text"), g_variant_new_string("£30.99")); glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_application_preview_new())); - unity_protocol_application_preview_set_app_icon(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), g_icon_new_for_string("/home/nick/SkypeIcon.png", NULL)); + unity_protocol_application_preview_set_app_icon(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), g_icon_new_for_string(PKGDATADIR "/launcher_bfb.png", NULL)); unity_protocol_application_preview_set_license(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), "Proprietary"); unity_protocol_application_preview_set_copyright(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), "(c) Skype 2012"); unity_protocol_application_preview_set_last_update(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), "11th Apr 2012"); unity_protocol_application_preview_set_rating(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), 0.5); unity_protocol_application_preview_set_num_ratings(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), 17); - unity_protocol_preview_set_image_source_uri(proto_obj, "file:///home/nick/Skype.png"); + unity_protocol_preview_set_image_source_uri(proto_obj, "file://" PKGDATADIR "/launcher_bfb.png"); unity_protocol_preview_set_title(proto_obj, app_name.str().c_str()); unity_protocol_preview_set_subtitle(proto_obj, subtitle); unity_protocol_preview_set_description(proto_obj, description.str().c_str()); @@ -210,24 +211,24 @@ void TestRunner::NavRight() The service allows users to communicate with peers by voice, video, and instant messaging over the Internet. Phone calls may be placed to recipients on the traditional telephone networks. Calls to other users within the Skype service are free of charge, while calls to landline telephones and mobile phones are charged via a debit-based user account system."; // creates a generic preview object - glib::Object<GIcon> iconHint1(g_icon_new_for_string("/usr/share/unity/icons/lens-nav-music.svg", NULL)); - glib::Object<GIcon> iconHint2(g_icon_new_for_string("/usr/share/unity/icons/lens-nav-home.svg", NULL)); - glib::Object<GIcon> iconHint3(g_icon_new_for_string("/usr/share/unity/icons/lens-nav-people.svg", NULL)); - glib::Object<GIcon> iconHint4(g_icon_new_for_string("/usr/share/unity/icons/lens-nav-people.svg", NULL)); + glib::Object<GIcon> iconHint1(g_icon_new_for_string(PKGDATADIR"/lens-nav-music.svg", NULL)); + glib::Object<GIcon> iconHint2(g_icon_new_for_string(PKGDATADIR"/lens-nav-home.svg", NULL)); + glib::Object<GIcon> iconHint3(g_icon_new_for_string(PKGDATADIR"/lens-nav-people.svg", NULL)); + glib::Object<GIcon> iconHint4(g_icon_new_for_string(PKGDATADIR"/lens-nav-people.svg", NULL)); GHashTable* action_hints1(g_hash_table_new(g_direct_hash, g_direct_equal)); g_hash_table_insert (action_hints1, g_strdup ("extra-text"), g_variant_new_string("£30.99")); glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_application_preview_new())); - unity_protocol_application_preview_set_app_icon(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), g_icon_new_for_string("/home/nick/SkypeIcon.png", NULL)); + unity_protocol_application_preview_set_app_icon(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), g_icon_new_for_string(PKGDATADIR "/launcher_bfb.png", NULL)); unity_protocol_application_preview_set_license(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), "Proprietary"); unity_protocol_application_preview_set_copyright(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), "(c) Skype 2012"); unity_protocol_application_preview_set_last_update(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), "11th Apr 2012"); unity_protocol_application_preview_set_rating(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), 0.25); unity_protocol_application_preview_set_num_ratings(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), 5); - unity_protocol_preview_set_image_source_uri(proto_obj, "file:///home/nick/Skype.png"); + unity_protocol_preview_set_image_source_uri(proto_obj, "file://" PKGDATADIR "/launcher_bfb.png"); unity_protocol_preview_set_title(proto_obj, app_name.str().c_str()); unity_protocol_preview_set_subtitle(proto_obj, subtitle); unity_protocol_preview_set_description(proto_obj, description); @@ -262,9 +263,9 @@ void TestRunner::NavLeft() The service allows users to communicate with peers by voice, video, and instant messaging over the Internet. Phone calls may be placed to recipients on the traditional telephone networks. Calls to other users within the Skype service are free of charge, while calls to landline telephones and mobile phones are charged via a debit-based user account system."; // creates a generic preview object - glib::Object<GIcon> iconHint1(g_icon_new_for_string("/usr/share/unity/icons/lens-nav-music.svg", NULL)); - glib::Object<GIcon> iconHint2(g_icon_new_for_string("/usr/share/unity/icons/lens-nav-home.svg", NULL)); - glib::Object<GIcon> iconHint3(g_icon_new_for_string("/usr/share/unity/icons/lens-nav-people.svg", NULL)); + glib::Object<GIcon> iconHint1(g_icon_new_for_string(PKGDATADIR"/lens-nav-music.svg", NULL)); + glib::Object<GIcon> iconHint2(g_icon_new_for_string(PKGDATADIR"/lens-nav-home.svg", NULL)); + glib::Object<GIcon> iconHint3(g_icon_new_for_string(PKGDATADIR"/lens-nav-people.svg", NULL)); GHashTable* action_hints1(g_hash_table_new(g_direct_hash, g_direct_equal)); g_hash_table_insert (action_hints1, g_strdup ("extra-text"), g_variant_new_string("£30.99")); @@ -272,14 +273,14 @@ void TestRunner::NavLeft() glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_application_preview_new())); - unity_protocol_application_preview_set_app_icon(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), g_icon_new_for_string("/home/nick/SkypeIcon.png", NULL)); + unity_protocol_application_preview_set_app_icon(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), g_icon_new_for_string(PKGDATADIR"/launcher_bfb.png", NULL)); unity_protocol_application_preview_set_license(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), "Proprietary"); unity_protocol_application_preview_set_copyright(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), "(c) Skype 2012"); unity_protocol_application_preview_set_last_update(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), "11th Apr 2012"); unity_protocol_application_preview_set_rating(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), 0.8); unity_protocol_application_preview_set_num_ratings(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), 1223); - unity_protocol_preview_set_image_source_uri(proto_obj, "file:///home/nick/Skype.png"); + unity_protocol_preview_set_image_source_uri(proto_obj, "file://" PKGDATADIR "/launcher_bfb.png"); unity_protocol_preview_set_title(proto_obj, app_name.str().c_str()); unity_protocol_preview_set_subtitle(proto_obj, subtitle); unity_protocol_preview_set_description(proto_obj, description); diff --git a/dash/previews/StandaloneSocialPreview.cpp b/dash/previews/StandaloneSocialPreview.cpp index 1eb2b77db..a73d9ba56 100644 --- a/dash/previews/StandaloneSocialPreview.cpp +++ b/dash/previews/StandaloneSocialPreview.cpp @@ -17,7 +17,7 @@ * Authored by: Nick Dedekind <nick.dedekind@canonical.com> * */ -#include <gtk/gtk.h> +#include "config.h" #include "Nux/Nux.h" #include "Nux/VLayout.h" @@ -159,7 +159,7 @@ void TestRunner::Init () const char* description = "Lorem ipsum dolor sit amet, id eruditi referrentur cum, et est enim persequeris. Munere docendi intellegebat pro id, nam no delenit facilisis similique, ut usu eros aliquando. Electram postulant accusamus ut ius, cum ad impedit facilis mediocrem. At cum tamquam."; glib::Object<GIcon> iconHint1(g_icon_new_for_string("/usr/share/pixmaps/faces/sunflower.jpg", NULL)); - glib::Object<GIcon> iconHint2(g_icon_new_for_string("/usr/share/unity/icons/lens-nav-home.svg", NULL)); + glib::Object<GIcon> iconHint2(g_icon_new_for_string(PKGDATADIR"/lens-nav-home.svg", NULL)); glib::Object<GIcon> iconHint3(g_icon_new_for_string("/usr/share/icons/unity-icon-theme/places/svg/service-twitter.svg", NULL)); glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_social_preview_new())); @@ -193,7 +193,7 @@ void TestRunner::NavRight() // creates a generic preview object glib::Object<GIcon> iconHint1(g_icon_new_for_string("/usr/share/pixmaps/faces/astronaut.jpg", NULL)); - glib::Object<GIcon> iconHint2(g_icon_new_for_string("/usr/share/unity/icons/lens-nav-home.svg", NULL)); + glib::Object<GIcon> iconHint2(g_icon_new_for_string(PKGDATADIR"/lens-nav-home.svg", NULL)); glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_social_preview_new())); @@ -228,7 +228,7 @@ void TestRunner::NavLeft() const char* description = "Profile pictures are what people want them to think they look like. Tagged pictures are what they really look like."; glib::Object<GIcon> iconHint1(g_icon_new_for_string("/usr/share/pixmaps/faces/soccerball.png", NULL)); - glib::Object<GIcon> iconHint2(g_icon_new_for_string("/usr/share/unity/icons/lens-nav-home.svg", NULL)); + glib::Object<GIcon> iconHint2(g_icon_new_for_string(PKGDATADIR"/lens-nav-home.svg", NULL)); glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_social_preview_new())); diff --git a/data/pam/CMakeLists.txt b/data/pam/CMakeLists.txt index ece7a4cc8..73f4b7d57 100644 --- a/data/pam/CMakeLists.txt +++ b/data/pam/CMakeLists.txt @@ -1 +1 @@ -install(FILES unity DESTINATION ${CMAKE_SYSCONFDIR}/pam.d) \ No newline at end of file +install(FILES unity DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/pam.d) diff --git a/debian/changelog b/debian/changelog index 49656e032..f3ab7fd8b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,28 @@ +unity (7.4.0+16.04.20160209.3-0ubuntu1) xenial; urgency=medium + + [ Didier Roche ] + * debian: Recommends session-shortcuts, prodiving easy way to + shutdown, reboot and logout from dash + + [ Marco Trevisan (Treviño) ] + * CMake: use GNUInstallDirs with native multi-arch support (LP: + #1508635, #1485668) + * Launcher: add FileManager, Trash and Volume icons integration (LP: + #1524721, #1161323, #1063838, #1063823) + * SwitcherModel: avoid to access to invalid selection or to divide by + zero (LP: #1537524) + + [ handsome_feng ] + * Extend the lockscreen theme for kylin. + + -- Marco Trevisan (Treviño) <mail@3v1n0.net> Tue, 09 Feb 2016 12:21:15 +0000 + +unity (7.4.0+16.04.20151218-0ubuntu2) xenial; urgency=medium + + * Multiarchify the library packages. + + -- Matthias Klose <doko@ubuntu.com> Thu, 28 Jan 2016 17:38:52 +0100 + unity (7.4.0+16.04.20151218-0ubuntu1) xenial; urgency=medium [ Aneesh Madhavan ] diff --git a/debian/control b/debian/control index c574461a7..7c30e36b2 100644 --- a/debian/control +++ b/debian/control @@ -83,6 +83,7 @@ Depends: ${shlibs:Depends}, Provides: indicator-renderer Recommends: unity-control-center, ${unity-default-masterscopes} + nautilus, indicator-appmenu (>= 15.02.0), indicator-application, indicator-sound, @@ -140,6 +141,8 @@ Description: Interface designed for efficiency of space and interaction. Package: libunity-core-6.0-9 Section: libs Architecture: any +Multi-Arch: same +Pre-Depends: ${misc:Pre-Depends} Depends: ${shlibs:Depends}, ${misc:Depends}, unity-services (= ${binary:Version}), @@ -160,6 +163,7 @@ Description: core library for the Unity interface Package: libunity-core-6.0-dev Section: libdevel Architecture: any +Multi-Arch: same Depends: ${misc:Depends}, libunity-core-6.0-9 (= ${binary:Version}), libglib2.0-dev, diff --git a/debian/libunity-core-6.0-9.install b/debian/libunity-core-6.0-9.install index 3e2b01376..be488a661 100644 --- a/debian/libunity-core-6.0-9.install +++ b/debian/libunity-core-6.0-9.install @@ -1,5 +1,5 @@ -usr/lib/libunity-core*.so.* -usr/lib/unity/*.py +usr/lib/*/libunity-core*.so.* +usr/lib/*/unity/*.py usr/share/ccsm usr/share/gnome-control-center/ usr/share/unity diff --git a/debian/libunity-core-6.0-dev.install b/debian/libunity-core-6.0-dev.install index 96044d726..62b07c3f2 100644 --- a/debian/libunity-core-6.0-dev.install +++ b/debian/libunity-core-6.0-dev.install @@ -1,3 +1,3 @@ usr/include/ -usr/lib/pkgconfig/ -usr/lib/libunity-core*.so +usr/lib/*/pkgconfig/ +usr/lib/*/libunity-core*.so diff --git a/debian/rules b/debian/rules index 5430079e5..5f4d89837 100755 --- a/debian/rules +++ b/debian/rules @@ -23,7 +23,7 @@ NUX_ABIVERSION := $(shell sed -rn 's/^\#define[[:space:]]+NUX_ABIVERSION[[:space LIBUNITY_PRIVATE := $(shell pkg-config --libs-only-L unity-protocol-private | sed -e 's/-L\(.*\)/\1/' ) SCOPES_RECOMMENDS := $(shell perl debian/scopes-recommends-generator /usr/share/unity/client-scopes.json) -cmake_base_options := -DUSE_GSETTINGS=TRUE -DCOMPIZ_BUILD_WITH_RPATH=FALSE -DCOMPIZ_PACKAGING_ENABLED=TRUE -DCMAKE_SYSCONFDIR=/etc -DCOMPIZ_PLUGIN_INSTALL_TYPE=package +cmake_base_options := -DUSE_GSETTINGS=TRUE -DCOMPIZ_BUILD_WITH_RPATH=FALSE -DCOMPIZ_PACKAGING_ENABLED=TRUE -DCOMPIZ_PLUGIN_INSTALL_TYPE=package ifeq ($(DEB_HOST_ARCH),$(findstring $(DEB_HOST_ARCH), $(gles2_architectures))) cmake_gl_options := -DBUILD_GLES=TRUE -DDISABLE_MAINTAINER_CFLAGS=ON endif @@ -39,9 +39,7 @@ override_dh_install: done; \ cd $(CURDIR) find debian/tmp/usr/lib -name \*.*a -exec rm {} \; - rm -f debian/tmp/usr/share/compiz/networkarearegion.xml - rm -f debian/tmp//usr/lib/compiz/libnetworkarearegion.so - rm -rf debian/tmp/usr/share/gconf/schemas/ + rm -rf debian/tmp/usr/share/gconf/schemas dh_install --fail-missing override_dh_gencontrol: diff --git a/debian/unity-services.install b/debian/unity-services.install index b7ab4d33f..4f0e67ca8 100644 --- a/debian/unity-services.install +++ b/debian/unity-services.install @@ -1,3 +1,3 @@ -usr/lib/unity/*service +usr/lib/*/unity/*service usr/share/upstart usr/share/man/*/unity-panel-service.1 diff --git a/debian/unity.install b/debian/unity.install index bf5cdc899..22e55b097 100644 --- a/debian/unity.install +++ b/debian/unity.install @@ -1,6 +1,6 @@ etc/pam.d usr/bin -usr/lib/compiz +usr/lib/*/compiz/libunity*.so usr/share/man/*/unity.1 usr/share/compiz usr/share/locale diff --git a/gnome/CMakeLists.txt b/gnome/CMakeLists.txt index c99077df4..f98b62d11 100644 --- a/gnome/CMakeLists.txt +++ b/gnome/CMakeLists.txt @@ -6,7 +6,7 @@ compiz_translate_xml (${CMAKE_CURRENT_SOURCE_DIR}/50-unity-launchers.xml.in ${CMAKE_CURRENT_BINARY_DIR}/50-unity-launchers.xml NOTRANSLATIONS) install (FILES ${CMAKE_CURRENT_BINARY_DIR}/50-unity-launchers.xml - DESTINATION ${CMAKE_INSTALL_PREFIX}/share/gnome-control-center/keybindings) + DESTINATION ${CMAKE_INSTALL_DATADIR}/gnome-control-center/keybindings) add_custom_target (unity-gnome-keybindings ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/50-unity-launchers.xml) diff --git a/launcher/AbstractLauncherIcon.h b/launcher/AbstractLauncherIcon.h index 926736be1..ed40c8f71 100644 --- a/launcher/AbstractLauncherIcon.h +++ b/launcher/AbstractLauncherIcon.h @@ -174,13 +174,17 @@ public: virtual WindowList Windows() = 0; - virtual std::vector<Window> WindowsForMonitor(int monitor) = 0; + virtual WindowList WindowsForMonitor(int monitor) = 0; - virtual std::vector<Window> WindowsOnViewport() = 0; + virtual WindowList WindowsOnViewport() = 0; - virtual const bool WindowVisibleOnMonitor(int monitor) = 0; + virtual bool WindowVisibleOnMonitor(int monitor) const = 0; - virtual const bool WindowVisibleOnViewport() = 0; + virtual bool WindowVisibleOnViewport() const = 0; + + virtual size_t WindowsVisibleOnMonitor(int monitor) const = 0; + + virtual size_t WindowsVisibleOnViewport() const = 0; virtual float PresentUrgency() = 0; diff --git a/launcher/ApplicationLauncherIcon.cpp b/launcher/ApplicationLauncherIcon.cpp index 3e6889825..91ea82107 100644 --- a/launcher/ApplicationLauncherIcon.cpp +++ b/launcher/ApplicationLauncherIcon.cpp @@ -1,6 +1,6 @@ // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* - * Copyright (C) 2010-2012 Canonical Ltd + * Copyright (C) 2010-2015 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as @@ -19,10 +19,8 @@ */ #include "config.h" -#include <boost/algorithm/string.hpp> #include <Nux/Nux.h> -#include <Nux/BaseWindow.h> #include <NuxCore/Logger.h> #include <UnityCore/GLibWrapper.h> @@ -30,12 +28,7 @@ #include "ApplicationLauncherIcon.h" #include "FavoriteStore.h" -#include "MultiMonitor.h" #include "unity-shared/DesktopApplicationManager.h" -#include "unity-shared/GnomeFileManager.h" -#include "unity-shared/UBusWrapper.h" -#include "unity-shared/UBusMessages.h" -#include "unity-shared/UScreen.h" #include <glib/gi18n-lib.h> #include <gio/gdesktopappinfo.h> @@ -44,15 +37,13 @@ namespace unity { namespace launcher { -DECLARE_LOGGER(logger, "unity.launcher.icon.application"); namespace { -// We use the "bamf-" prefix since the manager is protected, to avoid name clash -const std::string ICON_REMOVE_TIMEOUT = "bamf-icon-remove"; -const std::string ICON_DND_OVER_TIMEOUT = "bamf-icon-dnd-over"; +DECLARE_LOGGER(logger, "unity.launcher.icon.application"); + +// We use the "application-" prefix since the manager is protected, to avoid name clash +const std::string ICON_REMOVE_TIMEOUT = "application-icon-remove"; const std::string DEFAULT_ICON = "application-default-icon"; -const int MAXIMUM_QUICKLIST_WIDTH = 300; -const int COMPIZ_SCALE_DND_SPREAD = 1 << 7; enum MenuItemType { @@ -67,10 +58,8 @@ enum MenuItemType NUX_IMPLEMENT_OBJECT_TYPE(ApplicationLauncherIcon); ApplicationLauncherIcon::ApplicationLauncherIcon(ApplicationPtr const& app) - : SimpleLauncherIcon(IconType::APPLICATION) - , _startup_notification_timestamp(0) - , _last_scroll_timestamp(0) - , _progressive_scroll(0) + : WindowedLauncherIcon(IconType::APPLICATION) + , startup_notification_timestamp_(0) , use_custom_bg_color_(false) , bg_color_(nux::color::White) { @@ -83,13 +72,6 @@ ApplicationLauncherIcon::ApplicationLauncherIcon(ApplicationPtr const& app) << ", running: " << (app->running() ? "yes" : "no"); SetApplication(app); - - WindowManager& wm = WindowManager::Default(); - wm.window_minimized.connect(sigc::mem_fun(this, &ApplicationLauncherIcon::OnWindowMinimized)); - wm.screen_viewport_switch_ended.connect(sigc::mem_fun(this, &ApplicationLauncherIcon::EnsureWindowState)); - wm.terminate_expo.connect(sigc::mem_fun(this, &ApplicationLauncherIcon::EnsureWindowState)); - UScreen::GetDefault()->changed.connect(sigc::hide(sigc::hide(sigc::mem_fun(this, &ApplicationLauncherIcon::EnsureWindowsLocation)))); - EnsureWindowsLocation(); } @@ -157,23 +139,19 @@ void ApplicationLauncherIcon::SetupApplicationSignalsConnections() signals_conn_.Add(app_->window_opened.connect([this](ApplicationWindowPtr const& win) { signals_conn_.Add(win->monitor.changed.connect([this] (int) { EnsureWindowsLocation(); })); EnsureWindowsLocation(); - - if (WindowManager::Default().IsScaleActiveForGroup() && IsActive()) - Spread(true, 0, false); })); - auto ensure_win_location_cb = sigc::hide(sigc::mem_fun(this, &ApplicationLauncherIcon::EnsureWindowsLocation)); - signals_conn_.Add(app_->window_closed.connect(ensure_win_location_cb)); + signals_conn_.Add(app_->window_closed.connect([this] (ApplicationWindowPtr const&) { EnsureWindowsLocation(); })); for (auto& win : app_->GetWindows()) - signals_conn_.Add(win->monitor.changed.connect(ensure_win_location_cb)); + signals_conn_.Add(win->monitor.changed.connect([this] (int) { EnsureWindowsLocation(); })); - signals_conn_.Add(app_->urgent.changed.connect([this](bool const& urgent) { + signals_conn_.Add(app_->urgent.changed.connect([this](bool urgent) { LOG_DEBUG(logger) << tooltip_text() << " urgent now " << (urgent ? "true" : "false"); SetQuirk(Quirk::URGENT, urgent); })); - signals_conn_.Add(app_->active.changed.connect([this](bool const& active) { + signals_conn_.Add(app_->active.changed.connect([this](bool active) { LOG_DEBUG(logger) << tooltip_text() << " active now " << (active ? "true" : "false"); SetQuirk(Quirk::ACTIVE, active); })); @@ -185,8 +163,8 @@ void ApplicationLauncherIcon::SetupApplicationSignalsConnections() signals_conn_.Add(app_->title.changed.connect([this](std::string const& name) { LOG_DEBUG(logger) << tooltip_text() << " name now " << name; - if (_menu_items.size() == MenuItemType::SIZE) - _menu_items[MenuItemType::APP_NAME] = nullptr; + if (menu_items_.size() == MenuItemType::SIZE) + menu_items_[MenuItemType::APP_NAME] = nullptr; tooltip_text = name; })); @@ -195,7 +173,7 @@ void ApplicationLauncherIcon::SetupApplicationSignalsConnections() icon_name = (icon.empty() ? DEFAULT_ICON : icon); })); - signals_conn_.Add(app_->running.changed.connect([this](bool const& running) { + signals_conn_.Add(app_->running.changed.connect([this](bool running) { LOG_DEBUG(logger) << tooltip_text() << " running now " << (running ? "true" : "false"); SetQuirk(Quirk::RUNNING, running); @@ -208,35 +186,47 @@ void ApplicationLauncherIcon::SetupApplicationSignalsConnections() } })); - signals_conn_.Add(app_->visible.changed.connect([this](bool const& visible) { + signals_conn_.Add(app_->visible.changed.connect([this](bool visible) { SetQuirk(Quirk::VISIBLE, IsSticky() ? true : visible); })); - signals_conn_.Add(app_->closed.connect([this]() { - if (!IsSticky()) - { - SetQuirk(Quirk::VISIBLE, false); - HideTooltip(); - - /* Use a timeout to remove the icon, this avoids - * that we remove an application that is going - * to be reopened soon. So applications that - * have a splash screen won't be removed from - * the launcher while the splash is closed and - * a new window is opened. */ - _source_manager.AddTimeoutSeconds(1, [this] { - Remove(); - return false; - }, ICON_REMOVE_TIMEOUT); - } + signals_conn_.Add(app_->closed.connect([this] { + LOG_DEBUG(logger) << tooltip_text() << " closed"; + OnApplicationClosed(); })); } +WindowList ApplicationLauncherIcon::GetManagedWindows() const +{ + return app_ ? app_->GetWindows() : WindowList(); +} + +void ApplicationLauncherIcon::OnApplicationClosed() +{ + if (IsSticky()) + return; + + SetQuirk(Quirk::VISIBLE, false); + HideTooltip(); + + /* Use a timeout to remove the icon, this avoids + * that we remove an application that is going + * to be reopened soon. So applications that + * have a splash screen won't be removed from + * the launcher while the splash is closed and + * a new window is opened. */ + _source_manager.AddTimeoutSeconds(1, [this] { + Remove(); + return false; + }, ICON_REMOVE_TIMEOUT); +} + +// Move to WindowedLauncherIcon?! bool ApplicationLauncherIcon::GetQuirk(AbstractLauncherIcon::Quirk quirk, int monitor) const { if (quirk == Quirk::ACTIVE) { - if (!SimpleLauncherIcon::GetQuirk(Quirk::ACTIVE, monitor)) + if (!WindowedLauncherIcon::GetQuirk(Quirk::ACTIVE, monitor)) return false; if (app_->type() == AppType::WEBAPP) @@ -248,304 +238,35 @@ bool ApplicationLauncherIcon::GetQuirk(AbstractLauncherIcon::Quirk quirk, int mo return app_->OwnsWindow(WindowManager::Default().GetActiveWindow()); } - return SimpleLauncherIcon::GetQuirk(quirk, monitor); + return WindowedLauncherIcon::GetQuirk(quirk, monitor); } void ApplicationLauncherIcon::Remove() { LogUnityEvent(ApplicationEventType::LEAVE); UnsetApplication(); - SimpleLauncherIcon::Remove(); + WindowedLauncherIcon::Remove(); } bool ApplicationLauncherIcon::IsSticky() const { if (app_) - return app_->sticky() && SimpleLauncherIcon::IsSticky(); + return app_->sticky() && WindowedLauncherIcon::IsSticky(); return false; } -bool ApplicationLauncherIcon::IsActive() const -{ - return GetQuirk(Quirk::ACTIVE); -} - -bool ApplicationLauncherIcon::IsRunning() const -{ - return GetQuirk(Quirk::RUNNING); -} - -bool ApplicationLauncherIcon::IsUrgent() const -{ - return GetQuirk(Quirk::URGENT); -} - -void ApplicationLauncherIcon::ActivateLauncherIcon(ActionArg arg) -{ - SimpleLauncherIcon::ActivateLauncherIcon(arg); - WindowManager& wm = WindowManager::Default(); - - // This is a little awkward as the target is only set from the switcher. - if (arg.target) - { - // thumper: should we Raise too? should the WM raise? - wm.Activate(arg.target); - return; - } - - bool scale_was_active = wm.IsScaleActive(); - bool active = IsActive(); - bool user_visible = IsRunning(); - /* We should check each child to see if there is - * an unmapped (!= minimized) window around and - * if so force "Focus" behaviour */ - - if (arg.source != ActionArg::Source::SWITCHER) - { - user_visible = app_->visible(); - - if (active) - { - bool any_visible = false; - bool any_mapped = false; - bool any_on_top = false; - bool any_on_monitor = (arg.monitor < 0); - int active_monitor = arg.monitor; - - for (auto const& window : app_->GetWindows()) - { - Window xid = window->window_id(); - - if (!any_visible && wm.IsWindowOnCurrentDesktop(xid)) - { - any_visible = true; - } - - if (!any_mapped && wm.IsWindowMapped(xid)) - { - any_mapped = true; - } - - if (!any_on_top && wm.IsWindowOnTop(xid)) - { - any_on_top = true; - } - - if (!any_on_monitor && window->monitor() == arg.monitor && - wm.IsWindowMapped(xid) && wm.IsWindowVisible(xid)) - { - any_on_monitor = true; - } - - if (window->active()) - { - active_monitor = window->monitor(); - } - } - - if (!any_visible || !any_mapped || !any_on_top) - active = false; - - if (any_on_monitor && arg.monitor >= 0 && active_monitor != arg.monitor) - active = false; - } - - if (user_visible && IsSticky() && IsFileManager()) - { - // See bug #753938 - unsigned minimum_windows = 0; - auto const& file_manager = GnomeFileManager::Get(); - - if (file_manager->IsTrashOpened()) - ++minimum_windows; - - if (file_manager->IsDeviceOpened()) - ++minimum_windows; - - if (minimum_windows > 0) - { - if (file_manager->OpenedLocations().size() == minimum_windows && - GetWindows(WindowFilter::USER_VISIBLE|WindowFilter::MAPPED).size() == minimum_windows) - { - user_visible = false; - } - } - } - } - - /* Behaviour: - * 1) Nothing running, or nothing visible -> launch application - * 2) Running and active -> spread application - * 3) Running and not active -> focus application - * 4) Spread is active and different icon pressed -> change spread - * 5) Spread is active -> Spread de-activated, and fall through - */ - - if (!IsRunning() || (IsRunning() && !user_visible)) // #1 above - { - if (GetQuirk(Quirk::STARTING, arg.monitor)) - return; - - wm.TerminateScale(); - SetQuirk(Quirk::STARTING, true, arg.monitor); - OpenInstanceLauncherIcon(arg.timestamp); - } - else // app is running - { - if (active) - { - if (scale_was_active) // #5 above - { - wm.TerminateScale(); - - if (minimize_window_on_click()) - { - for (auto const& win : GetWindows(WindowFilter::ON_CURRENT_DESKTOP)) - wm.Minimize(win->window_id()); - } - else - { - Focus(arg); - } - } - else // #2 above - { - if (arg.source != ActionArg::Source::SWITCHER) - { - bool minimized = false; - - if (minimize_window_on_click()) - { - WindowList const& windows = GetWindows(WindowFilter::ON_CURRENT_DESKTOP); - - if (windows.size() == 1) - { - wm.Minimize(windows[0]->window_id()); - minimized = true; - } - } - - if (!minimized) - { - Spread(true, 0, false); - } - } - } - } - else - { - if (scale_was_active) // #4 above - { - if (GetWindows(WindowFilter::ON_CURRENT_DESKTOP).size() <= 1) - wm.TerminateScale(); - - Focus(arg); - - if (arg.source != ActionArg::Source::SWITCHER) - Spread(true, 0, false); - } - else // #3 above - { - Focus(arg); - } - } - } -} - -WindowList ApplicationLauncherIcon::GetWindows(WindowFilterMask filter, int monitor) -{ - WindowManager& wm = WindowManager::Default(); - WindowList results; - - monitor = (filter & WindowFilter::ON_ALL_MONITORS) ? -1 : monitor; - bool mapped = (filter & WindowFilter::MAPPED); - bool user_visible = (filter & WindowFilter::USER_VISIBLE); - bool current_desktop = (filter & WindowFilter::ON_CURRENT_DESKTOP); - - for (auto& window : app_->GetWindows()) - { - if ((monitor >= 0 && window->monitor() == monitor) || monitor < 0) - { - if ((user_visible && window->visible()) || !user_visible) - { - Window xid = window->window_id(); - - if ((mapped && wm.IsWindowMapped(xid)) || !mapped) - { - if ((current_desktop && wm.IsWindowOnCurrentDesktop(xid)) || !current_desktop) - { - results.push_back(window); - } - } - } - } - } - - return results; -} - -WindowList ApplicationLauncherIcon::Windows() +bool ApplicationLauncherIcon::IsUserVisible() const { - return GetWindows(WindowFilter::MAPPED|WindowFilter::ON_ALL_MONITORS); -} - -std::vector<Window> ApplicationLauncherIcon::WindowsOnViewport() -{ - WindowFilterMask filter = 0; - filter |= WindowFilter::MAPPED; - filter |= WindowFilter::USER_VISIBLE; - filter |= WindowFilter::ON_CURRENT_DESKTOP; - filter |= WindowFilter::ON_ALL_MONITORS; - - std::vector<Window> windows; - for (auto& window : GetWindows(filter)) - { - windows.push_back(window->window_id()); - } - return windows; -} - -std::vector<Window> ApplicationLauncherIcon::WindowsForMonitor(int monitor) -{ - WindowFilterMask filter = 0; - filter |= WindowFilter::MAPPED; - filter |= WindowFilter::USER_VISIBLE; - filter |= WindowFilter::ON_CURRENT_DESKTOP; - - std::vector<Window> windows; - for (auto& window : GetWindows(filter, monitor)) - { - windows.push_back(window->window_id()); - } - return windows; -} - -void ApplicationLauncherIcon::OnWindowMinimized(guint32 xid) -{ - for (auto const& window: app_->GetWindows()) - { - if (xid == window->window_id()) - { - int monitor = GetCenterForMonitor(window->monitor()).first; - - if (monitor >= 0) - { - Present(0.5f, 600, monitor); - FullyAnimateQuirkDelayed(300, Quirk::SHIMMER, monitor); - } - - break; - } - } + return app_ ? app_->visible() : false; } void ApplicationLauncherIcon::UpdateDesktopFile() { std::string const& filename = app_->desktop_file(); - if (_desktop_file_monitor) - _gsignals.Disconnect(_desktop_file_monitor, "changed"); + if (desktop_file_monitor_) + glib_signals_.Disconnect(desktop_file_monitor_, "changed"); auto old_uri = RemoteUri(); UpdateRemoteUri(); @@ -559,11 +280,11 @@ void ApplicationLauncherIcon::UpdateDesktopFile() // we can remove ourself from the launcher and when it's changed // we can update the quicklist. glib::Object<GFile> desktop_file(g_file_new_for_path(filename.c_str())); - _desktop_file_monitor = g_file_monitor_file(desktop_file, G_FILE_MONITOR_NONE, + desktop_file_monitor_ = g_file_monitor_file(desktop_file, G_FILE_MONITOR_NONE, nullptr, nullptr); - g_file_monitor_set_rate_limit(_desktop_file_monitor, 2000); + g_file_monitor_set_rate_limit(desktop_file_monitor_, 2000); - _gsignals.Add<void, GFileMonitor*, GFile*, GFile*, GFileMonitorEvent>(_desktop_file_monitor, "changed", + glib_signals_.Add<void, GFileMonitor*, GFile*, GFile*, GFileMonitorEvent>(desktop_file_monitor_, "changed", [this, desktop_file] (GFileMonitor*, GFile*, GFile*, GFileMonitorEvent event_type) { switch (event_type) { @@ -600,7 +321,7 @@ void ApplicationLauncherIcon::UpdateDesktopFile() bool update_saved_uri = (!filename.empty() && app_->sticky()); if (update_saved_uri) - SimpleLauncherIcon::UnStick(); + WindowedLauncherIcon::UnStick(); uri_changed.emit(new_uri); @@ -614,22 +335,6 @@ std::string ApplicationLauncherIcon::DesktopFile() const return app_->desktop_file(); } -void ApplicationLauncherIcon::AddProperties(debug::IntrospectionData& introspection) -{ - SimpleLauncherIcon::AddProperties(introspection); - - std::vector<Window> xids; - for (auto const& window : GetWindows()) - xids.push_back(window->window_id()); - - introspection - .add("desktop_file", DesktopFile()) - .add("desktop_id", app_->desktop_id()) - .add("xids", glib::Variant::FromVector(xids)) - .add("sticky", IsSticky()) - .add("startup_notification_timestamp", _startup_notification_timestamp); -} - void ApplicationLauncherIcon::OpenInstanceWithUris(std::set<std::string> const& uris, Time timestamp) { glib::Error error; @@ -639,9 +344,9 @@ void ApplicationLauncherIcon::OpenInstanceWithUris(std::set<std::string> const& GdkDisplay* display = gdk_display_get_default(); glib::Object<GdkAppLaunchContext> app_launch_context(gdk_display_get_app_launch_context(display)); - _startup_notification_timestamp = timestamp; - if (_startup_notification_timestamp > 0) - gdk_app_launch_context_set_timestamp(app_launch_context, _startup_notification_timestamp); + startup_notification_timestamp_ = timestamp; + if (startup_notification_timestamp_ > 0) + gdk_app_launch_context_set_timestamp(app_launch_context, startup_notification_timestamp_); if (g_app_info_supports_uris(appInfo)) { @@ -705,83 +410,40 @@ void ApplicationLauncherIcon::Focus(ActionArg arg) app_->Focus(show_only_visible, arg.monitor); } -bool ApplicationLauncherIcon::Spread(bool current_desktop, int state, bool force) -{ - std::vector<Window> windows; - for (auto& window : GetWindows(current_desktop ? WindowFilter::ON_CURRENT_DESKTOP : 0)) - windows.push_back(window->window_id()); - - return WindowManager::Default().ScaleWindowGroup(windows, state, force); -} - -void ApplicationLauncherIcon::EnsureWindowState() -{ - std::vector<int> number_of_windows_on_monitor(monitors::MAX); - - for (auto& window: app_->GetWindows()) - { - int monitor = window->monitor(); - Window window_id = window->window_id(); - - if (WindowManager::Default().IsWindowOnCurrentDesktop(window_id)) - { - // If monitor is -1 (or negative), show on all monitors. - if (monitor < 0) - { - for (unsigned j; j < monitors::MAX; ++j) - ++number_of_windows_on_monitor[j]; - } - else - { - ++number_of_windows_on_monitor[monitor]; - } - } - } - - for (unsigned i = 0; i < monitors::MAX; ++i) - SetNumberOfWindowsVisibleOnMonitor(number_of_windows_on_monitor[i], i); -} - -void ApplicationLauncherIcon::EnsureWindowsLocation() -{ - EnsureWindowState(); - UpdateIconGeometries(GetCenters()); -} - void ApplicationLauncherIcon::UpdateDesktopQuickList() { std::string const& desktop_file = DesktopFile(); - if (_menu_desktop_shortcuts) + if (menu_desktop_shortcuts_) { - for (GList *l = dbusmenu_menuitem_get_children(_menu_desktop_shortcuts); l; l = l->next) + for (GList *l = dbusmenu_menuitem_get_children(menu_desktop_shortcuts_); l; l = l->next) { - _gsignals.Disconnect(l->data, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED); + glib_signals_.Disconnect(l->data, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED); } - _menu_desktop_shortcuts = nullptr; + menu_desktop_shortcuts_ = nullptr; } if (desktop_file.empty()) return; - _menu_desktop_shortcuts = dbusmenu_menuitem_new(); - dbusmenu_menuitem_set_root(_menu_desktop_shortcuts, TRUE); + menu_desktop_shortcuts_ = dbusmenu_menuitem_new(); + dbusmenu_menuitem_set_root(menu_desktop_shortcuts_, TRUE); // Build a desktop shortcuts object and tell it that our // environment is Unity to handle the filtering - _desktop_shortcuts = indicator_desktop_shortcuts_new(desktop_file.c_str(), "Unity"); + desktop_shortcuts_ = indicator_desktop_shortcuts_new(desktop_file.c_str(), "Unity"); // This will get us a list of the nicks available, it should // always be at least one entry of NULL if there either aren't // any or they're filtered for the environment we're in - const gchar** nicks = indicator_desktop_shortcuts_get_nicks(_desktop_shortcuts); + const gchar** nicks = indicator_desktop_shortcuts_get_nicks(desktop_shortcuts_); for (int index = 0; nicks[index]; ++index) { // Build a dbusmenu item for each nick that is the desktop // file that is built from it's name and includes a callback // to the desktop shortcuts object to execute the nick - glib::String name(indicator_desktop_shortcuts_nick_get_name(_desktop_shortcuts, + glib::String name(indicator_desktop_shortcuts_nick_get_name(desktop_shortcuts_, nicks[index])); glib::Object<DbusmenuMenuitem> item(dbusmenu_menuitem_new()); dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, name); @@ -789,16 +451,16 @@ void ApplicationLauncherIcon::UpdateDesktopQuickList() dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); auto nick = glib::gchar_to_string(nicks[index]); - _gsignals.Add<void, DbusmenuMenuitem*, gint>(item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + glib_signals_.Add<void, DbusmenuMenuitem*, gint>(item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this, nick] (DbusmenuMenuitem* item, unsigned timestamp) { GdkDisplay* display = gdk_display_get_default(); glib::Object<GdkAppLaunchContext> context(gdk_display_get_app_launch_context(display)); gdk_app_launch_context_set_timestamp(context, timestamp); auto gcontext = glib::object_cast<GAppLaunchContext>(context); - indicator_desktop_shortcuts_nick_exec_with_context(_desktop_shortcuts, nick.c_str(), gcontext); + indicator_desktop_shortcuts_nick_exec_with_context(desktop_shortcuts_, nick.c_str(), gcontext); }); - dbusmenu_menuitem_child_append(_menu_desktop_shortcuts, item); + dbusmenu_menuitem_child_append(menu_desktop_shortcuts_, item); } } @@ -821,60 +483,16 @@ void ApplicationLauncherIcon::UpdateBackgroundColor() } } -void ApplicationLauncherIcon::EnsureMenuItemsWindowsReady() -{ - // delete all menu items for windows - _menu_items_windows.clear(); - - auto const& windows = Windows(); - - // We only add quicklist menu-items for windows if we have more than one window - if (windows.size() < 2) - return; - - // add menu items for all open windows - for (auto const& w : windows) - { - auto const& title = w->title(); - - if (title.empty()) - continue; - - glib::Object<DbusmenuMenuitem> menu_item(dbusmenu_menuitem_new()); - dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, title.c_str()); - dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true); - dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true); - dbusmenu_menuitem_property_set_bool(menu_item, QuicklistMenuItem::MARKUP_ACCEL_DISABLED_PROPERTY, true); - dbusmenu_menuitem_property_set_int(menu_item, QuicklistMenuItem::MAXIMUM_LABEL_WIDTH_PROPERTY, MAXIMUM_QUICKLIST_WIDTH); - - Window xid = w->window_id(); - _gsignals.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - [xid] (DbusmenuMenuitem*, unsigned) { - WindowManager& wm = WindowManager::Default(); - wm.Activate(xid); - wm.Raise(xid); - }); - - if (w->active()) - { - dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, DBUSMENU_MENUITEM_TOGGLE_RADIO); - dbusmenu_menuitem_property_set_int(menu_item, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED); - } - - _menu_items_windows.push_back(menu_item); - } -} - void ApplicationLauncherIcon::EnsureMenuItemsStaticQuicklist() { // make a client for desktop file actions - if (!_menu_desktop_shortcuts.IsType(DBUSMENU_TYPE_MENUITEM)) + if (!menu_desktop_shortcuts_.IsType(DBUSMENU_TYPE_MENUITEM)) { UpdateDesktopQuickList(); } } -void ApplicationLauncherIcon::Quit() +void ApplicationLauncherIcon::Quit() const { app_->Quit(); } @@ -899,7 +517,7 @@ void ApplicationLauncherIcon::Stick(bool save) } else { - SimpleLauncherIcon::Stick(save); + WindowedLauncherIcon::Stick(save); if (save) LogUnityEvent(ApplicationEventType::ACCESS); @@ -912,11 +530,11 @@ void ApplicationLauncherIcon::UnStick() return; LogUnityEvent(ApplicationEventType::ACCESS); - SimpleLauncherIcon::UnStick(); + WindowedLauncherIcon::UnStick(); SetQuirk(Quirk::VISIBLE, app_->visible()); app_->sticky = false; - if (!app_->running()) + if (!IsRunning()) Remove(); } @@ -956,10 +574,10 @@ ApplicationSubjectPtr ApplicationLauncherIcon::GetSubject() void ApplicationLauncherIcon::EnsureMenuItemsDefaultReady() { - if (_menu_items.size() == MenuItemType::SIZE) + if (menu_items_.size() == MenuItemType::SIZE) return; - _menu_items.resize(MenuItemType::SIZE); + menu_items_.resize(MenuItemType::SIZE); /* (Un)Stick to Launcher */ glib::Object<DbusmenuMenuitem> menu_item(dbusmenu_menuitem_new()); @@ -968,12 +586,12 @@ void ApplicationLauncherIcon::EnsureMenuItemsDefaultReady() dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true); dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true); - _gsignals.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + glib_signals_.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, unsigned) { ToggleSticky(); }); - _menu_items[MenuItemType::STICK] = menu_item; + menu_items_[MenuItemType::STICK] = menu_item; /* Quit */ menu_item = dbusmenu_menuitem_new(); @@ -981,17 +599,17 @@ void ApplicationLauncherIcon::EnsureMenuItemsDefaultReady() dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true); dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true); - _gsignals.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + glib_signals_.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, unsigned) { Quit(); }); - _menu_items[MenuItemType::QUIT] = menu_item; + menu_items_[MenuItemType::QUIT] = menu_item; /* Separator */ menu_item = dbusmenu_menuitem_new(); dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); - _menu_items[MenuItemType::SEPARATOR] = menu_item; + menu_items_[MenuItemType::SEPARATOR] = menu_item; } AbstractLauncherIcon::MenuItemsVector ApplicationLauncherIcon::GetMenus() @@ -1003,7 +621,7 @@ AbstractLauncherIcon::MenuItemsVector ApplicationLauncherIcon::GetMenus() EnsureMenuItemsDefaultReady(); EnsureMenuItemsStaticQuicklist(); - for (auto const& menus : {GetRemoteMenus(), _menu_desktop_shortcuts}) + for (auto const& menus : {GetRemoteMenus(), menu_desktop_shortcuts_}) { if (!menus.IsType(DBUSMENU_TYPE_MENUITEM)) continue; @@ -1049,11 +667,11 @@ AbstractLauncherIcon::MenuItemsVector ApplicationLauncherIcon::GetMenus() if (separator_needed) { - result.push_back(_menu_items[MenuItemType::SEPARATOR]); + result.push_back(menu_items_[MenuItemType::SEPARATOR]); separator_needed = false; } - if (!_menu_items[MenuItemType::APP_NAME]) + if (!menu_items_[MenuItemType::APP_NAME]) { glib::String app_name(g_markup_escape_text(app_->title().c_str(), -1)); std::string bold_app_name("<b>"+app_name.Str()+"</b>"); @@ -1064,7 +682,7 @@ AbstractLauncherIcon::MenuItemsVector ApplicationLauncherIcon::GetMenus() dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE); dbusmenu_menuitem_property_set_bool(item, QuicklistMenuItem::MARKUP_ENABLED_PROPERTY, TRUE); - _gsignals.Add<void, DbusmenuMenuitem*, unsigned>(item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + glib_signals_.Add<void, DbusmenuMenuitem*, unsigned>(item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, unsigned timestamp) { _source_manager.AddIdle([this, timestamp] { ActivateLauncherIcon(ActionArg(ActionArg::Source::LAUNCHER, 0, timestamp)); @@ -1072,25 +690,23 @@ AbstractLauncherIcon::MenuItemsVector ApplicationLauncherIcon::GetMenus() }); }); - _menu_items[MenuItemType::APP_NAME] = item; + menu_items_[MenuItemType::APP_NAME] = item; } - result.push_back(_menu_items[MenuItemType::APP_NAME]); - result.push_back(_menu_items[MenuItemType::SEPARATOR]); + result.push_back(menu_items_[MenuItemType::APP_NAME]); + result.push_back(menu_items_[MenuItemType::SEPARATOR]); - EnsureMenuItemsWindowsReady(); + auto const& windows_menu_items = GetWindowsMenuItems(); - if (!_menu_items_windows.empty()) + if (!windows_menu_items.empty()) { - for (auto const& it : _menu_items_windows) - result.push_back(it); - - result.push_back(_menu_items[MenuItemType::SEPARATOR]); + result.insert(end(result), begin(windows_menu_items), end(windows_menu_items)); + result.push_back(menu_items_[MenuItemType::SEPARATOR]); } const char* label = !IsSticky() ? _("Lock to Launcher") : _("Unlock from Launcher"); - dbusmenu_menuitem_property_set(_menu_items[MenuItemType::STICK], DBUSMENU_MENUITEM_PROP_LABEL, label); - result.push_back(_menu_items[MenuItemType::STICK]); + dbusmenu_menuitem_property_set(menu_items_[MenuItemType::STICK], DBUSMENU_MENUITEM_PROP_LABEL, label); + result.push_back(menu_items_[MenuItemType::STICK]); if (IsRunning()) { @@ -1102,7 +718,7 @@ AbstractLauncherIcon::MenuItemsVector ApplicationLauncherIcon::GetMenus() dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true); dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true); - _gsignals.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + glib_signals_.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, unsigned) { app_->CreateLocalDesktopFile(); }); @@ -1111,7 +727,7 @@ AbstractLauncherIcon::MenuItemsVector ApplicationLauncherIcon::GetMenus() } if (!quit_item) - quit_item = _menu_items[MenuItemType::QUIT]; + quit_item = menu_items_[MenuItemType::QUIT]; dbusmenu_menuitem_property_set(quit_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Quit")); result.push_back(quit_item); @@ -1125,28 +741,7 @@ void ApplicationLauncherIcon::UpdateIconGeometries(std::vector<nux::Point3> cons if (app_->type() == AppType::WEBAPP) return; - nux::Geometry geo(0, 0, icon_size, icon_size); - - for (auto& window : app_->GetWindows()) - { - Window xid = window->window_id(); - int monitor = GetCenterForMonitor(window->monitor()).first; - - if (monitor < 0) - { - WindowManager::Default().SetWindowIconGeometry(xid, nux::Geometry()); - continue; - } - - geo.x = centers[monitor].x - icon_size / 2; - geo.y = centers[monitor].y - icon_size / 2; - WindowManager::Default().SetWindowIconGeometry(xid, geo); - } -} - -void ApplicationLauncherIcon::OnCenterStabilized(std::vector<nux::Point3> const& centers) -{ - UpdateIconGeometries(centers); + return WindowedLauncherIcon::UpdateIconGeometries(centers); } void ApplicationLauncherIcon::UpdateRemoteUri() @@ -1155,69 +750,21 @@ void ApplicationLauncherIcon::UpdateRemoteUri() if (!desktop_id.empty()) { - _remote_uri = FavoriteStore::URI_PREFIX_APP + desktop_id; + remote_uri_ = FavoriteStore::URI_PREFIX_APP + desktop_id; } else { - _remote_uri.clear(); + remote_uri_.clear(); } } std::string ApplicationLauncherIcon::GetRemoteUri() const { - return _remote_uri; -} - -void ApplicationLauncherIcon::OnDndEnter() -{ - auto timestamp = nux::GetGraphicsDisplay()->GetCurrentEvent().x11_timestamp; - - _source_manager.AddTimeout(1000, [this, timestamp] { - bool to_spread = GetWindows(WindowFilter::ON_CURRENT_DESKTOP).size() > 1; - - if (!to_spread) - WindowManager::Default().TerminateScale(); - - if (!IsRunning()) - return false; - - UBusManager::SendMessage(UBUS_OVERLAY_CLOSE_REQUEST); - Focus(ActionArg(ActionArg::Source::LAUNCHER, 1, timestamp)); - - if (to_spread) - Spread(true, COMPIZ_SCALE_DND_SPREAD, false); - - return false; - }, ICON_DND_OVER_TIMEOUT); -} - -void ApplicationLauncherIcon::OnDndLeave() -{ - _source_manager.Remove(ICON_DND_OVER_TIMEOUT); -} - -bool ApplicationLauncherIcon::IsFileManager() -{ - auto const& desktop_file = DesktopFile(); - - return boost::algorithm::ends_with(desktop_file, "org.gnome.Nautilus.desktop") || - boost::algorithm::ends_with(desktop_file, "nautilus.desktop") || - boost::algorithm::ends_with(desktop_file, "nautilus-folder-handler.desktop") || - boost::algorithm::ends_with(desktop_file, "nautilus-home.desktop"); + return remote_uri_; } bool ApplicationLauncherIcon::OnShouldHighlightOnDrag(DndData const& dnd_data) { - if (IsFileManager()) - { - for (auto const& uri : dnd_data.Uris()) - { - if (boost::algorithm::starts_with(uri, "file://")) - return true; - } - return false; - } - for (auto type : dnd_data.Types()) { for (auto supported_type : GetSupportedTypes()) @@ -1248,28 +795,6 @@ void ApplicationLauncherIcon::OnAcceptDrop(DndData const& dnd_data) OpenInstanceWithUris(dnd_data.Uris(), timestamp); } -bool ApplicationLauncherIcon::ShowInSwitcher(bool current) -{ - if (!removed() && IsRunning() && IsVisible()) - { - // If current is true, we only want to show the current workspace. - if (!current) - { - return true; - } - else - { - for (unsigned i = 0; i < monitors::MAX; ++i) - { - if (WindowVisibleOnMonitor(i)) - return true; - } - } - } - - return false; -} - bool ApplicationLauncherIcon::AllowDetailViewInSwitcher() const { return app_->type() != AppType::WEBAPP; @@ -1277,18 +802,11 @@ bool ApplicationLauncherIcon::AllowDetailViewInSwitcher() const uint64_t ApplicationLauncherIcon::SwitcherPriority() { - uint64_t result = 0; // Webapps always go at the back. if (app_->type() == AppType::WEBAPP) - return result; + return 0; - for (auto& window : app_->GetWindows()) - { - Window xid = window->window_id(); - result = std::max(result, WindowManager::Default().GetWindowActiveNumber(xid)); - } - - return result; + return WindowedLauncherIcon::SwitcherPriority(); } nux::Color ApplicationLauncherIcon::BackgroundColor() const @@ -1296,7 +814,7 @@ nux::Color ApplicationLauncherIcon::BackgroundColor() const if (use_custom_bg_color_) return bg_color_; - return SimpleLauncherIcon::BackgroundColor(); + return WindowedLauncherIcon::BackgroundColor(); } const std::set<std::string> ApplicationLauncherIcon::GetSupportedTypes() @@ -1312,102 +830,17 @@ const std::set<std::string> ApplicationLauncherIcon::GetSupportedTypes() return supported_types; } -void PerformScrollUp(WindowList const& windows, unsigned int progressive_scroll) -{ - if (progressive_scroll == windows.size() - 1) - { - //RestackAbove to preserve Global Stacking Order - WindowManager::Default().RestackBelow(windows.at(0)->window_id(), windows.at(1)->window_id()); - WindowManager::Default().RestackBelow(windows.at(1)->window_id(), windows.at(0)->window_id()); - windows.back()->Focus(); - return; - } - - WindowManager::Default().RestackBelow(windows.at(0)->window_id(), windows.at(progressive_scroll + 1)->window_id()); - windows.at(progressive_scroll + 1)->Focus(); -} - -void PerformScrollDown(WindowList const& windows, unsigned int progressive_scroll) -{ - if (!progressive_scroll) - { - WindowManager::Default().RestackBelow(windows.at(0)->window_id(), windows.back()->window_id()); - windows.at(1)->Focus(); - return; - } - - WindowManager::Default().RestackBelow(windows.at(0)->window_id(), windows.at(progressive_scroll)->window_id()); - windows.at(progressive_scroll)->Focus(); -} - -void ApplicationLauncherIcon::PerformScroll(ScrollDirection direction, Time timestamp) +std::string ApplicationLauncherIcon::GetName() const { - if (timestamp - _last_scroll_timestamp < 150) - return; - else if (timestamp - _last_scroll_timestamp > 1500) - _progressive_scroll = 0; - - _last_scroll_timestamp = timestamp; - - auto const& windows = GetWindowsOnCurrentDesktopInStackingOrder(); - - if (windows.empty()) - return; - - if (scroll_inactive_icons && !IsActive()) - { - windows.at(0)->Focus(); - return; - } - - if (!scroll_inactive_icons && !IsActive()) - return; - - if (windows.size() <= 1) - return; - - if (direction == ScrollDirection::DOWN) - ++_progressive_scroll; - else - //--_progressive_scroll; but roll to the top of windows - _progressive_scroll += windows.size() - 1; - _progressive_scroll %= windows.size(); - - switch(direction) - { - case ScrollDirection::UP: - PerformScrollUp(windows, _progressive_scroll); - break; - case ScrollDirection::DOWN: - PerformScrollDown(windows, _progressive_scroll); - break; - } + return "ApplicationLauncherIcon"; } -WindowList ApplicationLauncherIcon::GetWindowsOnCurrentDesktopInStackingOrder() +void ApplicationLauncherIcon::AddProperties(debug::IntrospectionData& introspection) { - auto windows = GetWindows(WindowFilter::ON_CURRENT_DESKTOP | WindowFilter::ON_ALL_MONITORS); - auto sorted_windows = WindowManager::Default().GetWindowsInStackingOrder(); - - // Order the windows - std::sort(windows.begin(), windows.end(), [&sorted_windows] (ApplicationWindowPtr const& win1, ApplicationWindowPtr const& win2) { - for (auto const& window : sorted_windows) - { - if (window == win1->window_id()) - return false; - else if (window == win2->window_id()) - return true; - } + WindowedLauncherIcon::AddProperties(introspection); - return true; - }); - - return windows; -} - -std::string ApplicationLauncherIcon::GetName() const -{ - return "ApplicationLauncherIcon"; + introspection.add("desktop_file", DesktopFile()) + .add("desktop_id", app_->desktop_id()); } } // namespace launcher diff --git a/launcher/ApplicationLauncherIcon.h b/launcher/ApplicationLauncherIcon.h index 2ea48c184..afdf0118e 100644 --- a/launcher/ApplicationLauncherIcon.h +++ b/launcher/ApplicationLauncherIcon.h @@ -1,6 +1,6 @@ // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* - * Copyright (C) 2010-2012 Canonical Ltd + * Copyright (C) 2010-2015 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as @@ -18,17 +18,15 @@ * Marco Trevisan (Treviño) <3v1n0@ubuntu.com> */ -#ifndef APPLICATIONLAUNCHERICON_H -#define APPLICATIONLAUNCHERICON_H +#ifndef APPLICATION_LAUNCHER_ICON_H +#define APPLICATION_LAUNCHER_ICON_H -#include <UnityCore/GLibSignal.h> -#include <UnityCore/GLibWrapper.h> #include <UnityCore/ConnectionManager.h> #include <UnityCore/Variant.h> #include <libindicator/indicator-desktop-shortcuts.h> -#include "SimpleLauncherIcon.h" +#include "WindowedLauncherIcon.h" namespace unity { @@ -37,115 +35,74 @@ namespace launcher class Launcher; -class ApplicationLauncherIcon : public SimpleLauncherIcon +class ApplicationLauncherIcon : public virtual WindowedLauncherIcon { - NUX_DECLARE_OBJECT_TYPE(ApplicationLauncherIcon, SimpleLauncherIcon); + NUX_DECLARE_OBJECT_TYPE(ApplicationLauncherIcon, WindowedLauncherIcon); public: - ApplicationLauncherIcon(ApplicationPtr const& app); + ApplicationLauncherIcon(ApplicationPtr const&); virtual ~ApplicationLauncherIcon(); - virtual void ActivateLauncherIcon(ActionArg arg); - std::string DesktopFile() const; - bool IsSticky() const; - bool IsActive() const; - bool IsRunning() const; - bool IsUrgent() const; - - virtual bool GetQuirk(Quirk quirk, int monitor = 0) const override; - - virtual void Quit(); - virtual void AboutToRemove(); - - virtual void Stick(bool save = true); - virtual void UnStick(); - - virtual bool ShowInSwitcher(bool current); - virtual bool AllowDetailViewInSwitcher() const override; - virtual uint64_t SwitcherPriority(); - - virtual nux::Color BackgroundColor() const; + bool IsSticky() const override; + bool IsUserVisible() const override; + bool GetQuirk(Quirk quirk, int monitor = 0) const override; - WindowList Windows(); - std::vector<Window> WindowsOnViewport(); - std::vector<Window> WindowsForMonitor(int monitor); + void Quit() const override; - void PerformScroll(ScrollDirection direction, Time timestamp) override; + void Stick(bool save = true) override; + void UnStick() override; protected: void SetApplication(ApplicationPtr const& app); ApplicationPtr GetApplication() const; - void Remove(); - void UpdateIconGeometries(std::vector<nux::Point3> const& centers); - void OnCenterStabilized(std::vector<nux::Point3> const& centers); - void AddProperties(debug::IntrospectionData&); - void OnAcceptDrop(DndData const& dnd_data); - void OnDndEnter(); - void OnDndLeave(); - void OpenInstanceLauncherIcon(Time timestamp) override; - void ToggleSticky(); - void LogUnityEvent(ApplicationEventType); - bool IsFileManager(); + WindowList GetManagedWindows() const override; - bool OnShouldHighlightOnDrag(DndData const& dnd_data); - nux::DndAction OnQueryAcceptDrop(DndData const& dnd_data); + void LogUnityEvent(ApplicationEventType); + void Remove(); - MenuItemsVector GetMenus(); + void AboutToRemove() override; + bool AllowDetailViewInSwitcher() const override; + uint64_t SwitcherPriority() override; + void UpdateIconGeometries(std::vector<nux::Point3> const& centers) override; + nux::Color BackgroundColor() const override; + MenuItemsVector GetMenus() override; + std::string GetRemoteUri() const override; - std::string GetRemoteUri() const; + void OpenInstanceLauncherIcon(Time timestamp) override; + void OpenInstanceWithUris(std::set<std::string> const& uris, Time timestamp); + void Focus(ActionArg arg) override; - bool HandlesSpread() { return true; } - std::string GetName() const; + void OnAcceptDrop(DndData const&) override; + bool OnShouldHighlightOnDrag(DndData const&) override; + nux::DndAction OnQueryAcceptDrop(DndData const&) override; - void UpdateDesktopFile(); - void UpdateRemoteUri(); - std::string _desktop_file; - -private: - typedef unsigned long int WindowFilterMask; - enum WindowFilter - { - MAPPED = (1 << 0), - USER_VISIBLE = (1 << 1), - ON_CURRENT_DESKTOP = (1 << 2), - ON_ALL_MONITORS = (1 << 3), - }; + std::string GetName() const override; + void AddProperties(debug::IntrospectionData&) override; void UnsetApplication(); void SetupApplicationSignalsConnections(); - void EnsureWindowState(); - void EnsureWindowsLocation(); - void EnsureMenuItemsWindowsReady(); void EnsureMenuItemsDefaultReady(); void EnsureMenuItemsStaticQuicklist(); void UpdateBackgroundColor(); void UpdateDesktopQuickList(); + void UpdateDesktopFile(); + void UpdateRemoteUri(); + void ToggleSticky(); + void OnApplicationClosed(); - void OpenInstanceWithUris(std::set<std::string> const& uris, Time timestamp); - void Focus(ActionArg arg); - bool Spread(bool current_desktop, int state, bool force); - - void OnWindowMinimized(guint32 xid); - - WindowList GetWindows(WindowFilterMask filter = 0, int monitor = -1); const std::set<std::string> GetSupportedTypes(); - WindowList GetWindowsOnCurrentDesktopInStackingOrder(); ApplicationSubjectPtr GetSubject(); ApplicationPtr app_; - std::string _remote_uri; - Time _startup_notification_timestamp; - Time _last_scroll_timestamp; - unsigned int _progressive_scroll; - std::set<std::string> _supported_types; - std::vector<glib::Object<DbusmenuMenuitem>> _menu_items; - std::vector<glib::Object<DbusmenuMenuitem>> _menu_items_windows; - glib::Object<IndicatorDesktopShortcuts> _desktop_shortcuts; - glib::Object<DbusmenuMenuitem> _menu_desktop_shortcuts; - glib::Object<GFileMonitor> _desktop_file_monitor; - glib::SignalManager _gsignals; + std::string remote_uri_; + Time startup_notification_timestamp_; + std::set<std::string> supported_types_; + MenuItemsVector menu_items_; + glib::Object<IndicatorDesktopShortcuts> desktop_shortcuts_; + glib::Object<DbusmenuMenuitem> menu_desktop_shortcuts_; + glib::Object<GFileMonitor> desktop_file_monitor_; bool use_custom_bg_color_; nux::Color bg_color_; @@ -153,7 +110,7 @@ private: connection::Manager signals_conn_; }; -} -} +} // namespace launcher +} // namespace unity -#endif // BAMFLAUNCHERICON_H +#endif // APPLICATION_LAUNCHER_ICON_H diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index f832a23e9..229d981c9 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -32,6 +32,7 @@ set (LAUNCHER_SOURCES FavoriteStore.cpp FavoriteStoreGSettings.cpp FavoriteStorePrivate.cpp + FileManagerLauncherIcon.cpp HudLauncherIcon.cpp Launcher.cpp LauncherController.cpp @@ -55,12 +56,14 @@ set (LAUNCHER_SOURCES SingleMonitorLauncherIcon.cpp SoftwareCenterLauncherIcon.cpp SpacerLauncherIcon.cpp + StorageLauncherIcon.cpp Tooltip.cpp TooltipManager.cpp TrashLauncherIcon.cpp VolumeImp.cpp VolumeLauncherIcon.cpp VolumeMonitorWrapper.cpp + WindowedLauncherIcon.cpp XdndCollectionWindowImp.cpp XdndManagerImp.cpp XdndStartStopNotifier.cpp diff --git a/launcher/DesktopLauncherIcon.cpp b/launcher/DesktopLauncherIcon.cpp index cec293077..df9a982aa 100644 --- a/launcher/DesktopLauncherIcon.cpp +++ b/launcher/DesktopLauncherIcon.cpp @@ -77,5 +77,10 @@ bool DesktopLauncherIcon::ShowInSwitcher(bool current) return show_in_switcher_; } +uint64_t DesktopLauncherIcon::SwitcherPriority() +{ + return std::numeric_limits<uint64_t>::max(); +} + } // namespace launcher } // namespace unity diff --git a/launcher/DesktopLauncherIcon.h b/launcher/DesktopLauncherIcon.h index 6778b59a6..c17099165 100644 --- a/launcher/DesktopLauncherIcon.h +++ b/launcher/DesktopLauncherIcon.h @@ -37,6 +37,7 @@ public: protected: void ActivateLauncherIcon(ActionArg arg); + uint64_t SwitcherPriority() override; std::string GetName() const; std::string GetRemoteUri() const; diff --git a/launcher/DeviceLauncherSection.h b/launcher/DeviceLauncherSection.h index 358b405c4..7824cca79 100644 --- a/launcher/DeviceLauncherSection.h +++ b/launcher/DeviceLauncherSection.h @@ -37,10 +37,14 @@ namespace launcher class DeviceLauncherSection : public sigc::trackable { public: + typedef std::shared_ptr<DeviceLauncherSection> Ptr; + DeviceLauncherSection(AbstractVolumeMonitorWrapper::Ptr const& volume_monitor = nullptr, DevicesSettings::Ptr const& devices_settings = nullptr, DeviceNotificationDisplay::Ptr const& notifications = nullptr); + virtual ~DeviceLauncherSection() = default; + std::vector<VolumeLauncherIcon::Ptr> GetIcons() const; sigc::signal<void, AbstractLauncherIcon::Ptr const&> icon_added; diff --git a/launcher/FileManagerLauncherIcon.cpp b/launcher/FileManagerLauncherIcon.cpp new file mode 100644 index 000000000..d5895ad0f --- /dev/null +++ b/launcher/FileManagerLauncherIcon.cpp @@ -0,0 +1,128 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2015 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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 General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Marco Trevisan <marco.trevisan@canonical.com> + */ + +#include "FileManagerLauncherIcon.h" + +#include <boost/algorithm/string.hpp> +#include <NuxCore/Logger.h> +#include <UnityCore/DesktopUtilities.h> + +#include "unity-shared/GnomeFileManager.h" + +namespace unity +{ +namespace launcher +{ +namespace +{ +DECLARE_LOGGER(logger, "unity.launcher.icon.filemanager"); +const std::string TRASH_URI = "trash:"; +const std::string TRASH_PATH = "file://" + DesktopUtilities::GetUserTrashDirectory(); +const std::string DEFAULT_ICON = "system-file-manager"; +} + +FileManagerLauncherIcon::FileManagerLauncherIcon(ApplicationPtr const& app, DeviceLauncherSection::Ptr const& dev, FileManager::Ptr const& fm) + : WindowedLauncherIcon(IconType::APPLICATION) + , ApplicationLauncherIcon(app) + , StorageLauncherIcon(GetIconType(), fm ? fm : GnomeFileManager::Get()) + , devices_(dev) +{ + // We disconnect from ApplicationLauncherIcon app signals, as we manage them manually + signals_conn_.Clear(); + + signals_conn_.Add(app_->desktop_file.changed.connect([this](std::string const& desktop_file) { + LOG_DEBUG(logger) << tooltip_text() << " desktop_file now " << desktop_file; + UpdateDesktopFile(); + })); + + signals_conn_.Add(app_->closed.connect([this] { + LOG_DEBUG(logger) << tooltip_text() << " closed"; + OnApplicationClosed(); + })); + + signals_conn_.Add(app_->title.changed.connect([this](std::string const& name) { + LOG_DEBUG(logger) << tooltip_text() << " name now " << name; + menu_items_.clear(); + tooltip_text = name; + })); + + signals_conn_.Add(app_->icon.changed.connect([this](std::string const& icon) { + LOG_DEBUG(logger) << tooltip_text() << " icon now " << icon; + icon_name = (icon.empty() ? DEFAULT_ICON : icon); + })); + + UpdateStorageWindows(); +} + +void FileManagerLauncherIcon::Focus(ActionArg arg) +{ + WindowedLauncherIcon::Focus(arg); +} + +void FileManagerLauncherIcon::Quit() const +{ + WindowedLauncherIcon::Quit(); +} + +bool FileManagerLauncherIcon::IsLocationManaged(std::string const& location) const +{ + if (location.empty()) + return true; + + if (boost::algorithm::starts_with(location, TRASH_URI)) + return false; + + if (boost::algorithm::starts_with(location, TRASH_PATH)) + return false; + + for (auto const& volume_icon : devices_->GetIcons()) + { + auto const& volume_uri = volume_icon->GetVolumeUri(); + if (!volume_uri.empty() && boost::algorithm::starts_with(location, volume_uri)) + return false; + } + + return true; +} + +WindowList FileManagerLauncherIcon::GetManagedWindows() const +{ + return StorageLauncherIcon::GetManagedWindows(); +} + +WindowList FileManagerLauncherIcon::GetStorageWindows() const +{ + WindowList fm_windows; + + for (auto const& app_win : ApplicationLauncherIcon::GetManagedWindows()) + { + if (IsLocationManaged(file_manager_->LocationForWindow(app_win))) + fm_windows.push_back(app_win); + } + + return fm_windows; +} + +bool FileManagerLauncherIcon::OnShouldHighlightOnDrag(DndData const& dnd_data) +{ + return StorageLauncherIcon::OnShouldHighlightOnDrag(dnd_data); +} + +} // namespace launcher +} // namespace unity diff --git a/launcher/FileManagerLauncherIcon.h b/launcher/FileManagerLauncherIcon.h new file mode 100644 index 000000000..1996747a3 --- /dev/null +++ b/launcher/FileManagerLauncherIcon.h @@ -0,0 +1,52 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2015 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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 General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Marco Trevisan <marco.trevisan@canonical.com> + */ + +#ifndef FILEMANAGER_LAUNCHER_ICON_H +#define FILEMANAGER_LAUNCHER_ICON_H + +#include "ApplicationLauncherIcon.h" +#include "StorageLauncherIcon.h" +#include "DeviceLauncherSection.h" + +namespace unity +{ +namespace launcher +{ + +class FileManagerLauncherIcon : public ApplicationLauncherIcon, public StorageLauncherIcon +{ +public: + FileManagerLauncherIcon(ApplicationPtr const&, DeviceLauncherSection::Ptr const&, FileManager::Ptr const& = nullptr); + +private: + WindowList GetManagedWindows() const override; + WindowList GetStorageWindows() const override; + void Focus(ActionArg arg) override; + void Quit() const override; + bool OnShouldHighlightOnDrag(DndData const& dnd_data) override; + + bool IsLocationManaged(std::string const&) const; + + DeviceLauncherSection::Ptr devices_; +}; + +} // namespace launcher +} // namespace unity + +#endif // FILEMANAGER_LAUNCHER_ICON_H diff --git a/launcher/Launcher.cpp b/launcher/Launcher.cpp index 6a45d23cf..e4bdb6212 100644 --- a/launcher/Launcher.cpp +++ b/launcher/Launcher.cpp @@ -598,16 +598,9 @@ void Launcher::SetupRenderArg(AbstractLauncherIcon::Ptr const& icon, RenderArg& else { if (options()->show_for_all) - arg.window_indicators = std::max<int> (icon->WindowsOnViewport().size(), 1); + arg.window_indicators = std::max<int>(icon->WindowsVisibleOnViewport(), 1); else - arg.window_indicators = std::max<int> (icon->WindowsForMonitor(monitor).size(), 1); - - if (icon->GetIconType() == AbstractLauncherIcon::IconType::TRASH || - icon->GetIconType() == AbstractLauncherIcon::IconType::DEVICE) - { - // TODO: also these icons should respect the actual windows they have - arg.window_indicators = 0; - } + arg.window_indicators = std::max<int>(icon->WindowsVisibleOnMonitor(monitor), 1); } arg.backlight_intensity = IconBackgroundIntensity(icon); diff --git a/launcher/LauncherController.cpp b/launcher/LauncherController.cpp index e74b0fa90..a40b452bc 100644 --- a/launcher/LauncherController.cpp +++ b/launcher/LauncherController.cpp @@ -21,6 +21,7 @@ #include "config.h" #include <glib/gi18n-lib.h> +#include <boost/algorithm/string.hpp> #include <Nux/Nux.h> #include <Nux/HLayout.h> @@ -32,6 +33,8 @@ #include "DesktopLauncherIcon.h" #include "VolumeLauncherIcon.h" #include "FavoriteStore.h" +#include "FileManagerLauncherIcon.h" +#include "HudLauncherIcon.h" #include "LauncherController.h" #include "LauncherControllerPrivate.h" #include "SoftwareCenterLauncherIcon.h" @@ -100,13 +103,13 @@ std::string CreateAppUriNameFromDesktopPath(const std::string &desktop_path) return FavoriteStore::URI_PREFIX_APP + DesktopUtilities::GetDesktopID(desktop_path); } - } Controller::Impl::Impl(Controller* parent, XdndManager::Ptr const& xdnd_manager, ui::EdgeBarrierController::Ptr const& edge_barriers) : parent_(parent) , model_(std::make_shared<LauncherModel>()) , xdnd_manager_(xdnd_manager) + , device_section_(std::make_shared<DeviceLauncherSection>()) , bfb_icon_(new BFBLauncherIcon()) , hud_icon_(new HudLauncherIcon()) , expo_icon_(new ExpoLauncherIcon()) @@ -350,6 +353,21 @@ Launcher* Controller::Impl::CreateLauncher() return launcher; } +ApplicationLauncherIcon* Controller::Impl::CreateAppLauncherIcon(ApplicationPtr const& app) +{ + auto const& desktop_file = app->desktop_file(); + + if (boost::algorithm::ends_with(desktop_file, "org.gnome.Nautilus.desktop") || + boost::algorithm::ends_with(desktop_file, "nautilus.desktop") || + boost::algorithm::ends_with(desktop_file, "nautilus-folder-handler.desktop") || + boost::algorithm::ends_with(desktop_file, "nautilus-home.desktop")) + { + return new FileManagerLauncherIcon(app, device_section_); + } + + return new ApplicationLauncherIcon(app); +} + void Controller::Impl::OnLauncherAddRequest(std::string const& icon_uri, AbstractLauncherIcon::Ptr const& icon_before) { std::string app_uri; @@ -846,7 +864,7 @@ void Controller::Impl::OnApplicationStarted(ApplicationPtr const& app) if (app->sticky() || app->seen()) return; - AbstractLauncherIcon::Ptr icon(new ApplicationLauncherIcon(app)); + AbstractLauncherIcon::Ptr icon(CreateAppLauncherIcon(app)); RegisterIcon(icon, GetLastIconPriority<ApplicationLauncherIcon>(local::RUNNING_APPS_URI)); } @@ -883,11 +901,11 @@ AbstractLauncherIcon::Ptr Controller::Impl::CreateFavoriteIcon(std::string const if (!app || app->seen()) return result; - result = AbstractLauncherIcon::Ptr(new ApplicationLauncherIcon(app)); + result = AbstractLauncherIcon::Ptr(CreateAppLauncherIcon(app)); } else if (icon_uri.find(FavoriteStore::URI_PREFIX_DEVICE) == 0) { - auto const& devices = device_section_.GetIcons(); + auto const& devices = device_section_->GetIcons(); auto const& icon = std::find_if(devices.begin(), devices.end(), [&icon_uri](AbstractLauncherIcon::Ptr const& i) { return (i->RemoteUri() == icon_uri); }); @@ -962,7 +980,7 @@ void Controller::Impl::AddRunningApps() << (app->seen() ? "yes" : "no"); if (!app->seen()) { - AbstractLauncherIcon::Ptr icon(new ApplicationLauncherIcon(app)); + AbstractLauncherIcon::Ptr icon(CreateAppLauncherIcon(app)); icon->SkipQuirkAnimation(AbstractLauncherIcon::Quirk::VISIBLE); RegisterIcon(icon, ++sort_priority_); } @@ -972,7 +990,7 @@ void Controller::Impl::AddRunningApps() void Controller::Impl::AddDevices() { auto& fav_store = FavoriteStore::Instance(); - for (auto const& icon : device_section_.GetIcons()) + for (auto const& icon : device_section_->GetIcons()) { if (!icon->IsSticky() && !fav_store.IsFavorite(icon->RemoteUri())) { @@ -1052,7 +1070,7 @@ void Controller::Impl::SetupIcons() ApplicationManager::Default().application_started .connect(sigc::mem_fun(this, &Impl::OnApplicationStarted)); - device_section_.icon_added.connect(sigc::mem_fun(this, &Impl::OnDeviceIconAdded)); + device_section_->icon_added.connect(sigc::mem_fun(this, &Impl::OnDeviceIconAdded)); favorite_store.favorite_added.connect(sigc::mem_fun(this, &Impl::OnFavoriteStoreFavoriteAdded)); favorite_store.favorite_removed.connect(sigc::mem_fun(this, &Impl::OnFavoriteStoreFavoriteRemoved)); favorite_store.reordered.connect(sigc::mem_fun(this, &Impl::ResetIconPriorities)); diff --git a/launcher/LauncherControllerPrivate.h b/launcher/LauncherControllerPrivate.h index 02d639d80..a1400b94f 100644 --- a/launcher/LauncherControllerPrivate.h +++ b/launcher/LauncherControllerPrivate.h @@ -88,6 +88,7 @@ public: void RegisterIcon(AbstractLauncherIcon::Ptr const& icon, int priority = std::numeric_limits<int>::min()); + ApplicationLauncherIcon* CreateAppLauncherIcon(ApplicationPtr const&); AbstractLauncherIcon::Ptr CreateFavoriteIcon(std::string const& icon_uri, bool emit_signal = false); AbstractLauncherIcon::Ptr GetIconByUri(std::string const& icon_uri); SoftwareCenterLauncherIcon::Ptr CreateSCLauncherIcon(std::string const& file_path, std::string const& aptdaemon_trans_id, std::string const& icon_path); @@ -123,7 +124,7 @@ public: nux::ObjectPtr<Launcher> launcher_; nux::ObjectPtr<Launcher> keyboard_launcher_; XdndManager::Ptr xdnd_manager_; - DeviceLauncherSection device_section_; + DeviceLauncherSection::Ptr device_section_; LauncherEntryRemoteModel remote_model_; BFBLauncherIcon* bfb_icon_; HudLauncherIcon* hud_icon_; diff --git a/launcher/LauncherIcon.cpp b/launcher/LauncherIcon.cpp index cfa34c3d7..6dd163a9a 100644 --- a/launcher/LauncherIcon.cpp +++ b/launcher/LauncherIcon.cpp @@ -150,16 +150,26 @@ void LauncherIcon::LoadQuicklist() QuicklistManager::Default()->RegisterQuicklist(_quicklist); } -const bool LauncherIcon::WindowVisibleOnMonitor(int monitor) +bool LauncherIcon::WindowVisibleOnMonitor(int monitor) const { return _has_visible_window[monitor]; } -const bool LauncherIcon::WindowVisibleOnViewport() +bool LauncherIcon::WindowVisibleOnViewport() const { return _has_visible_window.any(); } +size_t LauncherIcon::WindowsVisibleOnMonitor(int monitor) const +{ + return _number_of_visible_windows[monitor]; +} + +size_t LauncherIcon::WindowsVisibleOnViewport() const +{ + return std::accumulate(begin(_number_of_visible_windows), end(_number_of_visible_windows), 0); +} + std::string LauncherIcon::GetName() const { diff --git a/launcher/LauncherIcon.h b/launcher/LauncherIcon.h index 65af7e08f..d42668ed5 100644 --- a/launcher/LauncherIcon.h +++ b/launcher/LauncherIcon.h @@ -82,7 +82,7 @@ public: nux::Point3 GetCenter(int monitor); - virtual void Activate(ActionArg arg); + void Activate(ActionArg arg); void OpenInstance(ActionArg arg); @@ -94,15 +94,19 @@ public: void SetOrder(int order); - virtual WindowList Windows() { return WindowList(); } + WindowList Windows() { return WindowList(); } - virtual std::vector<Window> WindowsOnViewport() { return std::vector<Window> (); } + WindowList WindowsOnViewport() { return WindowList(); } - virtual std::vector<Window> WindowsForMonitor(int monitor) { return std::vector<Window> (); } + WindowList WindowsForMonitor(int monitor) { return WindowList(); } - const bool WindowVisibleOnMonitor(int monitor); + bool WindowVisibleOnMonitor(int monitor) const; - const bool WindowVisibleOnViewport(); + bool WindowVisibleOnViewport() const; + + size_t WindowsVisibleOnMonitor(int monitor) const; + + size_t WindowsVisibleOnViewport() const; float PresentUrgency(); diff --git a/launcher/MockLauncherIcon.h b/launcher/MockLauncherIcon.h index 335f1e64b..1dae29cd8 100644 --- a/launcher/MockLauncherIcon.h +++ b/launcher/MockLauncherIcon.h @@ -112,34 +112,34 @@ public: return result; } - std::vector<Window> WindowsOnViewport () + WindowList WindowsOnViewport() { - std::vector<Window> result; + WindowList result; - result.push_back ((100 << 16) + 200); - result.push_back ((500 << 16) + 200); - result.push_back ((300 << 16) + 200); - result.push_back ((200 << 16) + 200); - result.push_back ((300 << 16) + 200); - result.push_back ((100 << 16) + 200); - result.push_back ((300 << 16) + 200); - result.push_back ((600 << 16) + 200); + result.push_back(std::make_shared<MockApplicationWindow>((100 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((500 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((300 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((200 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((300 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((100 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((300 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((600 << 16) + 200)); return result; } - std::vector<Window> WindowsForMonitor (int monitor) + WindowList WindowsForMonitor(int monitor) { - std::vector<Window> result; + WindowList result; - result.push_back ((100 << 16) + 200); - result.push_back ((500 << 16) + 200); - result.push_back ((300 << 16) + 200); - result.push_back ((200 << 16) + 200); - result.push_back ((300 << 16) + 200); - result.push_back ((100 << 16) + 200); - result.push_back ((300 << 16) + 200); - result.push_back ((600 << 16) + 200); + result.push_back(std::make_shared<MockApplicationWindow>((100 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((500 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((300 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((200 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((300 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((100 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((300 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((600 << 16) + 200)); return result; } @@ -194,16 +194,26 @@ public: return 7; } - const bool WindowVisibleOnViewport() + bool WindowVisibleOnViewport() const { return false; } - const bool WindowVisibleOnMonitor(int monitor) + bool WindowVisibleOnMonitor(int monitor) const { return false; } + size_t WindowsVisibleOnMonitor(int monitor) const + { + return 0; + } + + size_t WindowsVisibleOnViewport() const + { + return 0; + } + void SetVisibleOnMonitor(int monitor, bool visible) {} bool IsVisibleOnMonitor(int monitor) const diff --git a/launcher/SoftwareCenterLauncherIcon.cpp b/launcher/SoftwareCenterLauncherIcon.cpp index 72c96d033..9a2605ebc 100644 --- a/launcher/SoftwareCenterLauncherIcon.cpp +++ b/launcher/SoftwareCenterLauncherIcon.cpp @@ -47,7 +47,8 @@ NUX_IMPLEMENT_OBJECT_TYPE(SoftwareCenterLauncherIcon); SoftwareCenterLauncherIcon::SoftwareCenterLauncherIcon(ApplicationPtr const& app, std::string const& aptdaemon_trans_id, std::string const& icon_path) - : ApplicationLauncherIcon(app) + : WindowedLauncherIcon(IconType::APPLICATION) + , ApplicationLauncherIcon(app) , aptdaemon_trans_(std::make_shared<glib::DBusProxy>("org.debian.apt", aptdaemon_trans_id, "org.debian.apt.transaction", diff --git a/launcher/StorageLauncherIcon.cpp b/launcher/StorageLauncherIcon.cpp new file mode 100644 index 000000000..fcc367b72 --- /dev/null +++ b/launcher/StorageLauncherIcon.cpp @@ -0,0 +1,119 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2015 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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 General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Marco Trevisan <marco.trevisan@canonical.com> + */ + +#include "StorageLauncherIcon.h" + +namespace unity +{ +namespace launcher +{ + +StorageLauncherIcon::StorageLauncherIcon(AbstractLauncherIcon::IconType icon_type, FileManager::Ptr const& fm) + : WindowedLauncherIcon(icon_type) + , file_manager_(fm) +{ + file_manager_->locations_changed.connect(sigc::mem_fun(this, &StorageLauncherIcon::UpdateStorageWindows)); +} + +void StorageLauncherIcon::UpdateStorageWindows() +{ + bool active = false; + bool urgent = false; + bool check_visibility = (GetIconType() == IconType::APPLICATION); + bool visible = IsSticky(); + + managed_windows_ = GetStorageWindows(); + windows_connections_.Clear(); + + for (auto const& win : managed_windows_) + { + windows_connections_.Add(win->monitor.changed.connect([this] (int) { EnsureWindowsLocation(); })); + windows_connections_.Add(win->urgent.changed.connect([this] (bool) { OnWindowStateChanged(); })); + windows_connections_.Add(win->active.changed.connect([this] (bool) { OnWindowStateChanged(); })); + windows_connections_.Add(win->closed.connect([this] { UpdateStorageWindows(); })); + + if (!active && win->active()) + active = true; + + if (!urgent && win->urgent()) + urgent = true; + + if (check_visibility) + { + windows_connections_.Add(win->visible.changed.connect([this] (bool) { OnWindowStateChanged(); })); + + if (!visible && win->visible()) + visible = true; + } + } + + SetQuirk(Quirk::RUNNING, !managed_windows_.empty()); + SetQuirk(Quirk::ACTIVE, active); + SetQuirk(Quirk::URGENT, urgent); + + if (check_visibility) + SetQuirk(Quirk::VISIBLE, visible); + + EnsureWindowsLocation(); +} + +WindowList StorageLauncherIcon::GetManagedWindows() const +{ + return managed_windows_; +} + +void StorageLauncherIcon::OnWindowStateChanged() +{ + bool active = false; + bool urgent = false; + bool check_visibility = (GetIconType() == IconType::APPLICATION); + bool visible = IsSticky(); + + for (auto const& win : managed_windows_) + { + if (!active && win->active()) + active = true; + + if (!urgent && win->urgent()) + urgent = true; + + if (check_visibility && !visible && win->visible()) + visible = true; + } + + SetQuirk(Quirk::ACTIVE, active); + SetQuirk(Quirk::URGENT, urgent); + + if (check_visibility) + SetQuirk(Quirk::VISIBLE, visible); +} + +bool StorageLauncherIcon::OnShouldHighlightOnDrag(DndData const& dnd_data) +{ + for (auto const& uri : dnd_data.Uris()) + { + if (uri.find("file://") == 0) + return true; + } + + return false; +} + +} // namespace launcher +} // namespace unity diff --git a/launcher/StorageLauncherIcon.h b/launcher/StorageLauncherIcon.h new file mode 100644 index 000000000..a552f88d5 --- /dev/null +++ b/launcher/StorageLauncherIcon.h @@ -0,0 +1,55 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2015 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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 General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Marco Trevisan <marco.trevisan@canonical.com> + */ + +#ifndef STORAGE_LAUNCHER_ICON_H +#define STORAGE_LAUNCHER_ICON_H + +#include "WindowedLauncherIcon.h" +#include "unity-shared/FileManager.h" + +namespace unity +{ +namespace launcher +{ + +class StorageLauncherIcon : public virtual WindowedLauncherIcon +{ +public: + StorageLauncherIcon(AbstractLauncherIcon::IconType, FileManager::Ptr const&); + +protected: + void UpdateStorageWindows(); + WindowList GetManagedWindows() const override; + virtual WindowList GetStorageWindows() const = 0; + + bool OnShouldHighlightOnDrag(DndData const& dnd_data) override; + +private: + void OnWindowStateChanged(); + +protected: + FileManager::Ptr file_manager_; + WindowList managed_windows_; + connection::Manager windows_connections_; +}; + +} // namespace launcher +} // namespace unity + +#endif // STORAGE_LAUNCHER_ICON_H diff --git a/launcher/SwitcherController.cpp b/launcher/SwitcherController.cpp index 9b9711218..5f9c6e3f0 100644 --- a/launcher/SwitcherController.cpp +++ b/launcher/SwitcherController.cpp @@ -325,11 +325,18 @@ void Controller::Impl::Show(ShowMode show_mode, SortMode sort_mode, std::vector< model_->selection_changed.connect(sigc::mem_fun(this, &Controller::Impl::OnModelSelectionChanged)); model_->detail_selection.changed.connect([this] (bool) { sources_.Remove(DETAIL_TIMEOUT); }); model_->updated.connect([this] { if (!model_->Size()) Hide(false); }); - obj_->AddChild(model_.get()); + + if (!model_->Size()) + { + model_.reset(); + return; + } SelectFirstItem(); + obj_->AddChild(model_.get()); obj_->visible_ = true; + int real_wait = obj_->timeout_length() - fade_animator_.Duration(); if (real_wait > 0) @@ -442,7 +449,6 @@ void Controller::Impl::ConstructView() sources_.Remove(VIEW_CONSTRUCT_IDLE); view_ = SwitcherView::Ptr(new SwitcherView(icon_renderer_)); - obj_->AddChild(view_.GetPointer()); view_->SetModel(model_); view_->background_color = WindowManager::Default().average_color(); view_->monitor = obj_->monitor_; @@ -462,6 +468,7 @@ void Controller::Impl::ConstructView() view_->switcher_start_detail.connect(sigc::mem_fun(this, &Impl::StartDetailMode)); view_->switcher_stop_detail.connect(sigc::mem_fun(this, &Impl::StopDetailMode)); view_->switcher_close_current.connect(sigc::mem_fun(this, &Impl::CloseSelection)); + obj_->AddChild(view_.GetPointer()); ConstructWindow(); main_layout_->AddView(view_.GetPointer(), 1); @@ -507,6 +514,9 @@ void Controller::Impl::HideWindow() view_window_->ShowWindow(false); view_window_->PushToBack(); + obj_->RemoveChild(model_.get()); + obj_->RemoveChild(view_.GetPointer()); + model_.reset(); view_.Release(); } @@ -720,14 +730,11 @@ void Controller::Impl::SelectFirstItem() uint64_t second_first = 0; // second icons first highest active WindowManager& wm = WindowManager::Default(); - for (auto& window : first->Windows()) - { - Window xid = window->window_id(); - - if (model_->only_apps_on_viewport && !wm.IsWindowOnCurrentDesktop(xid)) - continue; + auto const& windows = (model_->only_apps_on_viewport) ? first->WindowsOnViewport() : first->Windows(); - uint64_t num = wm.GetWindowActiveNumber(xid); + for (auto& window : windows) + { + uint64_t num = wm.GetWindowActiveNumber(window->window_id()); if (num > first_highest) { diff --git a/launcher/SwitcherModel.cpp b/launcher/SwitcherModel.cpp index df3264328..4d8889435 100644 --- a/launcher/SwitcherModel.cpp +++ b/launcher/SwitcherModel.cpp @@ -37,16 +37,7 @@ namespace bool CompareSwitcherItemsPriority(AbstractLauncherIcon::Ptr const& first, AbstractLauncherIcon::Ptr const& second) { - if (first->GetIconType() == second->GetIconType()) - return first->SwitcherPriority() > second->SwitcherPriority(); - - if (first->GetIconType() == AbstractLauncherIcon::IconType::DESKTOP) - return true; - - if (second->GetIconType() == AbstractLauncherIcon::IconType::DESKTOP) - return false; - - return first->GetIconType() < second->GetIconType(); + return first->SwitcherPriority() > second->SwitcherPriority(); } } @@ -174,7 +165,7 @@ void SwitcherModel::ConnectToIconSignals(launcher::AbstractLauncherIcon::Ptr con void SwitcherModel::AddIcon(AbstractLauncherIcon::Ptr const& icon) { - if (!icon || icon->GetIconType() != AbstractLauncherIcon::IconType::APPLICATION) + if (!icon) return; if (icon->ShowInSwitcher(only_apps_on_viewport)) @@ -318,7 +309,7 @@ size_t SwitcherModel::Size() const AbstractLauncherIcon::Ptr SwitcherModel::Selection() const { - return applications_.at(index_); + return index_ < applications_.size() ? applications_.at(index_) : AbstractLauncherIcon::Ptr(); } int SwitcherModel::SelectionIndex() const @@ -328,7 +319,8 @@ int SwitcherModel::SelectionIndex() const bool SwitcherModel::SelectionIsActive() const { - return Selection()->GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE); + auto const& selection = Selection(); + return selection ? selection->GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE) : false; } AbstractLauncherIcon::Ptr SwitcherModel::LastSelection() const @@ -353,8 +345,12 @@ std::vector<Window> SwitcherModel::SelectionWindows() const WindowManager& wm = WindowManager::Default(); std::vector<Window> results; + auto const& selection = Selection(); + + if (!selection) + return results; - for (auto& window : Selection()->Windows()) + for (auto& window : selection->Windows()) { Window xid = window->window_id(); @@ -369,7 +365,7 @@ std::vector<Window> SwitcherModel::SelectionWindows() const return wm.GetWindowActiveNumber(first) > wm.GetWindowActiveNumber(second); }); - if (Selection() == last_active_application_) + if (selection == last_active_application_) { results.push_back(results.front()); results.erase(results.begin()); @@ -406,6 +402,9 @@ void SwitcherModel::UnsetDetailSelection() void SwitcherModel::NextIndex() { + if (applications_.empty()) + return; + last_index_ = index_; ++index_ %= applications_.size(); } @@ -419,6 +418,9 @@ void SwitcherModel::Next() void SwitcherModel::PrevIndex() { + if (applications_.empty()) + return; + last_index_ = index_; index_ = ((index_ > 0 && index_ < applications_.size()) ? index_ : applications_.size()) - 1; } @@ -432,7 +434,7 @@ void SwitcherModel::Prev() void SwitcherModel::NextDetail() { - if (!detail_selection()) + if (!detail_selection() || detail_xids_.empty()) return; detail_selection_index = (detail_selection_index + 1) % detail_xids_.size(); @@ -441,7 +443,7 @@ void SwitcherModel::NextDetail() void SwitcherModel::PrevDetail() { - if (!detail_selection()) + if (!detail_selection() || detail_xids_.empty()) return; detail_selection_index = ((detail_selection_index() > 0) ? detail_selection_index : detail_xids_.size()) - 1; diff --git a/launcher/SwitcherView.cpp b/launcher/SwitcherView.cpp index b81eeef5d..302901ba4 100644 --- a/launcher/SwitcherView.cpp +++ b/launcher/SwitcherView.cpp @@ -538,7 +538,7 @@ RenderArg SwitcherView::CreateBaseArgForIcon(AbstractLauncherIcon::Ptr const& ic // tells the renderer to render arrows by number arg.running_on_viewport = true; - arg.window_indicators = icon->WindowsForMonitor(monitor).size(); + arg.window_indicators = icon->WindowsVisibleOnMonitor(monitor); if (arg.window_indicators > 1) arg.running_arrow = true; else diff --git a/launcher/TrashLauncherIcon.cpp b/launcher/TrashLauncherIcon.cpp index fdc540e43..b8239aabd 100644 --- a/launcher/TrashLauncherIcon.cpp +++ b/launcher/TrashLauncherIcon.cpp @@ -1,6 +1,6 @@ // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* - * Copyright (C) 2010-2013 Canonical Ltd + * Copyright (C) 2010-2015 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as @@ -24,6 +24,7 @@ #include "config.h" #include <glib/gi18n-lib.h> #include <NuxCore/Logger.h> +#include <UnityCore/DesktopUtilities.h> #include <zeitgeist.h> #include "QuicklistMenuItemLabel.h" @@ -39,20 +40,19 @@ namespace DECLARE_LOGGER(logger, "unity.launcher.icon.trash"); const std::string ZEITGEIST_UNITY_ACTOR = "application://compiz.desktop"; const std::string TRASH_URI = "trash:"; + const std::string TRASH_PATH = "file://" + DesktopUtilities::GetUserTrashDirectory(); } -TrashLauncherIcon::TrashLauncherIcon(FileManager::Ptr const& fmo) - : SimpleLauncherIcon(IconType::TRASH) +TrashLauncherIcon::TrashLauncherIcon(FileManager::Ptr const& fm) + : WindowedLauncherIcon(IconType::TRASH) + , StorageLauncherIcon(GetIconType(), fm ? fm : GnomeFileManager::Get()) , empty_(true) - , file_manager_(fmo ? fmo : GnomeFileManager::Get()) { tooltip_text = _("Trash"); icon_name = "user-trash"; position = Position::END; SetQuirk(Quirk::VISIBLE, true); SkipQuirkAnimation(Quirk::VISIBLE); - - SetQuirk(Quirk::RUNNING, file_manager_->IsTrashOpened()); SetShortcut('t'); glib::Object<GFile> location(g_file_new_for_uri(TRASH_URI.c_str())); @@ -67,20 +67,27 @@ TrashLauncherIcon::TrashLauncherIcon(FileManager::Ptr const& fmo) } else { - trash_changed_signal_.Connect(trash_monitor_, "changed", + glib_signals_.Add<void, GFileMonitor*, GFile*, GFile*, GFileMonitorEvent>(trash_monitor_, "changed", [this] (GFileMonitor*, GFile*, GFile*, GFileMonitorEvent) { UpdateTrashIcon(); }); } - file_manager_->locations_changed.connect(sigc::mem_fun(this, &TrashLauncherIcon::OnOpenedLocationsChanged)); - UpdateTrashIcon(); + UpdateStorageWindows(); +} + +WindowList TrashLauncherIcon::GetStorageWindows() const +{ + auto windows = file_manager_->WindowsForLocation(TRASH_URI); + auto const& path_wins = file_manager_->WindowsForLocation(TRASH_PATH); + windows.insert(end(windows), begin(path_wins), end(path_wins)); + return windows; } -void TrashLauncherIcon::OnOpenedLocationsChanged() +void TrashLauncherIcon::OpenInstanceLauncherIcon(Time timestamp) { - SetQuirk(Quirk::RUNNING, file_manager_->IsTrashOpened()); + file_manager_->OpenTrash(timestamp); } AbstractLauncherIcon::MenuItemsVector TrashLauncherIcon::GetMenus() @@ -92,20 +99,41 @@ AbstractLauncherIcon::MenuItemsVector TrashLauncherIcon::GetMenus() dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Empty Trash…")); dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, !empty_); dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true); - empty_activated_signal_.Connect(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + glib_signals_.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, unsigned timestamp) { file_manager_->EmptyTrash(timestamp); }); result.push_back(menu_item); - return result; -} + if (IsRunning()) + { + auto const& windows_items = GetWindowsMenuItems(); + if (!windows_items.empty()) + { + menu_item = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); + result.push_back(menu_item); -void TrashLauncherIcon::ActivateLauncherIcon(ActionArg arg) -{ - SimpleLauncherIcon::ActivateLauncherIcon(arg); - file_manager_->OpenTrash(arg.timestamp); + result.insert(end(result), begin(windows_items), end(windows_items)); + } + + menu_item = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); + result.push_back(menu_item); + + menu_item = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Quit")); + dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true); + dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true); + result.push_back(menu_item); + + glib_signals_.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) { + Quit(); + }); + } + + return result; } void TrashLauncherIcon::UpdateTrashIcon() diff --git a/launcher/TrashLauncherIcon.h b/launcher/TrashLauncherIcon.h index 24a2622e3..3b32cd572 100644 --- a/launcher/TrashLauncherIcon.h +++ b/launcher/TrashLauncherIcon.h @@ -23,9 +23,10 @@ #include <gio/gio.h> #include <UnityCore/GLibWrapper.h> #include <UnityCore/GLibSignal.h> +#include <UnityCore/ConnectionManager.h> #include "DndData.h" -#include "SimpleLauncherIcon.h" +#include "StorageLauncherIcon.h" #include "unity-shared/FileManager.h" namespace unity @@ -33,7 +34,7 @@ namespace unity namespace launcher { -class TrashLauncherIcon : public SimpleLauncherIcon +class TrashLauncherIcon : public StorageLauncherIcon { public: TrashLauncherIcon(FileManager::Ptr const& = nullptr); @@ -45,21 +46,18 @@ protected: bool OnShouldHighlightOnDrag(DndData const& dnd_data); void OnAcceptDrop(DndData const& dnd_data); + WindowList GetStorageWindows() const override; std::string GetName() const; private: - void ActivateLauncherIcon(ActionArg arg); - void OnOpenedLocationsChanged(); + void OpenInstanceLauncherIcon(Time timestamp) override; MenuItemsVector GetMenus(); static void UpdateTrashIconCb(GObject* source, GAsyncResult* res, gpointer data); bool empty_; - FileManager::Ptr file_manager_; glib::Cancellable cancellable_; glib::Object<GFileMonitor> trash_monitor_; - glib::Signal<void, GFileMonitor*, GFile*, GFile*, GFileMonitorEvent> trash_changed_signal_; - glib::Signal<void, DbusmenuMenuitem*, unsigned> empty_activated_signal_; }; } diff --git a/launcher/VolumeLauncherIcon.cpp b/launcher/VolumeLauncherIcon.cpp index 8f09be7c7..85eee27fc 100644 --- a/launcher/VolumeLauncherIcon.cpp +++ b/launcher/VolumeLauncherIcon.cpp @@ -49,7 +49,7 @@ public: , volume_(volume) , devices_settings_(devices_settings) , notification_(notification) - , file_manager_(fm) + , file_manager_(parent_->file_manager_) { UpdateIcon(); UpdateVisibility(); @@ -60,48 +60,41 @@ public: { parent_->tooltip_text = volume_->GetName(); parent_->icon_name = volume_->GetIconName(); - parent_->SetQuirk(Quirk::RUNNING, file_manager_->IsPrefixOpened(volume_->GetUri())); } void UpdateVisibility() { - UpdateKeepInLauncher(); - parent_->SetQuirk(Quirk::VISIBLE, keep_in_launcher_); + parent_->SetQuirk(Quirk::VISIBLE, IsVisible()); } - void UpdateKeepInLauncher() + bool IsBlackListed() { - auto const& identifier = volume_->GetIdentifier(); - keep_in_launcher_ = !devices_settings_->IsABlacklistedDevice(identifier); + return devices_settings_->IsABlacklistedDevice(volume_->GetIdentifier()); } - void ConnectSignals() + bool IsVisible() { - connections_.Add(volume_->changed.connect(sigc::mem_fun(this, &Impl::OnVolumeChanged))); - connections_.Add(volume_->removed.connect(sigc::mem_fun(this, &Impl::OnVolumeRemoved))); - connections_.Add(devices_settings_->changed.connect(sigc::mem_fun(this, &Impl::OnSettingsChanged))); - connections_.Add(file_manager_->locations_changed.connect(sigc::mem_fun(this, &Impl::UpdateIcon))); + if (IsBlackListed() && parent_->GetManagedWindows().empty()) + return false; + + return true; } - void OnVolumeChanged() + void ConnectSignals() { - UpdateIcon(); + connections_.Add(volume_->changed.connect([this] { UpdateIcon(); })); + connections_.Add(volume_->removed.connect(sigc::mem_fun(this, &Impl::OnVolumeRemoved))); + connections_.Add(devices_settings_->changed.connect([this] { UpdateVisibility(); })); + connections_.Add(parent_->windows_changed.connect([this] (int) { UpdateVisibility(); })); } void OnVolumeRemoved() { - if (devices_settings_->IsABlacklistedDevice(volume_->GetIdentifier())) - devices_settings_->TryToUnblacklist(volume_->GetIdentifier()); - + devices_settings_->TryToUnblacklist(volume_->GetIdentifier()); parent_->UnStick(); parent_->Remove(); } - void OnSettingsChanged() - { - UpdateVisibility(); - } - bool CanEject() const { return volume_->CanBeEjected(); @@ -152,7 +145,7 @@ public: void OpenInFileManager(uint64_t timestamp) { DoActionWhenMounted([this, timestamp] { - file_manager_->OpenActiveChild(volume_->GetUri(), timestamp); + file_manager_->Open(volume_->GetUri(), timestamp); }); } @@ -171,29 +164,38 @@ public: AppendSeparatorItem(result); AppendNameItem(result); AppendSeparatorItem(result); - AppendUnlockFromLauncherItem(result); + AppendWindowsItems(result); + AppendToggleLockFromLauncherItem(result); AppendEjectItem(result); AppendSafelyRemoveItem(result); AppendUnmountItem(result); + AppendQuitItem(result); return result; } - void AppendUnlockFromLauncherItem(MenuItemsVector& menu) + void AppendToggleLockFromLauncherItem(MenuItemsVector& menu) { if (volume_->GetIdentifier().empty()) return; glib::Object<DbusmenuMenuitem> menu_item(dbusmenu_menuitem_new()); - dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Unlock from Launcher")); + const char* label = IsBlackListed() ? _("Lock to Launcher") : _("Unlock from Launcher"); + dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, label); dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true); dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true); - gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) { - auto const& identifier = volume_->GetIdentifier(); - parent_->UnStick(); - devices_settings_->TryToBlacklist(identifier); + parent_->glib_signals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) { + if (!IsBlackListed()) + { + parent_->UnStick(); + devices_settings_->TryToBlacklist(volume_->GetIdentifier()); + } + else + { + devices_settings_->TryToUnblacklist(volume_->GetIdentifier()); + } })); menu.push_back(menu_item); @@ -220,13 +222,26 @@ public: dbusmenu_menuitem_property_set_bool(menu_item, QuicklistMenuItem::MARKUP_ENABLED_PROPERTY, true); dbusmenu_menuitem_property_set_bool(menu_item, QuicklistMenuItem::MARKUP_ACCEL_DISABLED_PROPERTY, true); - gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, unsigned timestamp) { + parent_->glib_signals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, unsigned timestamp) { OpenInFileManager(timestamp); })); menu.push_back(menu_item); } + void AppendWindowsItems(MenuItemsVector& menu) + { + if (!parent_->IsRunning()) + return; + + auto const& windows_items = parent_->GetWindowsMenuItems(); + if (!windows_items.empty()) + { + menu.insert(end(menu), begin(windows_items), end(windows_items)); + AppendSeparatorItem(menu); + } + } + void AppendOpenItem(MenuItemsVector& menu) { glib::Object<DbusmenuMenuitem> menu_item(dbusmenu_menuitem_new()); @@ -235,7 +250,7 @@ public: dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true); dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true); - gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, unsigned timestamp) { + parent_->glib_signals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, unsigned timestamp) { OpenInFileManager(timestamp); })); @@ -253,7 +268,8 @@ public: dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true); dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true); - gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) { + parent_->glib_signals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) { + parent_->Quit(); EjectAndShowNotification(); })); @@ -271,8 +287,9 @@ public: dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true); dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true); - gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) { - volume_->StopDrive(); + parent_->glib_signals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) { + parent_->Quit(); + volume_->StopDrive(); })); menu.push_back(menu_item); @@ -289,8 +306,29 @@ public: dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true); dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true); - gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) { - volume_->Unmount(); + parent_->glib_signals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) { + volume_->Unmount(); + })); + + menu.push_back(menu_item); + } + + void AppendQuitItem(MenuItemsVector& menu) + { + if (!parent_->IsRunning()) + return; + + if (!menu.empty()) + AppendSeparatorItem(menu); + + glib::Object<DbusmenuMenuitem> menu_item(dbusmenu_menuitem_new()); + + dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Quit")); + dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true); + dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true); + + parent_->glib_signals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) { + parent_->Quit(); })); menu.push_back(menu_item); @@ -307,13 +345,10 @@ public: } VolumeLauncherIcon* parent_; - bool keep_in_launcher_; Volume::Ptr volume_; DevicesSettings::Ptr devices_settings_; DeviceNotificationDisplay::Ptr notification_; FileManager::Ptr file_manager_; - - glib::SignalManager gsignals_; connection::Manager connections_; }; @@ -325,15 +360,20 @@ VolumeLauncherIcon::VolumeLauncherIcon(Volume::Ptr const& volume, DevicesSettings::Ptr const& devices_settings, DeviceNotificationDisplay::Ptr const& notification, FileManager::Ptr const& fm) - : SimpleLauncherIcon(IconType::DEVICE) + : WindowedLauncherIcon(IconType::DEVICE) + , StorageLauncherIcon(GetIconType(), fm) , pimpl_(new Impl(volume, devices_settings, notification, fm, this)) -{} +{ + UpdateStorageWindows(); +} VolumeLauncherIcon::~VolumeLauncherIcon() {} void VolumeLauncherIcon::AboutToRemove() { + StorageLauncherIcon::AboutToRemove(); + if (CanEject()) EjectAndShowNotification(); else if (CanStop()) @@ -360,12 +400,6 @@ void VolumeLauncherIcon::StopDrive() return pimpl_->StopDrive(); } -void VolumeLauncherIcon::ActivateLauncherIcon(ActionArg arg) -{ - SimpleLauncherIcon::ActivateLauncherIcon(arg); - pimpl_->OpenInFileManager(arg.timestamp); -} - AbstractLauncherIcon::MenuItemsVector VolumeLauncherIcon::GetMenus() { return pimpl_->GetMenus(); @@ -388,17 +422,6 @@ void VolumeLauncherIcon::UnStick() SetQuirk(Quirk::VISIBLE, true); } -bool VolumeLauncherIcon::OnShouldHighlightOnDrag(DndData const& dnd_data) -{ - for (auto const& uri : dnd_data.Uris()) - { - if (uri.find("file://") == 0) - return true; - } - - return false; -} - nux::DndAction VolumeLauncherIcon::OnQueryAcceptDrop(DndData const& dnd_data) { return dnd_data.Uris().empty() ? nux::DNDACTION_NONE : nux::DNDACTION_COPY; @@ -412,6 +435,21 @@ void VolumeLauncherIcon::OnAcceptDrop(DndData const& dnd_data) FullyAnimateQuirkDelayed(100, LauncherIcon::Quirk::SHIMMER); } +std::string VolumeLauncherIcon::GetVolumeUri() const +{ + return pimpl_->volume_->GetUri(); +} + +WindowList VolumeLauncherIcon::GetStorageWindows() const +{ + return file_manager_->WindowsForLocation(GetVolumeUri()); +} + +void VolumeLauncherIcon::OpenInstanceLauncherIcon(Time timestamp) +{ + pimpl_->OpenInFileManager(timestamp); +} + // // Introspection // diff --git a/launcher/VolumeLauncherIcon.h b/launcher/VolumeLauncherIcon.h index a78e2199c..3322db26c 100644 --- a/launcher/VolumeLauncherIcon.h +++ b/launcher/VolumeLauncherIcon.h @@ -24,7 +24,7 @@ #include "Volume.h" #include "DevicesSettings.h" #include "DeviceNotificationDisplay.h" -#include "SimpleLauncherIcon.h" +#include "StorageLauncherIcon.h" #include "unity-shared/FileManager.h" namespace unity @@ -32,7 +32,7 @@ namespace unity namespace launcher { -class VolumeLauncherIcon : public SimpleLauncherIcon +class VolumeLauncherIcon : public StorageLauncherIcon { public: typedef nux::ObjectPtr<VolumeLauncherIcon> Ptr; @@ -41,7 +41,7 @@ public: DeviceNotificationDisplay::Ptr const&, FileManager::Ptr const&); virtual ~VolumeLauncherIcon(); - virtual void AboutToRemove(); + void AboutToRemove() override; bool CanEject() const; // TODO: rename to public virtual bool IsTrashable(); void EjectAndShowNotification(); // TODO: rename to private virtual void DoDropToTrash(); @@ -49,14 +49,16 @@ public: void StopDrive(); void Stick(bool save = true); void UnStick(); + MenuItemsVector GetMenus(); std::string GetRemoteUri() const; + std::string GetVolumeUri() const; protected: - void ActivateLauncherIcon(ActionArg arg); - bool OnShouldHighlightOnDrag(DndData const&); void OnAcceptDrop(DndData const&); nux::DndAction OnQueryAcceptDrop(DndData const&); + WindowList GetStorageWindows() const override; + void OpenInstanceLauncherIcon(Time timestamp) override; // Introspection virtual std::string GetName() const; diff --git a/launcher/WindowedLauncherIcon.cpp b/launcher/WindowedLauncherIcon.cpp new file mode 100644 index 000000000..efffb81ac --- /dev/null +++ b/launcher/WindowedLauncherIcon.cpp @@ -0,0 +1,618 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2015 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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 General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Marco Trevisan <marco.trevisan@canonical.com> + */ + +#include <Nux/Nux.h> + +#include "WindowedLauncherIcon.h" +#include "MultiMonitor.h" +#include "unity-shared/UBusWrapper.h" +#include "unity-shared/UBusMessages.h" +#include "unity-shared/UScreen.h" + +namespace unity +{ +namespace launcher +{ +namespace +{ +const std::string ICON_DND_OVER_TIMEOUT = "windowed-icon-dnd-over"; +const int COMPIZ_SCALE_DND_SPREAD = 1 << 7; +const int MAXIMUM_QUICKLIST_WIDTH = 300; +} + +NUX_IMPLEMENT_OBJECT_TYPE(WindowedLauncherIcon); + +WindowedLauncherIcon::WindowedLauncherIcon(AbstractLauncherIcon::IconType icon_type) + : SimpleLauncherIcon(icon_type) + , last_scroll_timestamp_(0) + , progressive_scroll_(0) +{ + WindowManager& wm = WindowManager::Default(); + wm.window_minimized.connect(sigc::mem_fun(this, &WindowedLauncherIcon::OnWindowMinimized)); + wm.screen_viewport_switch_ended.connect(sigc::mem_fun(this, &WindowedLauncherIcon::EnsureWindowState)); + wm.terminate_expo.connect(sigc::mem_fun(this, &WindowedLauncherIcon::EnsureWindowState)); + UScreen::GetDefault()->changed.connect(sigc::hide(sigc::hide(sigc::mem_fun(this, &WindowedLauncherIcon::EnsureWindowsLocation)))); + + windows_changed.connect([this] (int) { + if (WindowManager::Default().IsScaleActiveForGroup() && IsActive()) + Spread(true, 0, false); + }); +} + +bool WindowedLauncherIcon::IsActive() const +{ + return GetQuirk(Quirk::ACTIVE); +} + +bool WindowedLauncherIcon::IsRunning() const +{ + return GetQuirk(Quirk::RUNNING); +} + +bool WindowedLauncherIcon::IsUrgent() const +{ + return GetQuirk(Quirk::URGENT); +} + +bool WindowedLauncherIcon::IsUserVisible() const +{ + return IsRunning(); +} + +void WindowedLauncherIcon::ActivateLauncherIcon(ActionArg arg) +{ + SimpleLauncherIcon::ActivateLauncherIcon(arg); + WindowManager& wm = WindowManager::Default(); + + // This is a little awkward as the target is only set from the switcher. + if (arg.target) + { + // thumper: should we Raise too? should the WM raise? + wm.Activate(arg.target); + return; + } + + bool scale_was_active = wm.IsScaleActive(); + bool active = IsActive(); + bool user_visible = IsRunning(); + /* We should check each child to see if there is + * an unmapped (!= minimized) window around and + * if so force "Focus" behaviour */ + + if (arg.source != ActionArg::Source::SWITCHER) + { + user_visible = IsUserVisible(); + + if (active) + { + bool any_visible = false; + bool any_mapped = false; + bool any_on_top = false; + bool any_on_monitor = (arg.monitor < 0); + int active_monitor = arg.monitor; + + for (auto const& window : GetManagedWindows()) + { + Window xid = window->window_id(); + + if (!any_visible && wm.IsWindowOnCurrentDesktop(xid)) + { + any_visible = true; + } + + if (!any_mapped && wm.IsWindowMapped(xid)) + { + any_mapped = true; + } + + if (!any_on_top && wm.IsWindowOnTop(xid)) + { + any_on_top = true; + } + + if (!any_on_monitor && window->monitor() == arg.monitor && + wm.IsWindowMapped(xid) && wm.IsWindowVisible(xid)) + { + any_on_monitor = true; + } + + if (window->active()) + { + active_monitor = window->monitor(); + } + } + + if (!any_visible || !any_mapped || !any_on_top) + active = false; + + if (any_on_monitor && arg.monitor >= 0 && active_monitor != arg.monitor) + active = false; + } + } + + /* Behaviour: + * 1) Nothing running, or nothing visible -> launch application + * 2) Running and active -> spread application + * 3) Running and not active -> focus application + * 4) Spread is active and different icon pressed -> change spread + * 5) Spread is active -> Spread de-activated, and fall through + */ + + if (!IsRunning() || (IsRunning() && !user_visible)) // #1 above + { + if (GetQuirk(Quirk::STARTING, arg.monitor)) + return; + + wm.TerminateScale(); + SetQuirk(Quirk::STARTING, true, arg.monitor); + OpenInstanceLauncherIcon(arg.timestamp); + } + else // container is running + { + if (active) + { + if (scale_was_active) // #5 above + { + wm.TerminateScale(); + + if (minimize_window_on_click()) + { + for (auto const& win : GetWindows(WindowFilter::ON_CURRENT_DESKTOP)) + wm.Minimize(win->window_id()); + } + else + { + Focus(arg); + } + } + else // #2 above + { + if (arg.source != ActionArg::Source::SWITCHER) + { + bool minimized = false; + + if (minimize_window_on_click()) + { + WindowList const& windows = GetWindows(WindowFilter::ON_CURRENT_DESKTOP); + + if (windows.size() == 1) + { + wm.Minimize(windows[0]->window_id()); + minimized = true; + } + } + + if (!minimized) + { + Spread(true, 0, false); + } + } + } + } + else + { + if (scale_was_active) // #4 above + { + if (GetWindows(WindowFilter::ON_CURRENT_DESKTOP).size() <= 1) + wm.TerminateScale(); + + Focus(arg); + + if (arg.source != ActionArg::Source::SWITCHER) + Spread(true, 0, false); + } + else // #3 above + { + Focus(arg); + } + } + } +} + +WindowList WindowedLauncherIcon::GetWindows(WindowFilterMask filter, int monitor) +{ + if ((!filter && monitor < 0) || (filter == WindowFilter::ON_ALL_MONITORS)) + return GetManagedWindows(); + + WindowManager& wm = WindowManager::Default(); + WindowList results; + + monitor = (filter & WindowFilter::ON_ALL_MONITORS) ? -1 : monitor; + bool mapped = (filter & WindowFilter::MAPPED); + bool user_visible = (filter & WindowFilter::USER_VISIBLE); + bool current_desktop = (filter & WindowFilter::ON_CURRENT_DESKTOP); + + for (auto& window : GetManagedWindows()) + { + if ((monitor >= 0 && window->monitor() == monitor) || monitor < 0) + { + if ((user_visible && window->visible()) || !user_visible) + { + Window xid = window->window_id(); + + if ((mapped && wm.IsWindowMapped(xid)) || !mapped) + { + if ((current_desktop && wm.IsWindowOnCurrentDesktop(xid)) || !current_desktop) + { + results.push_back(window); + } + } + } + } + } + + return results; +} + +WindowList WindowedLauncherIcon::Windows() +{ + return GetWindows(WindowFilter::MAPPED|WindowFilter::ON_ALL_MONITORS); +} + +WindowList WindowedLauncherIcon::WindowsOnViewport() +{ + WindowFilterMask filter = 0; + filter |= WindowFilter::MAPPED; + filter |= WindowFilter::USER_VISIBLE; + filter |= WindowFilter::ON_CURRENT_DESKTOP; + filter |= WindowFilter::ON_ALL_MONITORS; + + return GetWindows(filter); +} + +WindowList WindowedLauncherIcon::WindowsForMonitor(int monitor) +{ + WindowFilterMask filter = 0; + filter |= WindowFilter::MAPPED; + filter |= WindowFilter::USER_VISIBLE; + filter |= WindowFilter::ON_CURRENT_DESKTOP; + + return GetWindows(filter, monitor); +} + +void WindowedLauncherIcon::OnWindowMinimized(Window xid) +{ + for (auto const& window : GetManagedWindows()) + { + if (xid == window->window_id()) + { + int monitor = GetCenterForMonitor(window->monitor()).first; + + if (monitor >= 0) + { + Present(0.5f, 600, monitor); + FullyAnimateQuirkDelayed(300, Quirk::SHIMMER, monitor); + } + + break; + } + } +} + +void WindowedLauncherIcon::Focus(ActionArg arg) +{ + bool show_only_visible = (arg.source == ActionArg::Source::SWITCHER); + ApplicationManager::Default().FocusWindowGroup(GetManagedWindows(), show_only_visible, arg.monitor); +} + +bool WindowedLauncherIcon::Spread(bool current_desktop, int state, bool force) +{ + std::vector<Window> windows; + for (auto& window : GetWindows(current_desktop ? WindowFilter::ON_CURRENT_DESKTOP : 0)) + windows.push_back(window->window_id()); + + return WindowManager::Default().ScaleWindowGroup(windows, state, force); +} + +void WindowedLauncherIcon::EnsureWindowState() +{ + std::vector<int> number_of_windows_on_monitor(monitors::MAX); + + for (auto const& window : WindowsOnViewport()) + { + int monitor = window->monitor(); + + // If monitor is -1 (or negative), show on all monitors. + if (monitor < 0) + { + for (unsigned j; j < monitors::MAX; ++j) + ++number_of_windows_on_monitor[j]; + } + else + { + ++number_of_windows_on_monitor[monitor]; + } + } + + for (unsigned i = 0; i < monitors::MAX; ++i) + SetNumberOfWindowsVisibleOnMonitor(number_of_windows_on_monitor[i], i); +} + +void WindowedLauncherIcon::EnsureWindowsLocation() +{ + EnsureWindowState(); + UpdateIconGeometries(GetCenters()); +} + +void WindowedLauncherIcon::UpdateIconGeometries(std::vector<nux::Point3> const& centers) +{ + nux::Geometry geo(0, 0, icon_size, icon_size); + + for (auto& window : GetManagedWindows()) + { + Window xid = window->window_id(); + int monitor = GetCenterForMonitor(window->monitor()).first; + + if (monitor < 0) + { + WindowManager::Default().SetWindowIconGeometry(xid, nux::Geometry()); + continue; + } + + geo.x = centers[monitor].x - icon_size / 2; + geo.y = centers[monitor].y - icon_size / 2; + WindowManager::Default().SetWindowIconGeometry(xid, geo); + } +} + +void WindowedLauncherIcon::OnCenterStabilized(std::vector<nux::Point3> const& centers) +{ + UpdateIconGeometries(centers); +} + +void WindowedLauncherIcon::OnDndEnter() +{ + auto timestamp = nux::GetGraphicsDisplay()->GetCurrentEvent().x11_timestamp; + + _source_manager.AddTimeout(1000, [this, timestamp] { + bool to_spread = GetWindows(WindowFilter::ON_CURRENT_DESKTOP).size() > 1; + + if (!to_spread) + WindowManager::Default().TerminateScale(); + + if (!IsRunning()) + return false; + + UBusManager::SendMessage(UBUS_OVERLAY_CLOSE_REQUEST); + Focus(ActionArg(ActionArg::Source::LAUNCHER, 1, timestamp)); + + if (to_spread) + Spread(true, COMPIZ_SCALE_DND_SPREAD, false); + + return false; + }, ICON_DND_OVER_TIMEOUT); +} + +void WindowedLauncherIcon::OnDndLeave() +{ + _source_manager.Remove(ICON_DND_OVER_TIMEOUT); +} + +bool WindowedLauncherIcon::HandlesSpread() +{ + return true; +} + +bool WindowedLauncherIcon::ShowInSwitcher(bool current) +{ + if (!removed() && IsRunning() && IsVisible()) + { + // If current is true, we only want to show the current workspace. + if (!current) + { + return true; + } + else + { + for (unsigned i = 0; i < monitors::MAX; ++i) + { + if (WindowVisibleOnMonitor(i)) + return true; + } + } + } + + return false; +} + +bool WindowedLauncherIcon::AllowDetailViewInSwitcher() const +{ + return true; +} + +uint64_t WindowedLauncherIcon::SwitcherPriority() +{ + uint64_t result = 0; + + for (auto& window : GetManagedWindows()) + { + Window xid = window->window_id(); + result = std::max(result, WindowManager::Default().GetWindowActiveNumber(xid)); + } + + return result; +} + +void PerformScrollUp(WindowList const& windows, unsigned int progressive_scroll) +{ + if (progressive_scroll == windows.size() - 1) + { + //RestackAbove to preserve Global Stacking Order + WindowManager::Default().RestackBelow(windows.at(0)->window_id(), windows.at(1)->window_id()); + WindowManager::Default().RestackBelow(windows.at(1)->window_id(), windows.at(0)->window_id()); + windows.back()->Focus(); + return; + } + + WindowManager::Default().RestackBelow(windows.at(0)->window_id(), windows.at(progressive_scroll + 1)->window_id()); + windows.at(progressive_scroll + 1)->Focus(); +} + +void PerformScrollDown(WindowList const& windows, unsigned int progressive_scroll) +{ + if (!progressive_scroll) + { + WindowManager::Default().RestackBelow(windows.at(0)->window_id(), windows.back()->window_id()); + windows.at(1)->Focus(); + return; + } + + WindowManager::Default().RestackBelow(windows.at(0)->window_id(), windows.at(progressive_scroll)->window_id()); + windows.at(progressive_scroll)->Focus(); +} + +void WindowedLauncherIcon::PerformScroll(ScrollDirection direction, Time timestamp) +{ + if (timestamp - last_scroll_timestamp_ < 150) + return; + else if (timestamp - last_scroll_timestamp_ > 1500) + progressive_scroll_ = 0; + + last_scroll_timestamp_ = timestamp; + + auto const& windows = GetWindowsOnCurrentDesktopInStackingOrder(); + + if (windows.empty()) + return; + + if (scroll_inactive_icons && !IsActive()) + { + windows.at(0)->Focus(); + return; + } + + if (!scroll_inactive_icons && !IsActive()) + return; + + if (windows.size() <= 1) + return; + + if (direction == ScrollDirection::DOWN) + ++progressive_scroll_; + else + //--progressive_scroll_; but roll to the top of windows + progressive_scroll_ += windows.size() - 1; + progressive_scroll_ %= windows.size(); + + switch(direction) + { + case ScrollDirection::UP: + PerformScrollUp(windows, progressive_scroll_); + break; + case ScrollDirection::DOWN: + PerformScrollDown(windows, progressive_scroll_); + break; + } +} + +WindowList WindowedLauncherIcon::GetWindowsOnCurrentDesktopInStackingOrder() +{ + auto windows = GetWindows(WindowFilter::ON_CURRENT_DESKTOP | WindowFilter::ON_ALL_MONITORS); + auto sorted_windows = WindowManager::Default().GetWindowsInStackingOrder(); + + // Order the windows + std::sort(windows.begin(), windows.end(), [&sorted_windows] (ApplicationWindowPtr const& win1, ApplicationWindowPtr const& win2) { + for (auto const& window : sorted_windows) + { + if (window == win1->window_id()) + return false; + else if (window == win2->window_id()) + return true; + } + + return true; + }); + + return windows; +} + +void WindowedLauncherIcon::Quit() const +{ + for (auto& window : GetManagedWindows()) + window->Quit(); +} + +void WindowedLauncherIcon::AboutToRemove() +{ + Quit(); +} + +AbstractLauncherIcon::MenuItemsVector WindowedLauncherIcon::GetWindowsMenuItems() +{ + auto const& windows = Windows(); + MenuItemsVector menu_items; + + // We only add quicklist menu-items for windows if we have more than one window + if (windows.size() < 2) + return menu_items; + + // add menu items for all open windows + for (auto const& w : windows) + { + auto const& title = w->title(); + + if (title.empty()) + continue; + + glib::Object<DbusmenuMenuitem> menu_item(dbusmenu_menuitem_new()); + dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, title.c_str()); + dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true); + dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true); + dbusmenu_menuitem_property_set_bool(menu_item, QuicklistMenuItem::MARKUP_ACCEL_DISABLED_PROPERTY, true); + dbusmenu_menuitem_property_set_int(menu_item, QuicklistMenuItem::MAXIMUM_LABEL_WIDTH_PROPERTY, MAXIMUM_QUICKLIST_WIDTH); + + Window xid = w->window_id(); + glib_signals_.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + [xid] (DbusmenuMenuitem*, unsigned) { + WindowManager& wm = WindowManager::Default(); + wm.Activate(xid); + wm.Raise(xid); + }); + + if (w->active()) + { + dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, DBUSMENU_MENUITEM_TOGGLE_RADIO); + dbusmenu_menuitem_property_set_int(menu_item, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED); + } + + menu_items.push_back(menu_item); + } + + return menu_items; +} + +std::string WindowedLauncherIcon::GetName() const +{ + return "WindowedLauncherIcon"; +} + +void WindowedLauncherIcon::AddProperties(debug::IntrospectionData& introspection) +{ + SimpleLauncherIcon::AddProperties(introspection); + + std::vector<Window> xids; + for (auto const& window : GetManagedWindows()) + xids.push_back(window->window_id()); + + introspection.add("xids", glib::Variant::FromVector(xids)) + .add("sticky", IsSticky()); +} + +} // namespace launcher +} // namespace unity diff --git a/launcher/WindowedLauncherIcon.h b/launcher/WindowedLauncherIcon.h new file mode 100644 index 000000000..83ecbdb78 --- /dev/null +++ b/launcher/WindowedLauncherIcon.h @@ -0,0 +1,100 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2015 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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 General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Marco Trevisan <marco.trevisan@canonical.com> + */ + +#ifndef WINDOWED_LAUNCHER_ICON_H +#define WINDOWED_LAUNCHER_ICON_H + +#include <UnityCore/GLibSignal.h> + +#include "SimpleLauncherIcon.h" + +namespace unity +{ +namespace launcher +{ + +class WindowedLauncherIcon : public SimpleLauncherIcon +{ + NUX_DECLARE_OBJECT_TYPE(WindowedLauncherIcon, SimpleLauncherIcon); +public: + WindowedLauncherIcon(AbstractLauncherIcon::IconType); + + WindowList Windows() override; + WindowList WindowsOnViewport() override; + WindowList WindowsForMonitor(int monitor) override; + + virtual bool IsActive() const; + virtual bool IsRunning() const; + virtual bool IsUrgent() const; + virtual bool IsUserVisible() const; + + virtual void Quit() const; + +protected: + virtual WindowList GetManagedWindows() const = 0; + void EnsureWindowState(); + void EnsureWindowsLocation(); + + virtual void UpdateIconGeometries(std::vector<nux::Point3> const& centers); + + std::string GetName() const override; + void AddProperties(debug::IntrospectionData&) override; + + bool HandlesSpread() override; + bool ShowInSwitcher(bool current) override; + bool AllowDetailViewInSwitcher() const override; + uint64_t SwitcherPriority() override; + void AboutToRemove() override; + + void ActivateLauncherIcon(ActionArg arg) override; + void PerformScroll(ScrollDirection direction, Time timestamp) override; + virtual void Focus(ActionArg arg); + virtual bool Spread(bool current_desktop, int state, bool force); + + typedef unsigned long int WindowFilterMask; + enum WindowFilter + { + MAPPED = (1 << 0), + USER_VISIBLE = (1 << 1), + ON_CURRENT_DESKTOP = (1 << 2), + ON_ALL_MONITORS = (1 << 3), + }; + + WindowList GetWindows(WindowFilterMask filter = 0, int monitor = -1); + WindowList GetWindowsOnCurrentDesktopInStackingOrder(); + + MenuItemsVector GetWindowsMenuItems(); + +private: + void OnCenterStabilized(std::vector<nux::Point3> const& centers) override; + void OnWindowMinimized(Window); + void OnDndEnter(); + void OnDndLeave(); + + Time last_scroll_timestamp_; + unsigned int progressive_scroll_; + +protected: + glib::SignalManager glib_signals_; +}; + +} // namespace launcher +} // namespace unity + +#endif // WINDOWED_LAUNCHER_ICON_H diff --git a/lockscreen/CMakeLists.txt b/lockscreen/CMakeLists.txt index 6e1ca2474..86d3f492e 100644 --- a/lockscreen/CMakeLists.txt +++ b/lockscreen/CMakeLists.txt @@ -19,11 +19,15 @@ include_directories (.. ../services ../UnityCore ${UNITY_SRC} ${CMAKE_BINARY_DIR set (LOCKSCREEN_SOURCES BackgroundSettings.cpp CofView.cpp + KylinUserPromptView.cpp + KylinLockScreenShield.cpp LockScreenController.cpp + LockScreenBaseShield.cpp LockScreenSettings.cpp LockScreenShield.cpp LockScreenShieldFactory.cpp LockScreenPanel.cpp + LockScreenPromptFactory.cpp LockScreenAcceleratorController.cpp LockScreenAccelerators.cpp ScreenSaverDBusManager.cpp diff --git a/lockscreen/KylinLockScreenShield.cpp b/lockscreen/KylinLockScreenShield.cpp new file mode 100644 index 000000000..5f2211827 --- /dev/null +++ b/lockscreen/KylinLockScreenShield.cpp @@ -0,0 +1,99 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2015 Canonical Ltd +* 2015, National University of Defense Technology(NUDT) & Kylin Ltd +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 3 as +* published by the Free Software Foundation. +* +* 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 General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* Authored by: Marco Trevisan <marco.trevisan@canonical.com> +* handsome_feng <jianfengli@ubuntukylin.com> +*/ + +#include "KylinLockScreenShield.h" + +#include <Nux/VLayout.h> +#include <Nux/HLayout.h> + +#include "CofView.h" +#include "LockScreenSettings.h" +#include "LockScreenAbstractPromptView.h" + +namespace unity +{ +namespace lockscreen +{ + +KylinShield::KylinShield(session::Manager::Ptr const& session_manager, + Accelerators::Ptr const& accelerators, + nux::ObjectPtr<AbstractUserPromptView> const& prompt_view, + int monitor_num, bool is_primary) + : BaseShield(session_manager, nullptr, accelerators, prompt_view, monitor_num, is_primary) +{ + is_primary ? ShowPrimaryView() : ShowSecondaryView(); + EnableInputWindow(true); +} + +void KylinShield::ShowPrimaryView() +{ + if (primary_layout_) + { + if (prompt_view_) + { + prompt_view_->scale = scale(); + prompt_layout_->AddView(prompt_view_.GetPointer()); + } + + GrabScreen(false); + SetLayout(primary_layout_.GetPointer()); + return; + } + + GrabScreen(true); + nux::Layout* main_layout = new nux::VLayout(); + primary_layout_ = main_layout; + SetLayout(primary_layout_.GetPointer()); + + prompt_layout_ = new nux::HLayout(); + + if (prompt_view_) + { + prompt_view_->scale = scale(); + prompt_layout_->AddView(prompt_view_.GetPointer()); + } + + // 10 is just a random number to center the prompt view. + main_layout->AddSpace(0, 10); + main_layout->AddLayout(prompt_layout_.GetPointer(), 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FIX); + main_layout->AddSpace(0, 10); +} + +nux::Area* KylinShield::FindKeyFocusArea(unsigned etype, unsigned long keysym, unsigned long modifiers) +{ + if (primary) + { + grab_key.emit(modifiers, keysym); + + if (prompt_view_) + { + auto* focus_view = prompt_view_->focus_view(); + + if (focus_view && focus_view->GetInputEventSensitivity()) + return focus_view; + } + } + + return nullptr; +} + +} +} diff --git a/lockscreen/KylinLockScreenShield.h b/lockscreen/KylinLockScreenShield.h new file mode 100644 index 000000000..93294521a --- /dev/null +++ b/lockscreen/KylinLockScreenShield.h @@ -0,0 +1,54 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2015 Canonical Ltd +* 2015, National University of Defense Technology(NUDT) & Kylin Ltd +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 3 as +* published by the Free Software Foundation. +* +* 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 General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* Authored by: Marco Trevisan <marco.trevisan@canonical.com> +* handsome_feng <jianfengli@ubuntukylin.com> +*/ + +#ifndef UNITY_KYLIN_LOCKSCREEN_SHIELD_H +#define UNITY_KYLIN_LOCKSCREEN_SHIELD_H + +#include <UnityCore/ConnectionManager.h> +#include <UnityCore/GLibSource.h> +#include "LockScreenBaseShield.h" + +namespace unity +{ +namespace lockscreen +{ + +class AbstractUserPromptView; + +class KylinShield : public BaseShield +{ +public: + KylinShield(session::Manager::Ptr const&, + Accelerators::Ptr const&, + nux::ObjectPtr<AbstractUserPromptView> const&, + int monitor, bool is_primary); + +protected: + nux::Area* FindKeyFocusArea(unsigned int, unsigned long, unsigned long) override; + +private: + void ShowPrimaryView() override; +}; + +} +} + +#endif diff --git a/lockscreen/KylinUserPromptView.cpp b/lockscreen/KylinUserPromptView.cpp new file mode 100644 index 000000000..a5a63d0a5 --- /dev/null +++ b/lockscreen/KylinUserPromptView.cpp @@ -0,0 +1,402 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2015 Canonical Ltd +* 2015, National University of Defense Technology(NUDT) & Kylin Ltd +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 3 as +* published by the Free Software Foundation. +* +* 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 General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> +* handsome_feng <jianfengli@ubuntukylin.com> +*/ + +#include "KylinUserPromptView.h" + +#include "config.h" +#include <gtk/gtk.h> +#include <glib/gi18n-lib.h> + +#include <boost/algorithm/string/trim.hpp> +#include <Nux/VLayout.h> +#include <Nux/HLayout.h> +#include <NuxCore/Logger.h> +#include "Variant.h" + +#include "LockScreenSettings.h" +#include "unity-shared/CairoTexture.h" +#include "unity-shared/TextInput.h" +#include "unity-shared/StaticCairoText.h" +#include "unity-shared/RawPixel.h" +#include "unity-shared/IconTexture.h" +#include "unity-shared/TextureCache.h" + +namespace unity +{ +namespace lockscreen +{ +namespace +{ +const RawPixel AVATAR_SIZE = 128_em; +const RawPixel ACTIVATOR_ICON_SIZE = 34_em; +const RawPixel LAYOUT_MARGIN = 20_em; +const RawPixel MSG_LAYOUT_MARGIN = 15_em; +const RawPixel MSG_LAYOUT_PADDING = 33_em; +const RawPixel PROMPT_LAYOUT_MARGIN = 5_em; +const RawPixel SWITCH_ICON_SIZE = 34_em; +const RawPixel TEXT_INPUT_HEIGHT = 36_em; +const RawPixel TEXT_INPUT_WIDTH = 320_em; +const int PROMPT_FONT_SIZE = 14; + +const std::string ACTIVATOR_ICON = "login.svg"; + +std::string SanitizeMessage(std::string const& message) +{ + std::string msg = boost::algorithm::trim_copy(message); + + if (msg.empty()) + return msg; + + if (msg[msg.size()-1] == ':') + msg = msg.substr(0, msg.size()-1); + + if (msg == "Password") + return _("Password"); + + if (msg == "login") + return _("Username"); + + return msg; +} + +} + +KylinUserPromptView::KylinUserPromptView(session::Manager::Ptr const& session_manager) + : AbstractUserPromptView(session_manager) + , scale(1.0) + , session_manager_(session_manager) + , username_(nullptr) + , msg_layout_(nullptr) + , prompt_layout_(nullptr) + , avatar_layout_(nullptr) + , switch_icon_(nullptr) + , avatar_(nullptr) + , avatar_icon_file("") +{ + user_authenticator_.echo_on_requested.connect([this](std::string const& message, PromiseAuthCodePtr const& promise){ + AddPrompt(message, true, promise); + }); + + user_authenticator_.echo_off_requested.connect([this](std::string const& message, PromiseAuthCodePtr const& promise){ + AddPrompt(message, false, promise); + }); + + user_authenticator_.message_requested.connect([this](std::string const& message){ + AddMessage(message, nux::color::White); + }); + + user_authenticator_.error_requested.connect([this](std::string const& message){ + AddMessage(message, nux::color::Red); + }); + + user_authenticator_.clear_prompts.connect([this](){ + ResetLayout(); + }); + + scale.changed.connect(sigc::hide(sigc::mem_fun(this, &KylinUserPromptView::UpdateSize))); + + session_manager_->UserIconFile([this] (std::string const& value) { + avatar_icon_file = value; + AddAvatar(value, AVATAR_SIZE.CP(scale)); + }); + + UpdateSize(); + ResetLayout(); + + user_authenticator_.AuthenticateStart(session_manager_->UserName(), + sigc::mem_fun(this, &KylinUserPromptView::AuthenticationCb)); +} + +void KylinUserPromptView::ResetLayout() +{ + focus_queue_.clear(); + + SetLayout(new nux::HLayout()); + + static_cast<nux::HLayout*>(GetLayout())->SetHorizontalInternalMargin(LAYOUT_MARGIN.CP(scale)); + + if (g_getenv("XDG_SEAT_PATH")) + { + nux::Layout* switch_layout = new nux::HLayout(); + + TextureCache& cache = TextureCache::GetDefault(); + switch_icon_ = new IconTexture(cache.FindTexture("switch_user.svg", SWITCH_ICON_SIZE.CP(scale), SWITCH_ICON_SIZE.CP(scale))); + switch_layout->AddView(switch_icon_); + switch_icon_->mouse_click.connect([this](int x, int y, unsigned long button_flags, unsigned long key_flags) { + session_manager_->SwitchToGreeter(); + }); + switch_layout->SetMaximumSize(SWITCH_ICON_SIZE.CP(scale), SWITCH_ICON_SIZE.CP(scale)); + GetLayout()->AddLayout(switch_layout); + } + + avatar_layout_ = new nux::VLayout(); + if (!avatar_icon_file().empty()) + AddAvatar(avatar_icon_file(), AVATAR_SIZE.CP(scale)); + GetLayout()->AddLayout(avatar_layout_); + + nux::Layout* prompt_layout = new nux::VLayout(); + + auto const& real_name = session_manager_->RealName(); + auto const& name = (real_name.empty() ? session_manager_->UserName() : real_name); + + username_ = new unity::StaticCairoText(name); + username_->SetScale(scale); + username_->SetFont("Ubuntu "+std::to_string(PROMPT_FONT_SIZE)); + prompt_layout->AddView(username_); + + msg_layout_ = new nux::VLayout(); + msg_layout_->SetVerticalInternalMargin(MSG_LAYOUT_MARGIN.CP(scale)); + msg_layout_->SetTopAndBottomPadding(MSG_LAYOUT_PADDING.CP(scale), 0); + prompt_layout->AddLayout(msg_layout_); + + prompt_layout_ = new nux::VLayout(); + prompt_layout_->SetVerticalInternalMargin(PROMPT_LAYOUT_MARGIN.CP(scale)); + prompt_layout->AddLayout(prompt_layout_); + + GetLayout()->AddLayout(prompt_layout); + QueueRelayout(); + QueueDraw(); +} + +void KylinUserPromptView::UpdateSize() +{ + auto width = 13 * Settings::GRID_SIZE.CP(scale); + auto height = 3 * Settings::GRID_SIZE.CP(scale); + + SetMinimumWidth(width); + SetMaximumWidth(width); + SetMinimumHeight(height); + + if (username_) + username_->SetScale(scale); + + if (msg_layout_) + { + msg_layout_->SetVerticalInternalMargin(MSG_LAYOUT_MARGIN.CP(scale)); + + for (auto* area : msg_layout_->GetChildren()) + { + area->SetMaximumWidth(TEXT_INPUT_WIDTH); + static_cast<StaticCairoText*>(area)->SetScale(scale); + } + } + + if (prompt_layout_) + { + prompt_layout_->SetVerticalInternalMargin(PROMPT_LAYOUT_MARGIN.CP(scale)); + + for (auto* area : prompt_layout_->GetChildren()) + { + auto* text_input = static_cast<TextInput*>(area); + text_input->SetMinimumHeight(TEXT_INPUT_HEIGHT.CP(scale)); + text_input->SetMaximumHeight(TEXT_INPUT_HEIGHT.CP(scale)); + text_input->SetMinimumWidth(TEXT_INPUT_WIDTH.CP(scale)); + text_input->SetMaximumWidth(TEXT_INPUT_WIDTH.CP(scale)); + text_input->scale = scale(); + } + } + + ComputeContentSize(); + QueueRelayout(); + QueueDraw(); +} + +bool KylinUserPromptView::InspectKeyEvent(unsigned int eventType, unsigned int key_sym, const char* character) +{ + if ((eventType == nux::NUX_KEYDOWN) && (key_sym == NUX_VK_ESCAPE)) + { + if (!focus_queue_.empty()) + focus_queue_.front()->text_entry()->SetText(""); + + return true; + } + + return false; +} + +void KylinUserPromptView::AuthenticationCb(bool authenticated) +{ + ResetLayout(); + + if (authenticated) + { + session_manager_->unlock_requested.emit(); + } + else + { + AddMessage(_("Invalid password, please try again"), nux::color::Red); + + user_authenticator_.AuthenticateStart(session_manager_->UserName(), + sigc::mem_fun(this, &KylinUserPromptView::AuthenticationCb)); + } +} + +void KylinUserPromptView::Draw(nux::GraphicsEngine& graphics_engine, bool force_draw) +{ + nux::Geometry const& geo = GetGeometry(); + + graphics_engine.PushClippingRectangle(geo); + nux::GetPainter().PaintBackground(graphics_engine, geo); + + graphics_engine.PopClippingRectangle(); +} + +void KylinUserPromptView::DrawContent(nux::GraphicsEngine& graphics_engine, bool force_draw) +{ + nux::Geometry const& geo = GetGeometry(); + graphics_engine.PushClippingRectangle(geo); + + if (GetLayout()) + GetLayout()->ProcessDraw(graphics_engine, force_draw); + + graphics_engine.PopClippingRectangle(); +} + +nux::View* KylinUserPromptView::focus_view() +{ + if (focus_queue_.empty()) + return nullptr; + + for (auto* view : focus_queue_) + if (view->text_entry()->HasKeyboardFocus()) + return view; + + return focus_queue_.front()->text_entry(); +} + +void KylinUserPromptView::AddPrompt(std::string const& message, bool visible, PromiseAuthCodePtr const& promise) +{ + auto* text_input = new unity::TextInput(); + auto* text_entry = text_input->text_entry(); + + text_input->scale = scale(); + text_input->activator_icon = ACTIVATOR_ICON; + text_input->activator_icon_size = ACTIVATOR_ICON_SIZE; + text_input->background_color = nux::Color(1.0f, 1.0f, 1.0f, 0.8f); + text_input->border_color = nux::Color(0.0f, 0.0f, 0.0f, 0.0f); + text_input->border_radius = 0; + text_input->hint_color = nux::Color(0.0f, 0.0f, 0.0f, 0.5f); + text_input->input_hint = SanitizeMessage(message); + text_input->hint_font_size = PROMPT_FONT_SIZE; + text_input->show_lock_warnings = true; + text_input->show_activator = true; + text_entry->SetPasswordMode(!visible); + text_entry->SetPasswordChar("•"); + text_entry->SetToggleCursorVisibilityOnKeyFocus(true); + text_entry->clipboard_enabled = false; + text_entry->SetTextColor(nux::color::Black); + + text_input->SetMinimumHeight(TEXT_INPUT_HEIGHT.CP(scale)); + text_input->SetMaximumHeight(TEXT_INPUT_HEIGHT.CP(scale)); + text_input->SetMinimumWidth(TEXT_INPUT_WIDTH.CP(scale)); + text_input->SetMaximumWidth(TEXT_INPUT_WIDTH.CP(scale)); + prompt_layout_->AddView(text_input, 1); + focus_queue_.push_back(text_input); + + // Don't remove it, it helps with a11y. + if (focus_queue_.size() == 1) + nux::GetWindowCompositor().SetKeyFocusArea(text_entry); + + text_entry->activated.connect([this, text_input, promise](){ + auto* text_entry = text_input->text_entry(); + + if (!text_entry->GetInputEventSensitivity()) + return; + + if (focus_queue_.size() == 1) + { + text_input->SetSpinnerVisible(true); + text_input->SetSpinnerState(STATE_SEARCHING); + } + + focus_queue_.pop_front(); + cached_focused_geo_ = text_entry->GetGeometry(); + text_entry->SetInputEventSensitivity(false); + QueueRelayout(); + QueueDraw(); + + std::string const& password = text_entry->GetText(); + if (promise) + promise->set_value(password); + }); + + GetLayout()->ComputeContentPosition(0, 0); + ComputeContentSize(); + QueueRelayout(); + QueueDraw(); +} + +void KylinUserPromptView::AddMessage(std::string const& message, nux::Color const& color) +{ + auto* view = new unity::StaticCairoText(""); + view->SetScale(scale); + view->SetFont(Settings::Instance().font_name()); + view->SetTextColor(color); + view->SetText(message); + view->SetMaximumWidth(TEXT_INPUT_WIDTH.CP(scale)); + msg_layout_->AddView(view); + + GetLayout()->ComputeContentPosition(0, 0); + ComputeContentSize(); + QueueRelayout(); + QueueDraw(); +} + +void KylinUserPromptView::AddAvatar(std::string const& icon_file, int icon_size) +{ + avatar_ = new IconTexture(LoadUserIcon(icon_file, icon_size)); + avatar_->SetMinimumWidth(icon_size); + avatar_->SetMaximumWidth(icon_size); + avatar_layout_->AddView(avatar_); + + GetLayout()->ComputeContentPosition(0, 0); + ComputeContentSize(); + QueueRelayout(); + QueueDraw(); +} + +nux::ObjectPtr<nux::BaseTexture> KylinUserPromptView::LoadUserIcon(std::string const& icon_file, int icon_size) +{ + glib::Error error; + glib::Object<GdkPixbuf> pixbuf(gdk_pixbuf_new_from_file_at_size(icon_file.c_str(), icon_size, icon_size, &error)); + if (!pixbuf) + { + auto* theme = gtk_icon_theme_get_default(); + GtkIconLookupFlags flags = GTK_ICON_LOOKUP_FORCE_SIZE; + pixbuf = gtk_icon_theme_load_icon(theme, "avatar-default-kylin", icon_size, flags, &error); + if (!pixbuf) + pixbuf = gtk_icon_theme_load_icon(theme, "avatar-default", icon_size, flags, &error); + } + nux::CairoGraphics cg(CAIRO_FORMAT_ARGB32, gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf)); + cairo_t* cr = cg.GetInternalContext(); + + gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); + cairo_paint_with_alpha(cr, 1.0); + cairo_set_source_rgba(cr, 1.0f, 1.0f, 1.0f, 1.0f); + cairo_rectangle(cr, 0, 0, gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf)); + cairo_set_line_width(cr, 3); + cairo_stroke(cr); + + return texture_ptr_from_cairo_graphics(cg); +} + +} +} diff --git a/lockscreen/KylinUserPromptView.h b/lockscreen/KylinUserPromptView.h new file mode 100644 index 000000000..b45ac18bc --- /dev/null +++ b/lockscreen/KylinUserPromptView.h @@ -0,0 +1,84 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2015 Canonical Ltd +* 2015, National University of Defense Technology(NUDT) & Kylin Ltd +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 3 as +* published by the Free Software Foundation. +* +* 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 General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> +* handsome_feng <jianfengli@ubuntukylin.com> +*/ + +#ifndef UNITY_KYLIN_USER_PROMPT_BOX +#define UNITY_KYLIN_USER_PROMPT_BOX + +#include "LockScreenAbstractPromptView.h" + +namespace nux +{ +class VLayout; +class HLayout; +} + +namespace unity +{ + +class StaticCairoText; +class TextInput; +class IconTexture; +class RawPixel; + +namespace lockscreen +{ + +class KylinUserPromptView : public AbstractUserPromptView +{ +public: + KylinUserPromptView(session::Manager::Ptr const& session_manager); + + nux::Property<double> scale; + + nux::View* focus_view(); + + void AddAvatar(std::string const& avatar_icon, int avatar_size); + void AddPrompt(std::string const& message, bool visible, PromiseAuthCodePtr const&); + void AddMessage(std::string const& message, nux::Color const& color); + void AuthenticationCb(bool authenticated); + +protected: + void Draw(nux::GraphicsEngine& graphics_engine, bool force_draw); + void DrawContent(nux::GraphicsEngine& graphics_engine, bool force_draw); + void ResetLayout(); + void UpdateSize(); + bool InspectKeyEvent(unsigned int eventType, unsigned int key_sym, const char* character); + nux::ObjectPtr<nux::BaseTexture> LoadUserIcon(std::string const& icon_file, int icon_size); + +private: + session::Manager::Ptr session_manager_; + UserAuthenticatorPam user_authenticator_; + StaticCairoText* username_; + nux::VLayout* msg_layout_; + nux::VLayout* prompt_layout_; + nux::VLayout* avatar_layout_; + std::deque<TextInput*> focus_queue_; + IconTexture* switch_icon_; + IconTexture* avatar_; + nux::Property<std::string> avatar_icon_file; + + nux::Geometry cached_focused_geo_; +}; + +} +} + +#endif diff --git a/lockscreen/LockScreenAbstractPromptView.h b/lockscreen/LockScreenAbstractPromptView.h new file mode 100644 index 000000000..2f5da195f --- /dev/null +++ b/lockscreen/LockScreenAbstractPromptView.h @@ -0,0 +1,79 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2015 Canonical Ltd + * 2015, National University of Defense Technology(NUDT) & Kylin Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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 General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: handsome_feng <jianfengli@ubuntukylin.com> + */ + +#ifndef UNITY_LOCKSCREEN_ABSTRACT_USER_PROMPT_H +#define UNITY_LOCKSCREEN_ABSTRACT_USER_PROMPT_H + +#include <memory> +#include <deque> + +#include <Nux/Nux.h> +#include <Nux/View.h> +#include <Nux/VLayout.h> +#include <UnityCore/SessionManager.h> + +#include "UserAuthenticatorPam.h" +#include "unity-shared/IMTextEntry.h" + +namespace nux +{ +class VLayout; +} +namespace unity +{ + +class StaticCairoText; +class TextInput; + +namespace lockscreen +{ + +class AbstractUserPromptView : public nux::View +{ +public: + AbstractUserPromptView(session::Manager::Ptr const& session_manager) + : nux::View(NUX_TRACKER_LOCATION) + , session_manager_(session_manager) + {} + + nux::Property<double> scale; + + virtual nux::View* focus_view() = 0; + + virtual void AuthenticationCb(bool authenticated) = 0; + virtual void ResetLayout() = 0; + virtual void UpdateSize() = 0; + +protected: + session::Manager::Ptr session_manager_; + UserAuthenticatorPam user_authenticator_; + std::shared_ptr<nux::AbstractPaintLayer> bg_layer_; + StaticCairoText* username_; + nux::VLayout* msg_layout_; + nux::VLayout* prompt_layout_; + std::deque<TextInput*> focus_queue_; + + nux::Geometry cached_focused_geo_; +}; + +} // lockscreen +} // unity + +#endif // UNITY_LOCKSCREEN_ABSTRACT_USER_PROMPT_H diff --git a/lockscreen/LockScreenBaseShield.cpp b/lockscreen/LockScreenBaseShield.cpp new file mode 100644 index 000000000..0d65550c3 --- /dev/null +++ b/lockscreen/LockScreenBaseShield.cpp @@ -0,0 +1,173 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2015 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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 General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Marco Trevisan <marco.trevisan@canonical.com> + */ + +#include "LockScreenBaseShield.h" + +#include "BackgroundSettings.h" +#include "CofView.h" +#include "LockScreenAbstractPromptView.h" +#include "LockScreenSettings.h" +#include "unity-shared/MockableBaseWindow.h" +#include "unity-shared/UnitySettings.h" +#include "unity-shared/UScreen.h" +#include "unity-shared/WindowManager.h" + +namespace unity +{ +namespace lockscreen +{ +namespace +{ +const unsigned MAX_GRAB_WAIT = 100; +} + +BaseShield::BaseShield(session::Manager::Ptr const& session, + indicator::Indicators::Ptr const& indicators, + Accelerators::Ptr const& accelerators, + nux::ObjectPtr<AbstractUserPromptView> const& prompt_view, + int monitor_num, bool is_primary) + : MockableBaseWindow("Unity Lockscreen") + , primary(is_primary) + , monitor(monitor_num) + , scale(1.0) + , session_manager_(session) + , indicators_(indicators) + , accelerators_(accelerators) + , prompt_view_(prompt_view) + , bg_settings_(std::make_shared<BackgroundSettings>()) + , cof_view_(nullptr) +{ + UpdateScale(); + + unity::Settings::Instance().dpi_changed.connect(sigc::mem_fun(this, &BaseShield::UpdateScale)); + geometry_changed.connect([this] (nux::Area*, nux::Geometry&) { UpdateBackgroundTexture();}); + + monitor.changed.connect([this] (int monitor) { + UpdateScale(); + UpdateBackgroundTexture(); + }); + + primary.changed.connect([this] (bool is_primary) { + regrab_conn_->disconnect(); + is_primary ? ShowPrimaryView() : ShowSecondaryView(); + QueueRelayout(); + QueueDraw(); + }); + + scale.changed.connect([this] (double scale) { + if (prompt_view_ && primary()) + prompt_view_->scale = scale; + + if (cof_view_) + cof_view_->scale = scale; + + if (prompt_layout_) + prompt_layout_->SetLeftAndRightPadding(2 * Settings::GRID_SIZE.CP(scale)); + + background_layer_.reset(); + UpdateBackgroundTexture(); + }); + + mouse_move.connect([this] (int x, int y, int, int, unsigned long, unsigned long) { + auto const& abs_geo = GetAbsoluteGeometry(); + grab_motion.emit(abs_geo.x + x, abs_geo.y + y); + }); +} + +bool BaseShield::HasGrab() const +{ + auto& wc = nux::GetWindowCompositor(); + return (wc.GetPointerGrabArea() == this && wc.GetKeyboardGrabArea() == this); +} + +nux::Area* BaseShield::FindAreaUnderMouse(nux::Point const& mouse, nux::NuxEventType event_type) +{ + nux::Area* area = BaseWindow::FindAreaUnderMouse(mouse, event_type); + + if (!area && primary) + return this; + + return area; +} + +void BaseShield::GrabScreen(bool cancel_on_failure) +{ + auto& wc = nux::GetWindowCompositor(); + + if (wc.GrabPointerAdd(this) && wc.GrabKeyboardAdd(this)) + { + regrab_conn_->disconnect(); + regrab_timeout_.reset(); + grabbed.emit(); + } + else + { + auto const& retry_cb = sigc::bind(sigc::mem_fun(this, &BaseShield::GrabScreen), false); + regrab_conn_ = WindowManager::Default().screen_ungrabbed.connect(retry_cb); + + if (cancel_on_failure) + { + regrab_timeout_.reset(new glib::Timeout(MAX_GRAB_WAIT, [this] { + grab_failed.emit(); + return false; + })); + } + } +} + +void BaseShield::UpdateBackgroundTexture() +{ + auto const& monitor_geo = UScreen::GetDefault()->GetMonitorGeometry(monitor); + + if (!background_layer_ || monitor_geo != background_layer_->GetGeometry()) + { + auto background_texture = bg_settings_->GetBackgroundTexture(monitor); + background_layer_.reset(new nux::TextureLayer(background_texture->GetDeviceTexture(), nux::TexCoordXForm(), nux::color::White, true)); + SetBackgroundLayer(background_layer_.get()); + } +} + +void BaseShield::UpdateScale() +{ + scale = unity::Settings::Instance().em(monitor)->DPIScale(); +} + +void BaseShield::ShowSecondaryView() +{ + if (prompt_layout_) + prompt_layout_->RemoveChildObject(prompt_view_.GetPointer()); + + if (cof_layout_) + { + SetLayout(cof_layout_.GetPointer()); + return; + } + + nux::Layout* main_layout = new nux::VLayout(); + cof_layout_ = main_layout; + SetLayout(cof_layout_.GetPointer()); + + // The circle of friends + cof_view_ = new CofView(); + cof_view_->scale = scale(); + main_layout->AddView(cof_view_); +} + +} // lockscreen +} // unity diff --git a/lockscreen/LockScreenAbstractShield.h b/lockscreen/LockScreenBaseShield.h index 71bc64fec..7a2192144 100644 --- a/lockscreen/LockScreenAbstractShield.h +++ b/lockscreen/LockScreenBaseShield.h @@ -1,6 +1,6 @@ // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* - * Copyright (C) 2014 Canonical Ltd + * Copyright (C) 2014-2015 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as @@ -17,49 +17,40 @@ * Authored by: Marco Trevisan <marco.trevisan@canonical.com> */ -#ifndef UNITY_LOCKSCREEN_ABSTRACT_SHIELD_H -#define UNITY_LOCKSCREEN_ABSTRACT_SHIELD_H +#ifndef UNITY_LOCKSCREEN_BASE_SHIELD_H +#define UNITY_LOCKSCREEN_BASE_SHIELD_H #include <NuxCore/Property.h> #include <UnityCore/SessionManager.h> #include <UnityCore/Indicators.h> - +#include <UnityCore/GLibSource.h> #include "unity-shared/MockableBaseWindow.h" + #include "LockScreenAccelerators.h" namespace unity { namespace lockscreen { +class BackgroundSettings; +class AbstractUserPromptView; +class CofView; -class UserPromptView; - -class AbstractShield : public MockableBaseWindow +class BaseShield : public MockableBaseWindow { public: - AbstractShield(session::Manager::Ptr const& session, - indicator::Indicators::Ptr const& indicators, - Accelerators::Ptr const& accelerators, - nux::ObjectPtr<UserPromptView> const& prompt_view, - int monitor_num, bool is_primary) - : MockableBaseWindow("Unity Lockscreen") - , primary(is_primary) - , monitor(monitor_num) - , scale(1.0) - , session_manager_(session) - , indicators_(indicators) - , accelerators_(accelerators) - , prompt_view_(prompt_view) - {} + BaseShield(session::Manager::Ptr const&, indicator::Indicators::Ptr const&, + Accelerators::Ptr const&, nux::ObjectPtr<AbstractUserPromptView> const&, + int monitor_num, bool is_primary); nux::Property<bool> primary; nux::Property<int> monitor; nux::Property<double> scale; + bool HasGrab() const; + virtual bool IsIndicatorOpen() const { return false; } + virtual void ActivatePanel() {} using MockableBaseWindow::RemoveLayout; - virtual bool HasGrab() const = 0; - virtual bool IsIndicatorOpen() const = 0; - virtual void ActivatePanel() = 0; sigc::signal<void> grabbed; sigc::signal<void> grab_failed; @@ -67,13 +58,31 @@ public: sigc::signal<void, unsigned long, unsigned long> grab_key; protected: + virtual bool AcceptKeyNavFocus() { return false; } + virtual void ShowPrimaryView() = 0; + virtual void ShowSecondaryView(); + + nux::Area* FindAreaUnderMouse(nux::Point const& mouse, nux::NuxEventType event_type) override; + + void GrabScreen(bool cancel_on_failure); + void UpdateBackgroundTexture(); + void UpdateScale(); + session::Manager::Ptr session_manager_; indicator::Indicators::Ptr indicators_; Accelerators::Ptr accelerators_; - nux::ObjectPtr<UserPromptView> prompt_view_; + nux::ObjectPtr<AbstractUserPromptView> prompt_view_; + std::shared_ptr<BackgroundSettings> bg_settings_; + std::unique_ptr<nux::AbstractPaintLayer> background_layer_; + nux::ObjectPtr<nux::Layout> primary_layout_; + nux::ObjectPtr<nux::Layout> prompt_layout_; + nux::ObjectPtr<nux::Layout> cof_layout_; + CofView* cof_view_; + connection::Wrapper regrab_conn_; + glib::Source::UniquePtr regrab_timeout_; }; } // lockscreen } // unity -#endif // UNITY_LOCKSCREEN_ABSTRACT_SHIELD_H +#endif // UNITY_LOCKSCREEN_BASE_SHIELD_H diff --git a/lockscreen/LockScreenController.cpp b/lockscreen/LockScreenController.cpp index 597381fb3..3bd91a0b3 100644 --- a/lockscreen/LockScreenController.cpp +++ b/lockscreen/LockScreenController.cpp @@ -23,6 +23,8 @@ #include <UnityCore/GLibDBusProxy.h> #include <NuxCore/Logger.h> +#include "LockScreenAbstractPromptView.h" +#include "LockScreenPromptFactory.h" #include "LockScreenShield.h" #include "LockScreenSettings.h" #include "unity-shared/AnimationUtils.h" @@ -218,13 +220,13 @@ void Controller::EnsureShields(std::vector<nux::Geometry> const& monitors) int primary = UScreen::GetDefault()->GetMonitorWithMouse(); // Keep a reference of the old prompt_view - nux::ObjectPtr<UserPromptView> prompt_view(prompt_view_.GetPointer()); + nux::ObjectPtr<AbstractUserPromptView> prompt_view(prompt_view_.GetPointer()); shields_.resize(num_monitors); if (!prompt_view) { - prompt_view = test_mode_ ? nullptr : new UserPromptView(session_manager_); + prompt_view = test_mode_ ? nux::ObjectPtr<AbstractUserPromptView>() : PromptFactory::CreatePrompt(session_manager_); prompt_view_ = prompt_view.GetPointer(); } diff --git a/lockscreen/LockScreenController.h b/lockscreen/LockScreenController.h index e769778e9..839028369 100644 --- a/lockscreen/LockScreenController.h +++ b/lockscreen/LockScreenController.h @@ -24,12 +24,12 @@ #include <UnityCore/ConnectionManager.h> #include <UnityCore/GLibSource.h> +#include "LockScreenBaseShield.h" #include "LockScreenShieldFactory.h" #include "LockScreenAcceleratorController.h" #include "ScreenSaverDBusManager.h" #include "ShutdownNotifier.h" #include "SuspendNotifier.h" -#include "UserPromptView.h" #include "unity-shared/BackgroundEffectHelper.h" #include "unity-shared/UpstartWrapper.h" @@ -38,7 +38,7 @@ namespace unity namespace lockscreen { -class UserPromptView; +class AbstractUserPromptView; class Controller : public sigc::trackable { @@ -77,9 +77,9 @@ private: void OnScreenSaverActivationRequest(bool activate); void OnPrimaryShieldMotion(int x, int y); - std::vector<nux::ObjectPtr<AbstractShield>> shields_; - nux::ObjectWeakPtr<AbstractShield> primary_shield_; - nux::ObjectWeakPtr<UserPromptView> prompt_view_; + std::vector<nux::ObjectPtr<BaseShield>> shields_; + nux::ObjectWeakPtr<BaseShield> primary_shield_; + nux::ObjectWeakPtr<AbstractUserPromptView> prompt_view_; nux::ObjectPtr<nux::BaseWindow> blank_window_; DBusManager::Ptr dbus_manager_; diff --git a/lockscreen/LockScreenPromptFactory.cpp b/lockscreen/LockScreenPromptFactory.cpp new file mode 100644 index 000000000..02e39eb24 --- /dev/null +++ b/lockscreen/LockScreenPromptFactory.cpp @@ -0,0 +1,42 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2015 Canonical Ltd +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 3 as +* published by the Free Software Foundation. +* +* 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 General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* Authored by: Marco Trevisan <marco.trevisan@canonical.com> +*/ + +#include "LockScreenPromptFactory.h" +#include "KylinUserPromptView.h" +#include "UserPromptView.h" +#include "unity-shared/UnitySettings.h" + +namespace unity +{ +namespace lockscreen +{ +nux::ObjectPtr<AbstractUserPromptView> PromptFactory::CreatePrompt(session::Manager::Ptr const& sm) +{ + nux::ObjectPtr<AbstractUserPromptView> prompt; + + if (unity::Settings::Instance().desktop_type() == DesktopType::UBUNTUKYLIN) + prompt = new KylinUserPromptView(sm); + else + prompt = new UserPromptView(sm); + + return prompt; +} + +} +} diff --git a/lockscreen/LockScreenPromptFactory.h b/lockscreen/LockScreenPromptFactory.h new file mode 100644 index 000000000..af21e1982 --- /dev/null +++ b/lockscreen/LockScreenPromptFactory.h @@ -0,0 +1,42 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2015 Canonical Ltd +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 3 as +* published by the Free Software Foundation. +* +* 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 General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* Authored by: Marco Trevisan <marco.trevisan@canonical.com> +*/ + +#ifndef UNITY_LOCKSCREEN_PROMPT_FACTORY +#define UNITY_LOCKSCREEN_PROMPT_FACTORY + +#include <NuxCore/NuxCore.h> +#include <UnityCore/SessionManager.h> + +namespace unity +{ +class MockableBaseWindow; + +namespace lockscreen +{ +class AbstractUserPromptView; + +struct PromptFactory +{ + static nux::ObjectPtr<AbstractUserPromptView> CreatePrompt(session::Manager::Ptr const&); +}; + +} +} + +#endif // UNITY_LOCKSCREEN_PROMPT_FACTORY diff --git a/lockscreen/LockScreenShield.cpp b/lockscreen/LockScreenShield.cpp index a8d412105..264cf7132 100644 --- a/lockscreen/LockScreenShield.cpp +++ b/lockscreen/LockScreenShield.cpp @@ -21,127 +21,35 @@ #include <Nux/VLayout.h> #include <Nux/HLayout.h> -#include <Nux/PaintLayer.h> -#include "BackgroundSettings.h" -#include "CofView.h" #include "LockScreenPanel.h" #include "LockScreenSettings.h" -#include "UserPromptView.h" -#include "unity-shared/UScreen.h" -#include "unity-shared/UnitySettings.h" -#include "unity-shared/WindowManager.h" +#include "LockScreenAbstractPromptView.h" namespace unity { namespace lockscreen { -namespace -{ -const unsigned MAX_GRAB_WAIT = 100; -} Shield::Shield(session::Manager::Ptr const& session_manager, indicator::Indicators::Ptr const& indicators, Accelerators::Ptr const& accelerators, - nux::ObjectPtr<UserPromptView> const& prompt_view, + nux::ObjectPtr<AbstractUserPromptView> const& prompt_view, int monitor_num, bool is_primary) - : AbstractShield(session_manager, indicators, accelerators, prompt_view, monitor_num, is_primary) - , bg_settings_(std::make_shared<BackgroundSettings>()) + : BaseShield(session_manager, indicators, accelerators, prompt_view, monitor_num, is_primary) , panel_view_(nullptr) - , cof_view_(nullptr) { - UpdateScale(); is_primary ? ShowPrimaryView() : ShowSecondaryView(); - EnableInputWindow(true); - unity::Settings::Instance().dpi_changed.connect(sigc::mem_fun(this, &Shield::UpdateScale)); - geometry_changed.connect([this] (nux::Area*, nux::Geometry&) { UpdateBackgroundTexture();}); - monitor.changed.connect([this] (int monitor) { - UpdateScale(); - if (panel_view_) panel_view_->monitor = monitor; - - UpdateBackgroundTexture(); }); primary.changed.connect([this] (bool is_primary) { - regrab_conn_->disconnect(); - is_primary ? ShowPrimaryView() : ShowSecondaryView(); if (panel_view_) panel_view_->SetInputEventSensitivity(is_primary); - QueueRelayout(); - QueueDraw(); - }); - - scale.changed.connect([this] (double scale) { - if (prompt_view_ && primary()) - prompt_view_->scale = scale; - - if (cof_view_) - cof_view_->scale = scale; - - if (prompt_layout_) - prompt_layout_->SetLeftAndRightPadding(2 * Settings::GRID_SIZE.CP(scale)); - - background_layer_.reset(); - UpdateBackgroundTexture(); }); - - mouse_move.connect([this] (int x, int y, int, int, unsigned long, unsigned long) { - auto const& abs_geo = GetAbsoluteGeometry(); - grab_motion.emit(abs_geo.x + x, abs_geo.y + y); - }); -} - -void Shield::UpdateScale() -{ - scale = unity::Settings::Instance().em(monitor)->DPIScale(); -} - -void Shield::UpdateBackgroundTexture() -{ - auto const& monitor_geo = UScreen::GetDefault()->GetMonitorGeometry(monitor); - - if (!background_layer_ || monitor_geo != background_layer_->GetGeometry()) - { - auto background_texture = bg_settings_->GetBackgroundTexture(monitor); - background_layer_.reset(new nux::TextureLayer(background_texture->GetDeviceTexture(), nux::TexCoordXForm(), nux::color::White, true)); - SetBackgroundLayer(background_layer_.get()); - } -} - -void Shield::GrabScreen(bool cancel_on_failure) -{ - auto& wc = nux::GetWindowCompositor(); - - if (wc.GrabPointerAdd(this) && wc.GrabKeyboardAdd(this)) - { - regrab_conn_->disconnect(); - regrab_timeout_.reset(); - grabbed.emit(); - } - else - { - auto const& retry_cb = sigc::bind(sigc::mem_fun(this, &Shield::GrabScreen), false); - regrab_conn_ = WindowManager::Default().screen_ungrabbed.connect(retry_cb); - - if (cancel_on_failure) - { - regrab_timeout_.reset(new glib::Timeout(MAX_GRAB_WAIT, [this] { - grab_failed.emit(); - return false; - })); - } - } -} - -bool Shield::HasGrab() const -{ - auto& wc = nux::GetWindowCompositor(); - return (wc.GetPointerGrabArea() == this && wc.GetKeyboardGrabArea() == this); } void Shield::ShowPrimaryView() @@ -181,27 +89,6 @@ void Shield::ShowPrimaryView() main_layout->AddSpace(0, 10); } -void Shield::ShowSecondaryView() -{ - if (prompt_layout_) - prompt_layout_->RemoveChildObject(prompt_view_.GetPointer()); - - if (cof_layout_) - { - SetLayout(cof_layout_.GetPointer()); - return; - } - - nux::Layout* main_layout = new nux::VLayout(); - cof_layout_ = main_layout; - SetLayout(cof_layout_.GetPointer()); - - // The circle of friends - cof_view_ = new CofView(); - cof_view_->scale = scale(); - main_layout->AddView(cof_view_); -} - Panel* Shield::CreatePanel() { if (!indicators_ || !session_manager_) @@ -259,21 +146,6 @@ nux::Area* Shield::FindKeyFocusArea(unsigned etype, unsigned long keysym, unsign return nullptr; } -bool Shield::AcceptKeyNavFocus() -{ - return false; -} - -nux::Area* Shield::FindAreaUnderMouse(nux::Point const& mouse, nux::NuxEventType event_type) -{ - nux::Area* area = BaseWindow::FindAreaUnderMouse(mouse, event_type); - - if (!area && primary) - return this; - - return area; -} - bool Shield::IsIndicatorOpen() const { return panel_view_ ? panel_view_->active() : false; diff --git a/lockscreen/LockScreenShield.h b/lockscreen/LockScreenShield.h index 967cca9c1..053e0102f 100644 --- a/lockscreen/LockScreenShield.h +++ b/lockscreen/LockScreenShield.h @@ -21,56 +21,37 @@ #define UNITY_LOCKSCREEN_SHIELD_H #include <UnityCore/ConnectionManager.h> -#include <UnityCore/GLibSource.h> -#include "LockScreenAbstractShield.h" +#include "LockScreenBaseShield.h" namespace unity { namespace lockscreen { -class BackgroundSettings; -class UserAuthenticator; -class UserPromptView; +class AbstractUserPromptView; class Panel; -class CofView; -class Shield : public AbstractShield +class Shield : public BaseShield { public: Shield(session::Manager::Ptr const&, indicator::Indicators::Ptr const&, Accelerators::Ptr const&, - nux::ObjectPtr<UserPromptView> const&, + nux::ObjectPtr<AbstractUserPromptView> const&, int monitor, bool is_primary); - bool HasGrab() const override; bool IsIndicatorOpen() const override; void ActivatePanel() override; protected: - bool AcceptKeyNavFocus() override; nux::Area* FindKeyFocusArea(unsigned int, unsigned long, unsigned long) override; - nux::Area* FindAreaUnderMouse(nux::Point const&, nux::NuxEventType) override; private: - void UpdateBackgroundTexture(); - void GrabScreen(bool cancel_on_failure); - void ShowPrimaryView(); - void ShowSecondaryView(); - void UpdateScale(); + void ShowPrimaryView() override; Panel* CreatePanel(); - std::shared_ptr<BackgroundSettings> bg_settings_; - std::unique_ptr<nux::AbstractPaintLayer> background_layer_; - nux::ObjectPtr<nux::Layout> primary_layout_; - nux::ObjectPtr<nux::Layout> prompt_layout_; - nux::ObjectPtr<nux::Layout> cof_layout_; connection::Wrapper panel_active_conn_; - connection::Wrapper regrab_conn_; - glib::Source::UniquePtr regrab_timeout_; Panel* panel_view_; - CofView* cof_view_; }; } diff --git a/lockscreen/LockScreenShieldFactory.cpp b/lockscreen/LockScreenShieldFactory.cpp index 7bc1eceba..4f8d51ade 100644 --- a/lockscreen/LockScreenShieldFactory.cpp +++ b/lockscreen/LockScreenShieldFactory.cpp @@ -19,20 +19,28 @@ #include "LockScreenShieldFactory.h" #include "LockScreenShield.h" -#include "UserPromptView.h" +#include "KylinLockScreenShield.h" +#include "unity-shared/UnitySettings.h" namespace unity { namespace lockscreen { -nux::ObjectPtr<AbstractShield> ShieldFactory::CreateShield(session::Manager::Ptr const& session_manager, - indicator::Indicators::Ptr const& indicators, - Accelerators::Ptr const& accelerators, - nux::ObjectPtr<UserPromptView> const& prompt_view, - int monitor, bool is_primary) +nux::ObjectPtr<BaseShield> ShieldFactory::CreateShield(session::Manager::Ptr const& session_manager, + indicator::Indicators::Ptr const& indicators, + Accelerators::Ptr const& accelerators, + nux::ObjectPtr<AbstractUserPromptView> const& prompt_view, + int monitor, bool is_primary) { - return nux::ObjectPtr<Shield>(new Shield(session_manager, indicators, accelerators, prompt_view, monitor, is_primary)); + nux::ObjectPtr<BaseShield> shield; + + if (Settings::Instance().desktop_type() == DesktopType::UBUNTUKYLIN) + shield = new KylinShield(session_manager, accelerators, prompt_view, monitor, is_primary); + else + shield = new Shield(session_manager, indicators, accelerators, prompt_view, monitor, is_primary); + + return shield; } } diff --git a/lockscreen/LockScreenShieldFactory.h b/lockscreen/LockScreenShieldFactory.h index 154812582..1e66b754d 100644 --- a/lockscreen/LockScreenShieldFactory.h +++ b/lockscreen/LockScreenShieldFactory.h @@ -20,18 +20,19 @@ #ifndef UNITY_LOCKSCREEN_SHIELD_FACTORY #define UNITY_LOCKSCREEN_SHIELD_FACTORY -#include <Nux/Nux.h> -#include "LockScreenAbstractShield.h" +#include <NuxCore/NuxCore.h> +#include <UnityCore/SessionManager.h> +#include <UnityCore/Indicators.h> +#include "LockScreenAccelerators.h" namespace unity { - class MockableBaseWindow; namespace lockscreen { - -class UserPromptView; +class AbstractUserPromptView; +class BaseShield; struct ShieldFactoryInterface { @@ -39,23 +40,23 @@ struct ShieldFactoryInterface virtual ~ShieldFactoryInterface() = default; - virtual nux::ObjectPtr<AbstractShield> CreateShield(session::Manager::Ptr const&, - indicator::Indicators::Ptr const&, - Accelerators::Ptr const&, - nux::ObjectPtr<UserPromptView> const&, - int monitor, bool is_primary) = 0; + virtual nux::ObjectPtr<BaseShield> CreateShield(session::Manager::Ptr const&, + indicator::Indicators::Ptr const&, + Accelerators::Ptr const&, + nux::ObjectPtr<AbstractUserPromptView> const&, + int monitor, bool is_primary) = 0; }; struct ShieldFactory : ShieldFactoryInterface { - nux::ObjectPtr<AbstractShield> CreateShield(session::Manager::Ptr const&, - indicator::Indicators::Ptr const&, - Accelerators::Ptr const&, - nux::ObjectPtr<UserPromptView> const&, - int monitor, bool is_primary) override; + nux::ObjectPtr<BaseShield> CreateShield(session::Manager::Ptr const&, + indicator::Indicators::Ptr const&, + Accelerators::Ptr const&, + nux::ObjectPtr<AbstractUserPromptView> const&, + int monitor, bool is_primary) override; }; } } -#endif +#endif // UNITY_LOCKSCREEN_SHIELD_FACTORY diff --git a/lockscreen/UserPromptView.cpp b/lockscreen/UserPromptView.cpp index baf26c423..efc6277f1 100644 --- a/lockscreen/UserPromptView.cpp +++ b/lockscreen/UserPromptView.cpp @@ -100,7 +100,7 @@ std::string SanitizeMessage(std::string const& message) } UserPromptView::UserPromptView(session::Manager::Ptr const& session_manager) - : nux::View(NUX_TRACKER_LOCATION) + : AbstractUserPromptView(session_manager) , scale(1.0) , session_manager_(session_manager) , username_(nullptr) diff --git a/lockscreen/UserPromptView.h b/lockscreen/UserPromptView.h index f3cad1cb2..381ad8f50 100644 --- a/lockscreen/UserPromptView.h +++ b/lockscreen/UserPromptView.h @@ -27,6 +27,7 @@ #include <Nux/View.h> #include <UnityCore/SessionManager.h> +#include "LockScreenAbstractPromptView.h" #include "UserAuthenticatorPam.h" #include "unity-shared/IMTextEntry.h" @@ -44,7 +45,7 @@ class TextInput; namespace lockscreen { -class UserPromptView : public nux::View +class UserPromptView : public AbstractUserPromptView { public: UserPromptView(session::Manager::Ptr const& session_manager); diff --git a/plugins/networkarearegion/CMakeLists.txt b/plugins/networkarearegion/CMakeLists.txt index ea1ece005..7d7af425b 100644 --- a/plugins/networkarearegion/CMakeLists.txt +++ b/plugins/networkarearegion/CMakeLists.txt @@ -8,6 +8,11 @@ if(CMAKE_BUILD_TYPE STREQUAL "") set(revert_compiz TRUE) endif() +set (libdir ${CMAKE_INSTALL_LIBDIR}) +set (includedir ${CMAKE_INSTALL_INCLUDEDIR}) +set (libdir ${CMAKE_INSTALL_LIBDIR}) +set (datadir ${CMAKE_INSTALL_FULL_DATADIR}) + compiz_plugin (networkarearegion) if(revert_compiz) diff --git a/plugins/unity-mt-grab-handles/CMakeLists.txt b/plugins/unity-mt-grab-handles/CMakeLists.txt index ec13c9f0d..acaaa8db3 100644 --- a/plugins/unity-mt-grab-handles/CMakeLists.txt +++ b/plugins/unity-mt-grab-handles/CMakeLists.txt @@ -8,6 +8,11 @@ if(CMAKE_BUILD_TYPE STREQUAL "") set(revert_compiz TRUE) endif() +set (libdir ${CMAKE_INSTALL_LIBDIR}) +set (includedir ${CMAKE_INSTALL_INCLUDEDIR}) +set (libdir ${CMAKE_INSTALL_LIBDIR}) +set (datadir ${CMAKE_INSTALL_FULL_DATADIR}) + compiz_plugin (unitymtgrabhandles PKGDEPS nux-4.0>=4.0.0 PLUGINDEPS composite opengl CFLAGSADD -std=c++0x) if(revert_compiz) diff --git a/plugins/unityshell/CMakeLists.txt b/plugins/unityshell/CMakeLists.txt index 01a300589..b7e5b5f78 100644 --- a/plugins/unityshell/CMakeLists.txt +++ b/plugins/unityshell/CMakeLists.txt @@ -10,6 +10,11 @@ if(CMAKE_BUILD_TYPE STREQUAL "") set(revert_compiz TRUE) endif() +set (libdir ${CMAKE_INSTALL_LIBDIR}) +set (includedir ${CMAKE_INSTALL_INCLUDEDIR}) +set (libdir ${CMAKE_INSTALL_LIBDIR}) +set (datadir ${CMAKE_INSTALL_FULL_DATADIR}) + compiz_plugin (unityshell PKGDEPS ${UNITY_PLUGIN_DEPS} PLUGINDEPS composite opengl compiztoolbox scale @@ -50,4 +55,4 @@ set_target_properties(unityshell # # Data # -install (FILES plugin-unityshell.png DESTINATION ${DATADIR}/ccsm/icons/hicolor/64x64/apps) +install (FILES plugin-unityshell.png DESTINATION ${COMPIZ_DATADIR}/ccsm/icons/hicolor/64x64/apps) diff --git a/plugins/unityshell/src/inputremover.cpp b/plugins/unityshell/src/inputremover.cpp index b28e7a1e2..ec09f9eeb 100644 --- a/plugins/unityshell/src/inputremover.cpp +++ b/plugins/unityshell/src/inputremover.cpp @@ -19,12 +19,12 @@ * Sam Spilsbury <sam.spilsbury@canonical.com> */ -#include <cstdlib> -#include <boost/scoped_array.hpp> #include "inputremover.h" +#include <cstdlib> #include <X11/Xregion.h> #include <cstdio> #include <cstring> +#include <vector> namespace { @@ -347,8 +347,7 @@ compiz::WindowInputRemover::writeProperty (XRectangle *input, */ const size_t dataSize = headerSize + (nInput * 4); - boost::scoped_array<unsigned long> data(new unsigned long[dataSize]); - + std::vector<unsigned long> data(dataSize); data[0] = propVersion; data[1] = nInput; data[2] = inputOrdering; @@ -370,7 +369,7 @@ compiz::WindowInputRemover::writeProperty (XRectangle *input, type, fmt, PropModeReplace, - reinterpret_cast<unsigned char*>(data.get()), + reinterpret_cast<unsigned char*>(data.data()), dataSize); return true; diff --git a/po/POTFILES.in b/po/POTFILES.in index 66c7663f6..3e3dffb84 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -29,13 +29,13 @@ lockscreen/UserPromptView.cpp panel/PanelMenuView.cpp plugins/networkarearegion/networkarearegion.xml.in plugins/unity-mt-grab-handles/unitymtgrabhandles.xml.in -plugins/unityshell/src/unity-dash-view-accessible.cpp -plugins/unityshell/src/unity-launcher-accessible.cpp -plugins/unityshell/src/unity-launcher-icon-accessible.cpp -plugins/unityshell/src/unity-quicklist-menu-accessible.cpp -plugins/unityshell/src/unity-scope-bar-icon-accessible.cpp -plugins/unityshell/src/unity-search-bar-accessible.cpp -plugins/unityshell/src/unity-switcher-accessible.cpp +a11y/unity-dash-view-accessible.cpp +a11y/unity-launcher-accessible.cpp +a11y/unity-launcher-icon-accessible.cpp +a11y/unity-quicklist-menu-accessible.cpp +a11y/unity-scope-bar-icon-accessible.cpp +a11y/unity-search-bar-accessible.cpp +a11y/unity-switcher-accessible.cpp plugins/unityshell/src/unityshell.cpp plugins/unityshell/unityshell.xml.in shortcuts/ShortcutHintPrivate.cpp diff --git a/resources/login.svg b/resources/login.svg new file mode 100644 index 000000000..de2ebeacd --- /dev/null +++ b/resources/login.svg @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 34 34" enable-background="new 0 0 34 34" xml:space="preserve"> +<rect x="0" display="none" fill="#CABADA" width="34" height="34"/> +<polygon fill="#1A2A7C" points="7,16 21.6,16 16,10 20,10 26.9,17.5 20,25 16,25 21.5,19 7,19 "/> +</svg> diff --git a/resources/switch_user.svg b/resources/switch_user.svg new file mode 100644 index 000000000..0a2311c05 --- /dev/null +++ b/resources/switch_user.svg @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 34 34" enable-background="new 0 0 34 34" xml:space="preserve"> +<rect x="0" display="none" fill="#CABADA" width="34" height="34"/> +<polygon display="none" fill="#1A2A7C" points="7,16 21.6,16 16,10 20,10 26.9,17.5 20,25 16,25 21.5,19 7,19 "/> +<g> + <path fill="#FFFFFF" d="M17,1c8.8,0,16,7.2,16,16s-7.2,16-16,16S1,25.8,1,17S8.1,1,17,1 M17,0C7.6,0,0,7.6,0,17s7.6,17,17,17 + s17-7.6,17-17S26.3,0,17,0L17,0z"/> +</g> +<polygon fill="#FFFFFF" points="13.9,9.6 19.2,9.6 14.9,14.8 27.6,14.8 27.6,20.1 14.8,20.1 19.1,25.4 13.9,25.4 6.4,17.5 "/> +</svg> diff --git a/services/CMakeLists.txt b/services/CMakeLists.txt index b80ec71ba..13a61716b 100644 --- a/services/CMakeLists.txt +++ b/services/CMakeLists.txt @@ -51,10 +51,10 @@ link_directories(${LIB_PATHS}) add_executable(unity-panel-service ${PANEL_SOURCES}) target_link_libraries(unity-panel-service ${LIBS}) -install(TARGETS unity-panel-service DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/unity/) +install(TARGETS unity-panel-service DESTINATION ${CMAKE_INSTALL_LIBDIR}/unity/) configure_file(unity-panel-service.conf.in ${CMAKE_CURRENT_BINARY_DIR}/unity-panel-service.conf) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/unity-panel-service.conf DESTINATION ${CMAKE_INSTALL_PREFIX}/share/upstart/sessions) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/unity-panel-service.conf DESTINATION ${CMAKE_INSTALL_DATADIR}/upstart/sessions) configure_file(unity-panel-service-lockscreen.conf.in ${CMAKE_CURRENT_BINARY_DIR}/unity-panel-service-lockscreen.conf) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/unity-panel-service-lockscreen.conf DESTINATION ${CMAKE_INSTALL_PREFIX}/share/upstart/sessions) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/unity-panel-service-lockscreen.conf DESTINATION ${CMAKE_INSTALL_DATADIR}/upstart/sessions) diff --git a/services/panel-indicator-entry-accessible.c b/services/panel-indicator-entry-accessible.c index 459812dff..55f45d297 100644 --- a/services/panel-indicator-entry-accessible.c +++ b/services/panel-indicator-entry-accessible.c @@ -293,7 +293,7 @@ panel_indicator_entry_accessible_ref_child (AtkObject *accessible, gint i) g_return_val_if_fail (PANEL_IS_INDICATOR_ENTRY_ACCESSIBLE (accessible), NULL); piea = PANEL_INDICATOR_ENTRY_ACCESSIBLE (accessible); - if (piea->priv->entry->parent_object && GTK_IS_MENU (piea->priv->entry->menu)) + if (piea->priv->entry && piea->priv->entry->parent_object && GTK_IS_MENU (piea->priv->entry->menu)) { child = gtk_widget_get_accessible (GTK_WIDGET (piea->priv->entry->menu)); atk_object_set_parent (child, accessible); diff --git a/services/unity-panel-service-lockscreen.conf.in b/services/unity-panel-service-lockscreen.conf.in index b6a3cb600..b9255d825 100644 --- a/services/unity-panel-service-lockscreen.conf.in +++ b/services/unity-panel-service-lockscreen.conf.in @@ -5,4 +5,4 @@ start on desktop-lock stop on desktop-unlock respawn -exec ${CMAKE_INSTALL_PREFIX}/lib/unity/unity-panel-service --lockscreen-mode \ No newline at end of file +exec ${CMAKE_INSTALL_FULL_LIBDIR}/unity/unity-panel-service --lockscreen-mode diff --git a/services/unity-panel-service.conf.in b/services/unity-panel-service.conf.in index 742e39b1f..62712f833 100644 --- a/services/unity-panel-service.conf.in +++ b/services/unity-panel-service.conf.in @@ -15,4 +15,4 @@ emits indicator-services-start emits indicator-services-end respawn -exec ${CMAKE_INSTALL_PREFIX}/lib/unity/unity-panel-service +exec ${CMAKE_INSTALL_FULL_LIBDIR}/unity/unity-panel-service diff --git a/shutdown/StandaloneSession.cpp b/shutdown/StandaloneSession.cpp index f9390f356..ade557cee 100644 --- a/shutdown/StandaloneSession.cpp +++ b/shutdown/StandaloneSession.cpp @@ -39,6 +39,7 @@ public: std::string RealName() const { return "Marco Trevisan"; } std::string UserName() const { return "marco"; } std::string HostName() const { return "tricky"; } + void UserIconFile(std::function<void(std::string const&)> const&) const { std::cout << "UserIconFile" << std::endl; } void ScreenSaverActivate() { std::cout << "ScreenSaverActivate" << std::endl; } void ScreenSaverDeactivate() { std::cout << "ScreenSaverDeactivate" << std::endl; } @@ -49,6 +50,7 @@ public: void Shutdown() { std::cout << "Shutdown" << std::endl; } void Suspend() { std::cout << "Suspend" << std::endl; } void Hibernate() { std::cout << "Hibernate" << std::endl; } + void SwitchToGreeter() { std::cout << "SwitchToGreeter" << std::endl; } void CancelAction() { std::cout << "CancelAction" << std::endl; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9bcf0a582..17ea9b758 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -80,6 +80,7 @@ if (GMOCK_LIB AND set (GTEST_SLOW_SOURCES test_main.cpp logger_helper.cpp + mock-application.cpp test_switcher_controller_slow.cpp test_switcher_controller_class.cpp test_tooltip_manager.cpp diff --git a/tests/mock-application.h b/tests/mock-application.h index 312168854..0ee200f9d 100644 --- a/tests/mock-application.h +++ b/tests/mock-application.h @@ -91,7 +91,7 @@ struct MockApplicationWindow : unity::ApplicationWindow return; title_ = new_title; - title.changed(title_); + title.changed.emit(title_); } void SetIcon(std::string const& new_icon) @@ -100,7 +100,16 @@ struct MockApplicationWindow : unity::ApplicationWindow return; icon_ = new_icon; - icon.changed(icon_); + icon.changed.emit(icon_); + } + + void SetMonitor(int new_monitor) + { + if (monitor_ == new_monitor) + return; + + monitor_ = new_monitor; + monitor.changed.emit(monitor_); } }; @@ -329,6 +338,7 @@ struct MockApplicationManager : public unity::ApplicationManager MOCK_CONST_METHOD0(GetActiveApplication, unity::ApplicationPtr()); MOCK_CONST_METHOD1(GetWindowsForMonitor, unity::WindowList(int)); MOCK_CONST_METHOD1(GetWindowForId, unity::ApplicationWindowPtr(Window)); + MOCK_CONST_METHOD3(FocusWindowGroup, void(unity::WindowList const&, bool, int)); unity::ApplicationPtr LocalGetApplicationForDesktopFile(std::string const& desktop_file) { diff --git a/tests/test_application_launcher_icon.cpp b/tests/test_application_launcher_icon.cpp index 41688d36d..c34c39b6c 100644 --- a/tests/test_application_launcher_icon.cpp +++ b/tests/test_application_launcher_icon.cpp @@ -50,7 +50,8 @@ struct MockApplicationLauncherIcon : ApplicationLauncherIcon typedef nux::ObjectPtr<MockApplicationLauncherIcon> Ptr; MockApplicationLauncherIcon(ApplicationPtr const& app) - : ApplicationLauncherIcon(app) + : WindowedLauncherIcon(IconType::APPLICATION) + , ApplicationLauncherIcon(app) { ON_CALL(*this, Stick(_)).WillByDefault(Invoke([this] (bool save) { ApplicationLauncherIcon::Stick(save); })); ON_CALL(*this, Stick()).WillByDefault(Invoke([this] { ApplicationLauncherIcon::Stick(); })); @@ -67,11 +68,14 @@ struct MockApplicationLauncherIcon : ApplicationLauncherIcon bool LauncherIconIsSticky() const { return LauncherIcon::IsSticky(); } void LocalActivate(ActionArg a) { ApplicationLauncherIcon::ActivateLauncherIcon(a); } - using ApplicationLauncherIcon::IsFileManager; using ApplicationLauncherIcon::LogUnityEvent; using ApplicationLauncherIcon::Remove; using ApplicationLauncherIcon::SetApplication; using ApplicationLauncherIcon::GetApplication; + using ApplicationLauncherIcon::PerformScroll; + using LauncherIcon::BackgroundColor; + using LauncherIcon::GetRemoteUri; + using LauncherIcon::AllowDetailViewInSwitcher; }; MATCHER_P(AreArgsEqual, a, "") @@ -90,15 +94,15 @@ struct TestApplicationLauncherIcon : testmocks::TestUnityAppBase virtual void SetUp() override { usc_app = std::make_shared<MockApplication::Nice>(USC_DESKTOP, "softwarecenter"); - usc_icon = new NiceMock<MockApplicationLauncherIcon>(usc_app); + usc_icon = new MockApplicationLauncherIcon(usc_app); ASSERT_EQ(usc_icon->DesktopFile(), USC_DESKTOP); empty_app = std::make_shared<MockApplication::Nice>(NO_ICON_DESKTOP); - empty_icon = new NiceMock<MockApplicationLauncherIcon>(empty_app); + empty_icon = new MockApplicationLauncherIcon(empty_app); ASSERT_EQ(empty_icon->DesktopFile(), NO_ICON_DESKTOP); mock_app = std::make_shared<MockApplication::Nice>(); - mock_icon = new NiceMock<MockApplicationLauncherIcon>(mock_app); + mock_icon = new MockApplicationLauncherIcon(mock_app); ASSERT_TRUE(mock_icon->DesktopFile().empty()); } @@ -173,7 +177,7 @@ TEST_F(TestApplicationLauncherIcon, ApplicationSignalDisconnection) { std::shared_ptr<MockApplication> app = std::make_shared<MockApplication::Nice>(USC_DESKTOP); { - MockApplicationLauncherIcon::Ptr icon(new NiceMock<MockApplicationLauncherIcon>(app)); + MockApplicationLauncherIcon::Ptr icon(new MockApplicationLauncherIcon(app)); EXPECT_FALSE(app->closed.empty()); } @@ -266,7 +270,7 @@ TEST_F(TestApplicationLauncherIcon, StickStickedDesktopApp) auto app = std::make_shared<MockApplication::Nice>(USC_DESKTOP); app->sticky = true; app->desktop_file_ = UM_DESKTOP; - MockApplicationLauncherIcon::Ptr icon(new NiceMock<MockApplicationLauncherIcon>(app)); + MockApplicationLauncherIcon::Ptr icon(new MockApplicationLauncherIcon(app)); ASSERT_TRUE(icon->IsSticky()); EXPECT_TRUE(icon->LauncherIconIsSticky()); } @@ -275,7 +279,7 @@ TEST_F(TestApplicationLauncherIcon, StickStickedDesktopLessApp) { auto app = std::make_shared<MockApplication::Nice>(); app->sticky = true; - MockApplicationLauncherIcon::Ptr icon(new NiceMock<MockApplicationLauncherIcon>(app)); + MockApplicationLauncherIcon::Ptr icon(new MockApplicationLauncherIcon(app)); ASSERT_FALSE(icon->IsSticky()); EXPECT_FALSE(icon->LauncherIconIsSticky()); } @@ -291,7 +295,7 @@ TEST_F(TestApplicationLauncherIcon, StickAndSaveDesktopAppDontCreateNewDesktop) TEST_F(TestApplicationLauncherIcon, StickAndSaveDesktopLessAppCreatesNewDesktop) { auto app = std::make_shared<MockApplication::Nice>(); - MockApplicationLauncherIcon::Ptr icon(new NiceMock<MockApplicationLauncherIcon>(app)); + MockApplicationLauncherIcon::Ptr icon(new MockApplicationLauncherIcon(app)); EXPECT_CALL(*app, CreateLocalDesktopFile()); icon->Stick(true); @@ -354,7 +358,7 @@ TEST_F(TestApplicationLauncherIcon, UnstickDesktopAppLogEvents) TEST_F(TestApplicationLauncherIcon, UnstickDesktopLessAppLogEvent) { auto app = std::make_shared<MockApplication::Nice>(); - MockApplicationLauncherIcon::Ptr icon(new NiceMock<MockApplicationLauncherIcon>(app)); + MockApplicationLauncherIcon::Ptr icon(new MockApplicationLauncherIcon(app)); EXPECT_CALL(*unity_app_, LogEvent(ApplicationEventType::ACCESS, _)).Times(0); icon->UnStick(); @@ -1103,25 +1107,6 @@ TEST_F(TestApplicationLauncherIcon, QuicklistMenuItemRemoteOverridesQuitByProper dbusmenu_menuitem_handle_event(item, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0); } -TEST_F(TestApplicationLauncherIcon, IsFileManager) -{ - EXPECT_FALSE(usc_icon->IsFileManager()); - EXPECT_FALSE(empty_icon->IsFileManager()); - EXPECT_FALSE(mock_icon->IsFileManager()); - - auto app = std::make_shared<MockApplication::Nice>("/any/path/org.gnome.Nautilus.desktop", "Nautilus"); - MockApplicationLauncherIcon::Ptr icon(new NiceMock<MockApplicationLauncherIcon>(app)); - EXPECT_TRUE(icon->IsFileManager()); - - app = std::make_shared<MockApplication::Nice>("/any/path/nautilus-folder-handler.desktop", "Nautilus"); - icon = new NiceMock<MockApplicationLauncherIcon>(app); - EXPECT_TRUE(icon->IsFileManager()); - - app = std::make_shared<MockApplication::Nice>("/any/path/nautilus-home.desktop", "Nautilus"); - icon = new NiceMock<MockApplicationLauncherIcon>(app); - EXPECT_TRUE(icon->IsFileManager()); -} - TEST_F(TestApplicationLauncherIcon, AllowDetailViewInSwitcher) { mock_app->type_ = AppType::NORMAL; @@ -1232,7 +1217,7 @@ TEST_F(TestApplicationLauncherIcon, DestructionDontUnsetsAppSeenIfReplaced) mock_icon->Remove(); ASSERT_FALSE(mock_app->seen); - MockApplicationLauncherIcon::Ptr new_icon(new NiceMock<MockApplicationLauncherIcon>(mock_app)); + MockApplicationLauncherIcon::Ptr new_icon(new MockApplicationLauncherIcon(mock_app)); mock_icon = nullptr; EXPECT_TRUE(mock_app->seen); diff --git a/tests/test_gnome_session_manager.cpp b/tests/test_gnome_session_manager.cpp index d44c3b7ec..e009ab483 100644 --- a/tests/test_gnome_session_manager.cpp +++ b/tests/test_gnome_session_manager.cpp @@ -42,6 +42,7 @@ const std::string LOGIND_SESSION_PATH = "/org/freedesktop/login1/session/id0"; const std::string CONSOLE_KIT_PATH = "/org/freedesktop/ConsoleKit/Manager"; const std::string SESSION_MANAGER_PATH = "/org/gnome/SessionManager"; const std::string SESSION_MANAGER_PRESENCE_PATH = "/org/gnome/SessionManager/Presence"; +const std::string DISPLAY_MANAGER_SEAT_PATH = "/org/freedesktop/DisplayManager/Seat0"; const std::string SESSION_OPTIONS = "com.canonical.indicator.session"; const std::string SUPPRESS_DIALOGS_KEY = "suppress-logout-restart-shutdown"; @@ -137,6 +138,13 @@ R"(<node> </node> )"; +const std::string DISPLAY_MANAGER_SEAT = +R"(<node> + <interface name="org.freedesktop.DisplayManager.Seat"> + <method name="SwitchToGreeter"/> + </interface> +</node> +)"; } struct MockGnomeSessionManager : session::GnomeManager { @@ -208,6 +216,9 @@ struct TestGnomeSessionManager : testing::Test return nullptr; }); + display_manager_seat_ = std::make_shared<DBusServer>(); + display_manager_seat_->AddObjects(introspection::DISPLAY_MANAGER_SEAT, DISPLAY_MANAGER_SEAT_PATH); + manager = std::make_shared<MockGnomeSessionManager>(); shell_proxy_ = std::make_shared<DBusProxy>(TEST_SERVER_NAME, SHELL_OBJECT_PATH, SHELL_INTERFACE); @@ -228,6 +239,7 @@ struct TestGnomeSessionManager : testing::Test Utils::WaitUntilMSec([] { return logind_->IsConnected(); }); Utils::WaitUntilMSec([] { return console_kit_->IsConnected(); }); Utils::WaitUntilMSec([] { return session_manager_->IsConnected(); }); + Utils::WaitUntilMSec([] { return display_manager_seat_->IsConnected(); }); Utils::WaitUntilMSec([] { return shell_proxy_->IsConnected();}); ASSERT_TRUE(shell_proxy_->IsConnected()); EnableInteractiveShutdown(true); @@ -277,6 +289,7 @@ struct TestGnomeSessionManager : testing::Test logind_.reset(); console_kit_.reset(); session_manager_.reset(); + display_manager_seat_.reset(); } bool SettingsAvailable() @@ -342,6 +355,7 @@ struct TestGnomeSessionManager : testing::Test static DBusServer::Ptr console_kit_; static DBusServer::Ptr logind_; static DBusServer::Ptr session_manager_; + static DBusServer::Ptr display_manager_seat_; static DBusProxy::Ptr shell_proxy_; }; @@ -350,6 +364,7 @@ DBusServer::Ptr TestGnomeSessionManager::upower_; DBusServer::Ptr TestGnomeSessionManager::console_kit_; DBusServer::Ptr TestGnomeSessionManager::logind_; DBusServer::Ptr TestGnomeSessionManager::session_manager_; +DBusServer::Ptr TestGnomeSessionManager::display_manager_seat_; DBusProxy::Ptr TestGnomeSessionManager::shell_proxy_; bool TestGnomeSessionManager::can_shutdown_; bool TestGnomeSessionManager::can_suspend_; @@ -390,6 +405,23 @@ TEST_F(TestGnomeSessionManager, HostName) EXPECT_EQ(manager->HostName(), g_get_host_name()); } +TEST_F(TestGnomeSessionManager, SwitchToGreeter) +{ + bool switch_called = false; + + display_manager_seat_->GetObjects().front()->SetMethodsCallsHandler([&] (std::string const& method, GVariant*) { + if (method == "SwitchToGreeter") + switch_called = true; + + return static_cast<GVariant*>(nullptr); + }); + + manager->SwitchToGreeter(); + + Utils::WaitUntilMSec(switch_called); + EXPECT_TRUE(switch_called); +} + TEST_F(TestGnomeSessionManager, ScreenSaverActivate) { bool signal_emitted = false; diff --git a/tests/test_launcher_controller.cpp b/tests/test_launcher_controller.cpp index 3612758da..a90005ef7 100644 --- a/tests/test_launcher_controller.cpp +++ b/tests/test_launcher_controller.cpp @@ -137,8 +137,10 @@ private: struct MockApplicationLauncherIcon : ApplicationLauncherIcon { - typedef NiceMock<MockApplicationLauncherIcon> Nice; - typedef nux::ObjectPtr<MockApplicationLauncherIcon::Nice> Ptr; + // NiceMock doesn't work well with Virtual Inheritance, so we need to disable it + //typedef NiceMock<MockApplicationLauncherIcon> Nice; + typedef MockApplicationLauncherIcon Nice; + typedef nux::ObjectPtr<MockApplicationLauncherIcon> Ptr; typedef bool Fake; MockApplicationLauncherIcon(Fake = true, std::string const& remote_uri = "") @@ -155,7 +157,8 @@ struct MockApplicationLauncherIcon : ApplicationLauncherIcon } explicit MockApplicationLauncherIcon(ApplicationPtr const& app) - : ApplicationLauncherIcon(app) + : WindowedLauncherIcon(IconType::APPLICATION) + , ApplicationLauncherIcon(app) { ON_CALL(*this, Stick(_)).WillByDefault(Invoke([this] (bool save) { ApplicationLauncherIcon::Stick(save); })); ON_CALL(*this, UnStick()).WillByDefault(Invoke([this] { ApplicationLauncherIcon::UnStick(); })); @@ -171,15 +174,18 @@ struct MockApplicationLauncherIcon : ApplicationLauncherIcon MOCK_CONST_METHOD0(GetRemoteUri, std::string()); MOCK_METHOD1(Stick, void(bool)); MOCK_METHOD0(UnStick, void()); - MOCK_METHOD0(Quit, void()); + MOCK_CONST_METHOD0(Quit, void()); }; struct MockVolumeLauncherIcon : public VolumeLauncherIcon { typedef nux::ObjectPtr<MockVolumeLauncherIcon> Ptr; + // typedef NiceMock<MockVolumeLauncherIcon> Nice; + typedef MockVolumeLauncherIcon Nice; MockVolumeLauncherIcon() - : VolumeLauncherIcon(Volume::Ptr(volume_ = new NiceMock<MockVolume>()), + : WindowedLauncherIcon(IconType::DEVICE) + , VolumeLauncherIcon(Volume::Ptr(volume_ = new NiceMock<MockVolume>()), std::make_shared<MockDevicesSettings::Nice>(), std::make_shared<MockDeviceNotificationDisplay::Nice>(), std::make_shared<MockFileManager::Nice>()) @@ -270,7 +276,7 @@ protected: void DisconnectSignals() { ApplicationManager::Default().application_started.clear(); - Impl()->device_section_.icon_added.clear(); + Impl()->device_section_->icon_added.clear(); Impl()->model_->icon_removed.clear(); Impl()->model_->saved.clear(); Impl()->model_->order_changed.clear(); @@ -660,8 +666,8 @@ TEST_F(TestLauncherController, CreateFavoriteInvalidDesktopFile) TEST_F(TestLauncherController, CreateFavoriteDevice) { - lc.Impl()->device_section_ = MockDeviceLauncherSection(); - auto const& icons = lc.Impl()->device_section_.GetIcons(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(); + auto const& icons = lc.Impl()->device_section_->GetIcons(); auto const& device_icon = icons.front(); ASSERT_TRUE(device_icon.IsValid()); @@ -923,8 +929,8 @@ TEST_F(TestLauncherController, AddDevices) { lc.ClearModel(); lc.DisconnectSignals(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(); - auto const& icons = lc.Impl()->device_section_.GetIcons(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(); + auto const& icons = lc.Impl()->device_section_->GetIcons(); auto const& device_icon1 = icons.front(); auto const& device_icon2 = *(std::next(icons.begin())); @@ -969,7 +975,7 @@ TEST_F(TestLauncherController, MigrateFavoritesUnneeded) TEST_F(TestLauncherController, SetupIcons) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(); lc.Impl()->expo_icon_->UnStick(); lc.Impl()->desktop_icon_->UnStick(); auto const& model = lc.Impl()->model_; @@ -990,7 +996,7 @@ TEST_F(TestLauncherController, SetupIcons) fav = lc.Impl()->GetIconByUri(FavoriteStore::URI_PREFIX_APP + app::SW_CENTER); EXPECT_EQ(model->IconIndex(fav), ++icon_index); - for (auto const& device : lc.Impl()->device_section_.GetIcons()) + for (auto const& device : lc.Impl()->device_section_->GetIcons()) ASSERT_EQ(model->IconIndex(device), ++icon_index); fav = lc.Impl()->GetIconByUri(FavoriteStore::URI_PREFIX_APP + app::UPDATE_MANAGER); @@ -1015,7 +1021,7 @@ TEST_F(TestLauncherController, SetupIcons) TEST_F(TestLauncherController, ResetIconPriorities) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(); auto const& model = lc.Impl()->model_; favorite_store.AddFavorite(places::APPS_URI, -1); @@ -1032,7 +1038,7 @@ TEST_F(TestLauncherController, ResetIconPriorities) int icon_index = -1; - for (auto const& device : lc.Impl()->device_section_.GetIcons()) + for (auto const& device : lc.Impl()->device_section_->GetIcons()) ASSERT_EQ(model->IconIndex(device), ++icon_index); auto fav = lc.Impl()->GetIconByUri(FavoriteStore::URI_PREFIX_APP + app::SW_CENTER); @@ -1063,8 +1069,8 @@ TEST_F(TestLauncherController, ResetIconPriorities) TEST_F(TestLauncherController, GetLastIconPriorityUnSticky) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(3); - auto const& device_icons = lc.Impl()->device_section_.GetIcons(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(3); + auto const& device_icons = lc.Impl()->device_section_->GetIcons(); auto const& last_device = device_icons.back(); favorite_store.SetFavorites({ places::DEVICES_URI, @@ -1080,8 +1086,8 @@ TEST_F(TestLauncherController, GetLastIconPriorityUnSticky) TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithAllStickyIcons) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(3); - auto const& device_icons = lc.Impl()->device_section_.GetIcons(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(3); + auto const& device_icons = lc.Impl()->device_section_->GetIcons(); auto const& last_device = device_icons.back(); favorite_store.SetFavorites({ places::DEVICES_URI, @@ -1100,8 +1106,8 @@ TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithAllStickyIcons) TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithSomeStickyIcons) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(3); - auto const& device_icons = lc.Impl()->device_section_.GetIcons(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(3); + auto const& device_icons = lc.Impl()->device_section_->GetIcons(); auto const& first_device = *(std::next(device_icons.rbegin())); auto const& last_device = device_icons.back(); @@ -1120,7 +1126,7 @@ TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithSomeStickyIcons) TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithNoIcons) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(0); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(0); lc.Impl()->SetupIcons(); lc.DisconnectSignals(); @@ -1131,7 +1137,7 @@ TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithNoIcons) TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithNoIconsAndUri) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(0); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(0); favorite_store.SetFavorites({ places::DEVICES_URI, FavoriteStore::URI_PREFIX_APP + app::SW_CENTER }); @@ -1156,11 +1162,11 @@ TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithNoIconsAndUri) TEST_F(TestLauncherController, GetLastIconPrioritySticky) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(3); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(3); lc.Impl()->SetupIcons(); lc.DisconnectSignals(); - auto const& device_icons = lc.Impl()->device_section_.GetIcons(); + auto const& device_icons = lc.Impl()->device_section_->GetIcons(); auto const& first_device = device_icons.front(); int last_priority = lc.Impl()->GetLastIconPriority<VolumeLauncherIcon>("", true); @@ -1170,8 +1176,8 @@ TEST_F(TestLauncherController, GetLastIconPrioritySticky) TEST_F(TestLauncherController, GetLastIconPriorityStickyWithAllStickyIcons) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(3); - auto const& device_icons = lc.Impl()->device_section_.GetIcons(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(3); + auto const& device_icons = lc.Impl()->device_section_->GetIcons(); auto const& last_device = device_icons.back(); favorite_store.SetFavorites({ places::DEVICES_URI, @@ -1190,8 +1196,8 @@ TEST_F(TestLauncherController, GetLastIconPriorityStickyWithAllStickyIcons) TEST_F(TestLauncherController, GetLastIconPriorityStickyWithSomeStickyIcons) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(3); - auto const& device_icons = lc.Impl()->device_section_.GetIcons(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(3); + auto const& device_icons = lc.Impl()->device_section_->GetIcons(); auto const& first_device = *(std::next(device_icons.rbegin())); favorite_store.SetFavorites({ places::DEVICES_URI, @@ -1209,7 +1215,7 @@ TEST_F(TestLauncherController, GetLastIconPriorityStickyWithSomeStickyIcons) TEST_F(TestLauncherController, GetLastIconPriorityStickyWithNoIcons) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(0); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(0); lc.Impl()->SetupIcons(); lc.DisconnectSignals(); @@ -1260,8 +1266,8 @@ TEST_F(TestLauncherController, LauncherAddRequestApplicationStick) TEST_F(TestLauncherController, LauncherAddRequestDeviceAdd) { auto const& model = lc.Impl()->model_; - lc.Impl()->device_section_ = MockDeviceLauncherSection(); - auto const& icons = lc.Impl()->device_section_.GetIcons(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(); + auto const& icons = lc.Impl()->device_section_->GetIcons(); auto const& device_icon = icons.front(); auto const& icon_uri = device_icon->RemoteUri(); @@ -1282,7 +1288,7 @@ TEST_F(TestLauncherController, LauncherAddRequestDeviceAdd) TEST_F(TestLauncherController, LauncherAddRequestDeviceStick) { auto const& model = lc.Impl()->model_; - MockVolumeLauncherIcon::Ptr device_icon(new NiceMock<MockVolumeLauncherIcon>()); + MockVolumeLauncherIcon::Ptr device_icon(new MockVolumeLauncherIcon::Nice()); lc.Impl()->RegisterIcon(device_icon, std::numeric_limits<int>::max()); auto app_icons = model->GetSublist<ApplicationLauncherIcon>(); @@ -1307,7 +1313,7 @@ TEST_F(TestLauncherController, LauncherRemoveRequestApplicationUnStickAndQuit) TEST_F(TestLauncherController, LauncherRemoveRequestDeviceEjects) { - MockVolumeLauncherIcon::Ptr device_icon(new NiceMock<MockVolumeLauncherIcon>()); + MockVolumeLauncherIcon::Ptr device_icon(new MockVolumeLauncherIcon::Nice()); EXPECT_CALL(*(device_icon->volume_), CanBeEjected()) .WillRepeatedly(Return(true)); @@ -1322,7 +1328,7 @@ TEST_F(TestLauncherController, LauncherRemoveRequestDeviceEjects) TEST_F(TestLauncherController, LauncherRemoveRequestDeviceStops) { - MockVolumeLauncherIcon::Ptr device_icon(new NiceMock<MockVolumeLauncherIcon>()); + MockVolumeLauncherIcon::Ptr device_icon(new MockVolumeLauncherIcon::Nice()); EXPECT_CALL(*(device_icon->volume_), CanBeEjected()) .WillRepeatedly(Return(false)); @@ -1382,7 +1388,7 @@ TEST_F(TestLauncherController, SaveIconsOrder) invisible_app->SetQuirk(AbstractLauncherIcon::Quirk::VISIBLE, false); lc.Impl()->RegisterIcon(invisible_app, ++priority); - MockVolumeLauncherIcon::Ptr sticky_device(new NiceMock<MockVolumeLauncherIcon>()); + MockVolumeLauncherIcon::Ptr sticky_device(new MockVolumeLauncherIcon::Nice()); sticky_device->Stick(false); lc.Impl()->RegisterIcon(sticky_device, ++priority); @@ -1413,7 +1419,7 @@ TEST_F(TestLauncherController, SaveIconsOrderWithOnlyStickyIcons) sticky_app->Stick(false); lc.Impl()->RegisterIcon(sticky_app, ++priority); - MockVolumeLauncherIcon::Ptr sticky_device(new NiceMock<MockVolumeLauncherIcon>()); + MockVolumeLauncherIcon::Ptr sticky_device(new MockVolumeLauncherIcon::Nice()); sticky_device->Stick(false); lc.Impl()->RegisterIcon(sticky_device, ++priority); @@ -1442,7 +1448,7 @@ TEST_F(TestLauncherController, SaveIconsOrderTriesToKeepIconProvidersOrder) sticky_app->Stick(false); lc.Impl()->RegisterIcon(sticky_app, ++priority); - MockVolumeLauncherIcon::Ptr sticky_device(new NiceMock<MockVolumeLauncherIcon>()); + MockVolumeLauncherIcon::Ptr sticky_device(new MockVolumeLauncherIcon::Nice()); sticky_device->Stick(false); lc.Impl()->RegisterIcon(sticky_device, ++priority); @@ -1467,7 +1473,7 @@ TEST_F(TestLauncherController, SaveIconsOrderTriesToKeepIconProvidersOrder2) sticky_app->Stick(false); lc.Impl()->RegisterIcon(sticky_app, ++priority); - MockVolumeLauncherIcon::Ptr sticky_device(new NiceMock<MockVolumeLauncherIcon>()); + MockVolumeLauncherIcon::Ptr sticky_device(new MockVolumeLauncherIcon::Nice()); sticky_device->Stick(false); lc.Impl()->RegisterIcon(sticky_device, ++priority); @@ -1617,9 +1623,9 @@ TEST_F(TestLauncherController, OnFavoriteStoreFavoriteAddedStickAfter) TEST_F(TestLauncherController, OnFavoriteStoreFavoriteAddedDeviceSection) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(); auto const& model = lc.Impl()->model_; - auto const& icons = lc.Impl()->device_section_.GetIcons(); + auto const& icons = lc.Impl()->device_section_->GetIcons(); auto const& device_icon1(icons.front()); auto const& device_icon2(*(std::next(icons.begin()))); @@ -1654,10 +1660,10 @@ TEST_F(TestLauncherController, OnFavoriteStoreFavoriteRemovedApplication) TEST_F(TestLauncherController, OnFavoriteStoreFavoriteRemovedDevice) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(); auto const& model = lc.Impl()->model_; - auto const& icons = lc.Impl()->device_section_.GetIcons(); + auto const& icons = lc.Impl()->device_section_->GetIcons(); auto const& device_icon(icons.front()); favorite_store.SetFavorites({ lc.Impl()->expo_icon_->RemoteUri(), @@ -1680,10 +1686,10 @@ TEST_F(TestLauncherController, OnFavoriteStoreFavoriteRemovedDevice) TEST_F(TestLauncherController, OnFavoriteStoreFavoriteRemovedDeviceSection) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(); auto const& model = lc.Impl()->model_; - auto const& icons = lc.Impl()->device_section_.GetIcons(); + auto const& icons = lc.Impl()->device_section_->GetIcons(); auto const& device_icon1(icons.front()); auto const& device_icon2(*(std::next(icons.begin()))); @@ -1978,10 +1984,9 @@ TEST_F(TestLauncherController, IconShowsOnQuickApplicationReopen) unity::glib::Object<BamfMockApplication> bamf_mock_application(bamf_mock_application_new()); ApplicationPtr app(new unity::bamf::Application(mock_manager, unity::glib::object_cast<BamfApplication>(bamf_mock_application))); - MockApplicationLauncherIcon::Ptr our_icon; - + AbstractLauncherIcon::Ptr our_icon; mock_manager.Default().application_started.emit(app); - + app->title.changed.emit("Hello"); auto app_icons = lc.Impl()->model_->GetSublist<ApplicationLauncherIcon>(); @@ -1991,7 +1996,7 @@ TEST_F(TestLauncherController, IconShowsOnQuickApplicationReopen) { our_icon = icon; break; - } + } } ASSERT_TRUE(our_icon); EXPECT_FALSE(our_icon->removed); diff --git a/tests/test_lockscreen_controller.cpp b/tests/test_lockscreen_controller.cpp index d77f0a298..3fcdf520b 100644 --- a/tests/test_lockscreen_controller.cpp +++ b/tests/test_lockscreen_controller.cpp @@ -20,7 +20,7 @@ #include <gmock/gmock.h> using namespace testing; -#include "lockscreen/UserPromptView.h" +#include "lockscreen/LockScreenAbstractPromptView.h" #include "lockscreen/LockScreenController.h" #include <Nux/NuxTimerTickSource.h> @@ -51,26 +51,27 @@ const unsigned TICK_DURATION = 10 * 1000; } -struct MockShield : AbstractShield +struct MockShield : BaseShield { MockShield() - : AbstractShield(nullptr, nullptr, nullptr, nux::ObjectPtr<UserPromptView>(), 0, false) + : BaseShield(nullptr, nullptr, nullptr, nux::ObjectPtr<AbstractUserPromptView>(), 0, false) {} MOCK_CONST_METHOD0(IsIndicatorOpen, bool()); MOCK_METHOD0(ActivatePanel, void()); MOCK_CONST_METHOD0(HasGrab, bool()); + MOCK_METHOD0(ShowPrimaryView, void()); }; struct ShieldFactoryMock : ShieldFactoryInterface { - nux::ObjectPtr<AbstractShield> CreateShield(session::Manager::Ptr const&, - indicator::Indicators::Ptr const&, - Accelerators::Ptr const&, - nux::ObjectPtr<UserPromptView> const&, - int, bool) override + nux::ObjectPtr<BaseShield> CreateShield(session::Manager::Ptr const&, + indicator::Indicators::Ptr const&, + Accelerators::Ptr const&, + nux::ObjectPtr<AbstractUserPromptView> const&, + int, bool) override { - return nux::ObjectPtr<AbstractShield>(new MockShield()); + return nux::ObjectPtr<BaseShield>(new MockShield()); } }; diff --git a/tests/test_mock_filemanager.h b/tests/test_mock_filemanager.h index 231c0074e..1e541ebfd 100644 --- a/tests/test_mock_filemanager.h +++ b/tests/test_mock_filemanager.h @@ -32,15 +32,18 @@ struct MockFileManager : FileManager typedef testing::NiceMock<MockFileManager> Nice; MOCK_METHOD2(Open, void(std::string const& uri, uint64_t time)); - MOCK_METHOD2(OpenActiveChild, void(std::string const& uri, uint64_t time)); MOCK_METHOD1(OpenTrash, void(uint64_t time)); MOCK_METHOD1(TrashFile, bool(std::string const& uri)); MOCK_METHOD1(EmptyTrash, void(uint64_t time)); MOCK_METHOD3(CopyFiles, void(std::set<std::string> const& files, std::string const& dest, uint64_t time)); - MOCK_CONST_METHOD0(OpenedLocations, std::vector<std::string>()); - MOCK_CONST_METHOD1(IsPrefixOpened, bool(std::string const& uri)); - MOCK_CONST_METHOD0(IsTrashOpened, bool()); - MOCK_CONST_METHOD0(IsDeviceOpened, bool()); + MOCK_CONST_METHOD1(WindowsForLocation, WindowList(std::string const&)); + MOCK_CONST_METHOD1(LocationForWindow, std::string(ApplicationWindowPtr const&)); + + MockFileManager() + { + using namespace testing; + ON_CALL(*this, WindowsForLocation(_)).WillByDefault(Return(WindowList())); + } }; } diff --git a/tests/test_mock_session_manager.h b/tests/test_mock_session_manager.h index 7d672b0e3..7e5ebeb16 100644 --- a/tests/test_mock_session_manager.h +++ b/tests/test_mock_session_manager.h @@ -28,10 +28,12 @@ namespace session struct MockManager : Manager { typedef std::shared_ptr<MockManager> Ptr; + typedef std::function<void(std::string const&)> ReplyCallback; MOCK_CONST_METHOD0(RealName, std::string()); MOCK_CONST_METHOD0(UserName, std::string()); MOCK_CONST_METHOD0(HostName, std::string()); + MOCK_CONST_METHOD1(UserIconFile, void(ReplyCallback const&)); MOCK_METHOD0(ScreenSaverActivate, void()); MOCK_METHOD0(ScreenSaverDeactivate, void()); @@ -43,6 +45,7 @@ struct MockManager : Manager MOCK_METHOD0(Suspend, void()); MOCK_METHOD0(Hibernate, void()); MOCK_METHOD0(CancelAction, void()); + MOCK_METHOD0(SwitchToGreeter, void()); MOCK_CONST_METHOD0(CanLock, bool()); MOCK_CONST_METHOD0(CanShutdown, bool()); diff --git a/tests/test_previews_application.cpp b/tests/test_previews_application.cpp index 8a268869e..d5a893d84 100644 --- a/tests/test_previews_application.cpp +++ b/tests/test_previews_application.cpp @@ -72,7 +72,7 @@ public: GHashTable* action_hints1(g_hash_table_new(g_direct_hash, g_direct_equal)); g_hash_table_insert (action_hints1, g_strdup ("extra-text"), g_variant_new_string("£30.99")); - unity_protocol_application_preview_set_app_icon(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), g_icon_new_for_string("/home/nick/SkypeIcon.png", NULL)); + unity_protocol_application_preview_set_app_icon(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), g_icon_new_for_string(TESTDATADIR "/bfb.png", NULL)); unity_protocol_application_preview_set_license(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), "License & special char"); unity_protocol_application_preview_set_copyright(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), "Copywrite & special char"); unity_protocol_application_preview_set_last_update(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), "11th Apr 2012"); diff --git a/tests/test_software_center_launcher_icon.cpp b/tests/test_software_center_launcher_icon.cpp index abf65d09f..6ee4d8d12 100644 --- a/tests/test_software_center_launcher_icon.cpp +++ b/tests/test_software_center_launcher_icon.cpp @@ -62,16 +62,17 @@ struct TestSoftwareCenterLauncherIcon : testmocks::TestUnityAppBase MockSoftwareCenterLauncherIcon(ApplicationPtr const& app, std::string const& aptdaemon_trans_id, std::string const& icon_path) - : SoftwareCenterLauncherIcon(app, aptdaemon_trans_id, icon_path) + : WindowedLauncherIcon(IconType::APPLICATION) + , SoftwareCenterLauncherIcon(app, aptdaemon_trans_id, icon_path) {} void LauncherIconUnstick() { LauncherIcon::UnStick(); } using SoftwareCenterLauncherIcon::GetActualDesktopFileAfterInstall; - using SoftwareCenterLauncherIcon::GetRemoteUri; using SoftwareCenterLauncherIcon::OnFinished; using SoftwareCenterLauncherIcon::OnPropertyChanged; using SoftwareCenterLauncherIcon::drag_window_; + using LauncherIcon::GetRemoteUri; }; nux::ObjectPtr<Launcher> CreateLauncher() diff --git a/tests/test_switcher_controller.h b/tests/test_switcher_controller.h index bc0118df4..5e35b2e59 100644 --- a/tests/test_switcher_controller.h +++ b/tests/test_switcher_controller.h @@ -27,10 +27,11 @@ #include "test_utils.h" #include "DesktopLauncherIcon.h" -#include "SimpleLauncherIcon.h" +#include "WindowedLauncherIcon.h" #include "SwitcherController.h" #include "SwitcherView.h" #include "TimeUtil.h" +#include "mock-application.h" #include "mock-base-window.h" #include "test_standalone_wm.h" @@ -48,35 +49,24 @@ const unsigned TICK_DURATION = 10 * 1000; /** * A fake ApplicationWindow for verifying selection of the switcher. */ -class FakeApplicationWindow : public unity::ApplicationWindow +struct FakeApplicationWindow : public ::testmocks::MockApplicationWindow::Nice { -public: + typedef NiceMock<FakeApplicationWindow> Nice; FakeApplicationWindow(Window xid, uint64_t active_number = 0); ~FakeApplicationWindow(); - - virtual WindowType type() const; - - virtual Window window_id() const; - virtual int monitor() const; - virtual unity::ApplicationPtr application() const; - virtual bool Focus() const; - virtual void Quit() const; - -private: - Window xid_; }; /** * A fake LauncherIcon for verifying selection operations of the switcher. */ -struct FakeLauncherIcon : unity::launcher::SimpleLauncherIcon +struct FakeLauncherIcon : unity::launcher::WindowedLauncherIcon { FakeLauncherIcon(std::string const& app_name, bool allow_detail_view, uint64_t priority); - unity::WindowList Windows() override; bool AllowDetailViewInSwitcher() const override; bool ShowInSwitcher(bool) override; uint64_t SwitcherPriority() override; + WindowList GetManagedWindows() const override; bool allow_detail_view_; uint64_t priority_; diff --git a/tests/test_switcher_controller_class.cpp b/tests/test_switcher_controller_class.cpp index 749359f54..807a239bc 100644 --- a/tests/test_switcher_controller_class.cpp +++ b/tests/test_switcher_controller_class.cpp @@ -26,14 +26,13 @@ using namespace unity::switcher; using namespace std::chrono; FakeApplicationWindow::FakeApplicationWindow(Window xid, uint64_t active_number) - : xid_(xid) + : MockApplicationWindow::Nice(xid) { - auto standalone_window = std::make_shared<StandaloneWindow>(xid_); + SetMonitor(-1); + auto standalone_window = std::make_shared<StandaloneWindow>(window_id()); standalone_window->active_number = active_number; testwrapper::StandaloneWM::Get()->AddStandaloneWindow(standalone_window); - - title.SetGetterFunction([this] { return "FakeApplicationWindow"; }); - icon.SetGetterFunction([this] { return ""; }); + ON_CALL(*this, Quit()).WillByDefault(Invoke([this] { WindowManager::Default().Close(window_id()); })); } FakeApplicationWindow::~FakeApplicationWindow() @@ -41,25 +40,17 @@ FakeApplicationWindow::~FakeApplicationWindow() testwrapper::StandaloneWM::Get()->Close(xid_); } -WindowType FakeApplicationWindow::type() const { return WindowType::MOCK; } - -Window FakeApplicationWindow::window_id() const { return xid_; } -int FakeApplicationWindow::monitor() const { return -1; } -ApplicationPtr FakeApplicationWindow::application() const { return ApplicationPtr(); } -bool FakeApplicationWindow::Focus() const { return false; } -void FakeApplicationWindow::Quit() const { WindowManager::Default().Close(xid_); } - FakeLauncherIcon::FakeLauncherIcon(std::string const& app_name, bool allow_detail_view, uint64_t priority) - : launcher::SimpleLauncherIcon(IconType::APPLICATION) + : launcher::WindowedLauncherIcon(IconType::APPLICATION) , allow_detail_view_(allow_detail_view) , priority_(priority) - , window_list{ std::make_shared<FakeApplicationWindow>(priority_ | 0x0001, SwitcherPriority()), - std::make_shared<FakeApplicationWindow>(priority_ | 0x0002, priority_) } + , window_list{ std::make_shared<FakeApplicationWindow::Nice>(priority_ | 0x0001, SwitcherPriority()), + std::make_shared<FakeApplicationWindow::Nice>(priority_ | 0x0002, priority_) } { tooltip_text = app_name; } -WindowList FakeLauncherIcon::Windows() +WindowList FakeLauncherIcon::GetManagedWindows() const { return window_list; } @@ -85,7 +76,7 @@ uint64_t FakeLauncherIcon::SwitcherPriority() //class TestSwitcherController : public testing::Test TestSwitcherController::TestSwitcherController() : animation_controller_(tick_source_) - , mock_window_(new NiceMock<testmocks::MockBaseWindow>()) + , mock_window_(new NiceMock<unity::testmocks::MockBaseWindow>()) , controller_(std::make_shared<Controller>([this] { return mock_window_; })) { controller_->timeout_length = 0; diff --git a/tests/test_trash_launcher_icon.cpp b/tests/test_trash_launcher_icon.cpp index 839c70ff4..d8a5b6162 100644 --- a/tests/test_trash_launcher_icon.cpp +++ b/tests/test_trash_launcher_icon.cpp @@ -27,9 +27,11 @@ using namespace unity; using namespace unity::launcher; using namespace testing; +using namespace testmocks; namespace { +const std::string TRASH_URI = "trash:"; struct TestTrashLauncherIcon : testmocks::TestUnityAppBase { @@ -42,6 +44,12 @@ struct TestTrashLauncherIcon : testmocks::TestUnityAppBase TrashLauncherIcon icon; }; +TEST_F(TestTrashLauncherIcon, InitState) +{ + EXPECT_FALSE(icon.GetQuirk(AbstractLauncherIcon::Quirk::RUNNING)); + EXPECT_FALSE(icon.GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE)); +} + TEST_F(TestTrashLauncherIcon, Position) { EXPECT_EQ(icon.position(), AbstractLauncherIcon::Position::END); @@ -74,15 +82,77 @@ TEST_F(TestTrashLauncherIcon, QuicklistEmptyTrash) TEST_F(TestTrashLauncherIcon, RunningState) { - EXPECT_CALL(*fm_, IsTrashOpened()).WillRepeatedly(Return(true)); + auto win1 = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + auto win2 = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + + ON_CALL(*fm_, WindowsForLocation(TRASH_URI)).WillByDefault(Return(WindowList({win1, win2}))); fm_->locations_changed.emit(); EXPECT_TRUE(icon.GetQuirk(AbstractLauncherIcon::Quirk::RUNNING)); - EXPECT_CALL(*fm_, IsTrashOpened()).WillRepeatedly(Return(false)); + ON_CALL(*fm_, WindowsForLocation(TRASH_URI)).WillByDefault(Return(WindowList())); fm_->locations_changed.emit(); EXPECT_FALSE(icon.GetQuirk(AbstractLauncherIcon::Quirk::RUNNING)); } +TEST_F(TestTrashLauncherIcon, ActiveState) +{ + auto win1 = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + auto win2 = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + + ON_CALL(*fm_, WindowsForLocation(TRASH_URI)).WillByDefault(Return(WindowList({win1, win2}))); + fm_->locations_changed.emit(); + ASSERT_FALSE(icon.GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE)); + + win2->LocalFocus(); + EXPECT_TRUE(icon.GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE)); + + ON_CALL(*fm_, WindowsForLocation(TRASH_URI)).WillByDefault(Return(WindowList())); + fm_->locations_changed.emit(); + EXPECT_FALSE(icon.GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE)); +} + +TEST_F(TestTrashLauncherIcon, WindowsCount) +{ + WindowList windows((g_random_int() % 10) + 5); + for (unsigned i = 0; i < windows.capacity(); ++i) + windows[i] = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + + ON_CALL(*fm_, WindowsForLocation(TRASH_URI)).WillByDefault(Return(windows)); + fm_->locations_changed.emit(); + EXPECT_EQ(icon.Windows().size(), windows.size()); +} + +TEST_F(TestTrashLauncherIcon, WindowsPerMonitor) +{ + WindowList windows((g_random_int() % 10) + 5); + for (unsigned i = 0; i < windows.capacity(); ++i) + { + auto win = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + win->monitor_ = i % 2; + windows[i] = win; + } + + ON_CALL(*fm_, WindowsForLocation(TRASH_URI)).WillByDefault(Return(windows)); + fm_->locations_changed.emit(); + + EXPECT_EQ(icon.WindowsVisibleOnMonitor(0), (windows.size() / 2) + (windows.size() % 2)); + EXPECT_EQ(icon.WindowsVisibleOnMonitor(1), windows.size() / 2); +} + +TEST_F(TestTrashLauncherIcon, WindowsOnMonitorChanges) +{ + auto win = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + ON_CALL(*fm_, WindowsForLocation(TRASH_URI)).WillByDefault(Return(WindowList({win}))); + fm_->locations_changed.emit(); + + EXPECT_EQ(icon.WindowsVisibleOnMonitor(0), 1); + EXPECT_EQ(icon.WindowsVisibleOnMonitor(1), 0); + + win->SetMonitor(1); + EXPECT_EQ(icon.WindowsVisibleOnMonitor(0), 0); + EXPECT_EQ(icon.WindowsVisibleOnMonitor(1), 1); +} + TEST_F(TestTrashLauncherIcon, FilemanagerSignalDisconnection) { auto file_manager = std::make_shared<NiceMock<MockFileManager>>(); diff --git a/tests/test_unity_settings.cpp b/tests/test_unity_settings.cpp index 0bf07858f..f64c9c594 100644 --- a/tests/test_unity_settings.cpp +++ b/tests/test_unity_settings.cpp @@ -53,12 +53,14 @@ struct TestUnitySettings : testing::Test , sig_receiver(unity_settings) { g_settings_set_enum(gsettings, "form-factor", static_cast<int>(unity::FormFactor::DESKTOP)); + g_settings_set_enum(gsettings, "desktop-type", static_cast<int>(unity::DesktopType::UBUNTU)); } ~TestUnitySettings() { sig_receiver.notify_callbacks(); g_settings_reset(gsettings, "form-factor"); + g_settings_reset(gsettings, "desktop-type"); } }; @@ -78,6 +80,14 @@ TEST_F(TestUnitySettings, GetFormFactor) EXPECT_EQ(unity_settings->form_factor(), unity::FormFactor::NETBOOK); } +TEST_F(TestUnitySettings, GetDesktopType) +{ + ASSERT_NE(unity_settings->desktop_type(), unity::DesktopType::UBUNTUKYLIN); + + g_settings_set_enum(gsettings, "desktop-type", static_cast<int>(unity::DesktopType::UBUNTUKYLIN)); + EXPECT_EQ(unity_settings->desktop_type(), unity::DesktopType::UBUNTUKYLIN); +} + TEST_F(TestUnitySettings, FormFactorChangedSignal_Extern) { EXPECT_CALL(sig_receiver, FormFactorChanged(unity::FormFactor::NETBOOK)); diff --git a/tests/test_volume_launcher_icon.cpp b/tests/test_volume_launcher_icon.cpp index 8d6bc48c2..41b794bae 100644 --- a/tests/test_volume_launcher_icon.cpp +++ b/tests/test_volume_launcher_icon.cpp @@ -27,8 +27,11 @@ using namespace testing; #include "test_utils.h" #include "test_mock_devices.h" #include "test_mock_filemanager.h" +#include "mock-application.h" + using namespace unity; using namespace unity::launcher; +using namespace testmocks; namespace { @@ -43,7 +46,7 @@ struct TestVolumeLauncherIcon : public Test { SetupVolumeDefaultBehavior(); SetupSettingsDefaultBehavior(); - icon_ = new NiceMock<VolumeLauncherIcon>(volume_, settings_, notifications_, file_manager_); + icon_ = new VolumeLauncherIcon(volume_, settings_, notifications_, file_manager_); } void SetupSettingsDefaultBehavior() @@ -94,7 +97,7 @@ struct TestVolumeLauncherIconDelayedConstruction : TestVolumeLauncherIcon void CreateIcon() { - icon_ = new NiceMock<VolumeLauncherIcon>(volume_, settings_, notifications_, file_manager_); + icon_ = new VolumeLauncherIcon(volume_, settings_, notifications_, file_manager_); } }; @@ -105,7 +108,7 @@ TEST_F(TestVolumeLauncherIcon, TestIconType) TEST_F(TestVolumeLauncherIconDelayedConstruction, TestRunningOnClosed) { - ON_CALL(*file_manager_, IsPrefixOpened(volume_->GetUri())).WillByDefault(Return(false)); + ON_CALL(*file_manager_, WindowsForLocation(_)).WillByDefault(Return(WindowList())); CreateIcon(); EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::RUNNING)); @@ -113,7 +116,8 @@ TEST_F(TestVolumeLauncherIconDelayedConstruction, TestRunningOnClosed) TEST_F(TestVolumeLauncherIconDelayedConstruction, TestRunningOnOpened) { - ON_CALL(*file_manager_, IsPrefixOpened(volume_->GetUri())).WillByDefault(Return(true)); + auto win = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList({win}))); CreateIcon(); EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::RUNNING)); @@ -128,16 +132,91 @@ TEST_F(TestVolumeLauncherIcon, FilemanagerSignalDisconnection) TEST_F(TestVolumeLauncherIcon, TestRunningStateOnLocationChangedClosed) { - ON_CALL(*file_manager_, IsPrefixOpened(volume_->GetUri())).WillByDefault(Return(false)); + ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList())); file_manager_->locations_changed.emit(); EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::RUNNING)); } TEST_F(TestVolumeLauncherIcon, TestRunningStateOnLocationChangedOpened) { - ON_CALL(*file_manager_, IsPrefixOpened(volume_->GetUri())).WillByDefault(Return(true)); + auto win1 = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + auto win2 = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList({win1, win2}))); + file_manager_->locations_changed.emit(); + EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::RUNNING)); +} + +TEST_F(TestVolumeLauncherIcon, RunningState) +{ + auto win1 = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + auto win2 = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + + ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList({win1, win2}))); file_manager_->locations_changed.emit(); EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::RUNNING)); + + ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList())); + file_manager_->locations_changed.emit(); + EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::RUNNING)); +} + +TEST_F(TestVolumeLauncherIcon, ActiveState) +{ + auto win1 = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + auto win2 = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + + ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList({win1, win2}))); + file_manager_->locations_changed.emit(); + ASSERT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE)); + + win2->LocalFocus(); + EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE)); + + ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList())); + file_manager_->locations_changed.emit(); + EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE)); +} + +TEST_F(TestVolumeLauncherIcon, WindowsCount) +{ + WindowList windows((g_random_int() % 10) + 5); + for (unsigned i = 0; i < windows.capacity(); ++i) + windows[i] = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + + ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(windows)); + file_manager_->locations_changed.emit(); + EXPECT_EQ(icon_->Windows().size(), windows.size()); +} + +TEST_F(TestVolumeLauncherIcon, WindowsPerMonitor) +{ + WindowList windows((g_random_int() % 10) + 5); + for (unsigned i = 0; i < windows.capacity(); ++i) + { + auto win = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + win->monitor_ = i % 2; + windows[i] = win; + } + + ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(windows)); + file_manager_->locations_changed.emit(); + + EXPECT_EQ(icon_->WindowsVisibleOnMonitor(0), (windows.size() / 2) + (windows.size() % 2)); + EXPECT_EQ(icon_->WindowsVisibleOnMonitor(1), windows.size() / 2); +} + +TEST_F(TestVolumeLauncherIcon, WindowsOnMonitorChanges) +{ + auto win = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList({win}))); + file_manager_->locations_changed.emit(); + + EXPECT_EQ(icon_->WindowsVisibleOnMonitor(0), 1); + EXPECT_EQ(icon_->WindowsVisibleOnMonitor(1), 0); + + win->SetMonitor(1); + EXPECT_EQ(icon_->WindowsVisibleOnMonitor(0), 0); + EXPECT_EQ(icon_->WindowsVisibleOnMonitor(1), 1); } TEST_F(TestVolumeLauncherIcon, TestPosition) @@ -240,6 +319,32 @@ TEST_F(TestVolumeLauncherIconDelayedConstruction, TestVisibilityAfterUnmount_Bla EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); } +TEST_F(TestVolumeLauncherIcon, TestVisibilityWithWindows) +{ + ON_CALL(*settings_, IsABlacklistedDevice(volume_->GetIdentifier())).WillByDefault(Return(false)); + settings_->changed.emit(); + ASSERT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); + + auto win = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList({win}))); + file_manager_->locations_changed.emit(); + + EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); +} + +TEST_F(TestVolumeLauncherIcon, TestVisibilityWithWindows_Blacklisted) +{ + ON_CALL(*settings_, IsABlacklistedDevice(volume_->GetIdentifier())).WillByDefault(Return(true)); + settings_->changed.emit(); + ASSERT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); + + auto win = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList({win}))); + file_manager_->locations_changed.emit(); + + EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); +} + TEST_F(TestVolumeLauncherIcon, TestUnlockFromLauncherMenuItem_VolumeWithoutIdentifier) { EXPECT_CALL(*volume_, GetIdentifier()) @@ -251,22 +356,22 @@ TEST_F(TestVolumeLauncherIcon, TestUnlockFromLauncherMenuItem_VolumeWithoutIdent TEST_F(TestVolumeLauncherIcon, TestUnlockFromLauncherMenuItem_Success) { + ON_CALL(*settings_, IsABlacklistedDevice(volume_->GetIdentifier())).WillByDefault(Return(false)); + settings_->changed.emit(); + ASSERT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); auto menuitem = GetMenuItemAtIndex(4); ASSERT_STREQ(dbusmenu_menuitem_property_get(menuitem, DBUSMENU_MENUITEM_PROP_LABEL), "Unlock from Launcher"); EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE)); EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_ENABLED)); - EXPECT_CALL(*settings_, TryToBlacklist(_)) - .Times(1); - - EXPECT_CALL(*settings_, IsABlacklistedDevice(_)) - .WillRepeatedly(Return(true)); - + EXPECT_CALL(*settings_, TryToBlacklist(volume_->GetIdentifier())).Times(1); dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0); + + EXPECT_CALL(*settings_, IsABlacklistedDevice(volume_->GetIdentifier())).WillRepeatedly(Return(true)); settings_->changed.emit(); // TryToBlacklist() works if DevicesSettings emits a changed signal. - ASSERT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); + EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); } TEST_F(TestVolumeLauncherIcon, TestUnlockFromLauncherMenuItem_Failure) @@ -277,12 +382,49 @@ TEST_F(TestVolumeLauncherIcon, TestUnlockFromLauncherMenuItem_Failure) EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE)); EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_ENABLED)); - EXPECT_CALL(*settings_, TryToBlacklist(_)) - .Times(1); + EXPECT_CALL(*settings_, TryToBlacklist(volume_->GetIdentifier())).Times(1); + dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0); + + EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); +} + +TEST_F(TestVolumeLauncherIcon, TestLockToLauncherMenuItem_Success) +{ + ON_CALL(*settings_, IsABlacklistedDevice(volume_->GetIdentifier())).WillByDefault(Return(true)); + settings_->changed.emit(); + ASSERT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); + + auto menuitem = GetMenuItemAtIndex(4); + ASSERT_STREQ(dbusmenu_menuitem_property_get(menuitem, DBUSMENU_MENUITEM_PROP_LABEL), "Lock to Launcher"); + EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE)); + EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_ENABLED)); + + EXPECT_CALL(*settings_, TryToUnblacklist(volume_->GetIdentifier())).Times(1); dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0); - ASSERT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); + EXPECT_CALL(*settings_, IsABlacklistedDevice(_)).WillRepeatedly(Return(false)); + settings_->changed.emit(); // TryToBlacklist() works if DevicesSettings emits a changed signal. + + EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); +} + +TEST_F(TestVolumeLauncherIcon, TestLockToLauncherMenuItem_Failure) +{ + ON_CALL(*settings_, IsABlacklistedDevice(volume_->GetIdentifier())).WillByDefault(Return(true)); + settings_->changed.emit(); + ASSERT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); + + auto menuitem = GetMenuItemAtIndex(4); + + ASSERT_STREQ(dbusmenu_menuitem_property_get(menuitem, DBUSMENU_MENUITEM_PROP_LABEL), "Lock to Launcher"); + EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE)); + EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_ENABLED)); + + EXPECT_CALL(*settings_, TryToUnblacklist(volume_->GetIdentifier())).Times(1); + dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0); + + EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); } TEST_F(TestVolumeLauncherIcon, TestOpenMenuItem) @@ -298,7 +440,7 @@ TEST_F(TestVolumeLauncherIcon, TestOpenMenuItem) InSequence seq; EXPECT_CALL(*volume_, Mount()); - EXPECT_CALL(*file_manager_, OpenActiveChild(volume_->GetUri(), time)); + EXPECT_CALL(*file_manager_, Open(volume_->GetUri(), time)); dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, time); } @@ -318,7 +460,7 @@ TEST_F(TestVolumeLauncherIcon, TestNameMenuItem) InSequence seq; EXPECT_CALL(*volume_, Mount()); - EXPECT_CALL(*file_manager_, OpenActiveChild(volume_->GetUri(), time)); + EXPECT_CALL(*file_manager_, Open(volume_->GetUri(), time)); dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, time); } @@ -438,7 +580,7 @@ TEST_F(TestVolumeLauncherIcon, OnRemoved) EXPECT_CALL(*settings_, TryToBlacklist(_)) .Times(0); EXPECT_CALL(*settings_, TryToUnblacklist(_)) - .Times(0); + .Times(1); volume_->removed.emit(); } @@ -451,7 +593,7 @@ TEST_F(TestVolumeLauncherIcon, OnRemoved_RemovabledVolume) EXPECT_CALL(*settings_, TryToBlacklist(_)) .Times(0); EXPECT_CALL(*settings_, TryToUnblacklist(_)) - .Times(0); + .Times(1); volume_->removed.emit(); } @@ -516,7 +658,7 @@ TEST_F(TestVolumeLauncherIcon, ActivateMounted) uint64_t time = g_random_int(); InSequence seq; EXPECT_CALL(*volume_, Mount()).Times(0); - EXPECT_CALL(*file_manager_, OpenActiveChild(volume_->GetUri(), time)); + EXPECT_CALL(*file_manager_, Open(volume_->GetUri(), time)); icon_->Activate(ActionArg(ActionArg::Source::LAUNCHER, 0, time)); } @@ -526,7 +668,7 @@ TEST_F(TestVolumeLauncherIcon, ActivateUnmounted) ON_CALL(*volume_, IsMounted()).WillByDefault(Return(false)); InSequence seq; EXPECT_CALL(*volume_, Mount()); - EXPECT_CALL(*file_manager_, OpenActiveChild(volume_->GetUri(), time)); + EXPECT_CALL(*file_manager_, Open(volume_->GetUri(), time)); icon_->Activate(ActionArg(ActionArg::Source::LAUNCHER, 0, time)); } diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 24dfc2280..e92776dd0 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,9 +1,8 @@ # # Some unity tools # -install(FILES makebootchart.py PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/unity/) +install(FILES makebootchart.py PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE DESTINATION ${CMAKE_INSTALL_LIBDIR}/unity) configure_file (${CMAKE_CURRENT_SOURCE_DIR}/unity.cmake ${CMAKE_BINARY_DIR}/bin/unity) install(FILES ${CMAKE_BINARY_DIR}/bin/unity PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ -GROUP_EXECUTE WORLD_READ WORLD_EXECUTE DESTINATION bin) - +GROUP_EXECUTE WORLD_READ WORLD_EXECUTE DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/unity-shared/ApplicationManager.h b/unity-shared/ApplicationManager.h index c0f681a5e..8a5e6270d 100644 --- a/unity-shared/ApplicationManager.h +++ b/unity-shared/ApplicationManager.h @@ -109,6 +109,8 @@ public: nux::ROProperty<bool> active; nux::ROProperty<bool> urgent; nux::ROProperty<bool> maximized; + + sigc::signal<void> closed; }; @@ -219,6 +221,7 @@ public: virtual WindowList GetWindowsForMonitor(int monitor = -1) const = 0; virtual ApplicationPtr GetApplicationForWindow(Window xid) const = 0; virtual ApplicationWindowPtr GetWindowForId(Window xid) const = 0; + virtual void FocusWindowGroup(WindowList const&, bool show_on_visible, int monitor) const = 0; sigc::signal<void, ApplicationPtr const&> application_started; sigc::signal<void, ApplicationPtr const&> application_stopped; diff --git a/unity-shared/BamfApplicationManager.cpp b/unity-shared/BamfApplicationManager.cpp index 9a76d2a08..8225ccc05 100644 --- a/unity-shared/BamfApplicationManager.cpp +++ b/unity-shared/BamfApplicationManager.cpp @@ -147,6 +147,7 @@ WindowBase::WindowBase(ApplicationManager const& manager, }); signals_.Add<void, BamfView*>(bamf_view_, "closed", [this] (BamfView* view) { + this->closed.emit(); pool::wins_.erase(view); }); } @@ -473,7 +474,7 @@ ApplicationWindowPtr Application::GetFocusableWindow() const return pool::EnsureWindow(manager_, bamf_application_get_focusable_child(bamf_app_)); } -void Application::Focus(bool show_only_visible, int monitor) const +void Manager::FocusWindowGroup(WindowList const& wins, bool show_only_visible, int monitor) const { WindowManager& wm = WindowManager::Default(); std::vector<Window> urgent_windows; @@ -481,7 +482,7 @@ void Application::Focus(bool show_only_visible, int monitor) const std::vector<Window> non_visible_windows; bool any_visible = false; - for (auto& window : GetWindows()) + for (auto& window : wins) { Window window_id = window->window_id(); if (window->urgent()) @@ -526,12 +527,15 @@ void Application::Focus(bool show_only_visible, int monitor) const } } +void Application::Focus(bool show_only_visible, int monitor) const +{ + manager_.FocusWindowGroup(GetWindows(), show_only_visible, monitor); +} + void Application::Quit() const { for (auto& window : GetWindows()) - { window->Quit(); - } } bool Application::CreateLocalDesktopFile() const diff --git a/unity-shared/BamfApplicationManager.h b/unity-shared/BamfApplicationManager.h index 74503a9aa..30859025a 100644 --- a/unity-shared/BamfApplicationManager.h +++ b/unity-shared/BamfApplicationManager.h @@ -64,7 +64,7 @@ public: bool operator==(unity::ApplicationWindow const& other) const override { - return static_cast<WindowBase const*>(this)->bamf_view_ == static_cast<WindowBase const&>(other).bamf_view_; + return static_cast<WindowBase const*>(this)->bamf_view_ == static_cast<WindowBase const&>(other).bamf_view_; } bool operator!=(unity::ApplicationWindow const& other) const override { return !(operator==(other)); } }; @@ -175,6 +175,8 @@ public: ApplicationPtr EnsureApplication(BamfView*) const; ApplicationWindowPtr EnsureWindow(BamfView*) const; + void FocusWindowGroup(WindowList const&, bool show_on_visible, int monitor) const; + private: void OnViewOpened(BamfMatcher* matcher, BamfView* view); void OnViewClosed(BamfMatcher* matcher, BamfView* view); diff --git a/unity-shared/DashStyle.cpp b/unity-shared/DashStyle.cpp index 6f967ff20..d9e7a825c 100755 --- a/unity-shared/DashStyle.cpp +++ b/unity-shared/DashStyle.cpp @@ -46,7 +46,7 @@ #include "UnitySettings.h" #include "config.h" -#define DASH_WIDGETS_FILE DATADIR"/unity/themes/dash-widgets.json" +#define DASH_WIDGETS_FILE UNITYDATADIR"/themes/dash-widgets.json" namespace unity { diff --git a/unity-shared/FileManager.h b/unity-shared/FileManager.h index 55647d2c0..15dc1d966 100644 --- a/unity-shared/FileManager.h +++ b/unity-shared/FileManager.h @@ -27,6 +27,8 @@ #include <vector> #include <set> #include <sigc++/sigc++.h> +#include "ApplicationManager.h" + namespace unity { @@ -40,15 +42,12 @@ public: virtual ~FileManager() = default; virtual void Open(std::string const& uri, uint64_t timestamp = 0) = 0; - virtual void OpenActiveChild(std::string const& uri, uint64_t timestamp = 0) = 0; virtual void OpenTrash(uint64_t timestamp) = 0; - virtual std::vector<std::string> OpenedLocations() const = 0; - virtual bool IsPrefixOpened(std::string const& uri) const = 0; - virtual bool IsTrashOpened() const = 0; - virtual bool IsDeviceOpened() const = 0; virtual void CopyFiles(std::set<std::string> const& uris, std::string const& dest, uint64_t timestamp = 0) = 0; virtual bool TrashFile(std::string const& uri) = 0; virtual void EmptyTrash(uint64_t timestamp = 0) = 0; + virtual WindowList WindowsForLocation(std::string const& location) const = 0; + virtual std::string LocationForWindow(ApplicationWindowPtr const&) const = 0; sigc::signal<void> locations_changed; @@ -57,6 +56,6 @@ private: FileManager& operator=(FileManager const&) = delete; }; -} +} // namespace unity #endif diff --git a/unity-shared/GnomeFileManager.cpp b/unity-shared/GnomeFileManager.cpp index 2f142f836..e273ffd70 100644 --- a/unity-shared/GnomeFileManager.cpp +++ b/unity-shared/GnomeFileManager.cpp @@ -21,8 +21,9 @@ #include "GnomeFileManager.h" #include <NuxCore/Logger.h> #include <UnityCore/DesktopUtilities.h> -#include <UnityCore/GLibWrapper.h> +#include <UnityCore/GLibSource.h> #include <UnityCore/GLibDBusProxy.h> +#include <UnityCore/GLibWrapper.h> #include <gdk/gdk.h> #include <gio/gio.h> @@ -33,10 +34,8 @@ namespace { DECLARE_LOGGER(logger, "unity.filemanager.gnome"); -const std::string TRASH_URI = "trash:"; +const std::string TRASH_URI = "trash:///"; const std::string FILE_SCHEMA = "file://"; -const std::string TRASH_PATH = FILE_SCHEMA + DesktopUtilities::GetUserDataDirectory() + "/Trash/files"; -const std::string DEVICES_PREFIX = FILE_SCHEMA + "/media/" + std::string(g_get_user_name()); const std::string NAUTILUS_NAME = "org.gnome.Nautilus"; const std::string NAUTILUS_PATH = "/org/gnome/Nautilus"; @@ -48,64 +47,83 @@ struct GnomeFileManager::Impl : parent_(parent) , filemanager_proxy_("org.freedesktop.FileManager1", "/org/freedesktop/FileManager1", "org.freedesktop.FileManager1") { - auto callback = sigc::mem_fun(this, &Impl::OnOpenLocationsUpdated); - filemanager_proxy_.GetProperty("OpenLocations", callback); - filemanager_proxy_.ConnectProperty("OpenLocations", callback); + auto callback = sigc::mem_fun(this, &Impl::OnOpenLocationsXidsUpdated); + filemanager_proxy_.GetProperty("XUbuntuOpenLocationsXids", callback); + filemanager_proxy_.ConnectProperty("XUbuntuOpenLocationsXids", callback); } - void OnOpenLocationsUpdated(GVariant* value) + glib::DBusProxy::Ptr NautilusOperationsProxy() const { - if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING_ARRAY)) + return std::make_shared<glib::DBusProxy>(NAUTILUS_NAME, NAUTILUS_PATH, + "org.gnome.Nautilus.FileOperations"); + } + + void OnOpenLocationsXidsUpdated(GVariant* value) + { + opened_location_for_xid_.clear(); + + if (!value) { - LOG_ERROR(logger) << "Locations value type is not matching the expected one!"; + LOG_WARN(logger) << "Locations have been invalidated, maybe there's no filemanager around..."; + parent_->locations_changed.emit(); return; } - opened_locations_.clear(); + if (!g_variant_is_of_type(value, G_VARIANT_TYPE("a{uas}"))) + { + LOG_ERROR(logger) << "Locations value type is not matching the expected one!"; + parent_->locations_changed.emit(); + return; + } GVariantIter iter; - const char *str; + GVariantIter *str_iter; + const char *loc; + guint32 xid; g_variant_iter_init(&iter, value); - while (g_variant_iter_loop(&iter, "s", &str)) + while (g_variant_iter_loop(&iter, "{uas}", &xid, &str_iter)) { - LOG_DEBUG(logger) << "Opened location " << str; - opened_locations_.push_back(str); + while (g_variant_iter_loop(str_iter, "s", &loc)) + { + /* We only care about the first mentioned location as per our "standard" + * it's the active one */ + LOG_DEBUG(logger) << xid << ": Opened location " << loc; + opened_location_for_xid_[xid] = loc; + break; + } } - parent_->locations_changed.emit(); - } - - std::string GetOpenedPrefix(std::string const& uri, bool allow_equal = true) - { - glib::Object<GFile> uri_file(g_file_new_for_uri(uri.c_str())); - - for (auto const& loc : opened_locations_) + // We must ensure that we emit the locations_changed signal only when all + // the parent windows have been registered on the app-manager + auto app_manager_not_synced = [this] { - bool equal = false; + auto& app_manager = ApplicationManager::Default(); + bool synced = true; - glib::Object<GFile> loc_file(g_file_new_for_uri(loc.c_str())); + for (auto const& pair : opened_location_for_xid_) + { + synced = (app_manager.GetWindowForId(pair.first) != nullptr); - if (allow_equal && g_file_equal(loc_file, uri_file)) - equal = true; + if (!synced) + break; + } - if (equal || g_file_has_prefix(loc_file, uri_file)) - return loc; - } + if (synced) + parent_->locations_changed.emit(); - return ""; - } + return !synced; + }; - glib::DBusProxy::Ptr NautilusOperationsProxy() const - { - return std::make_shared<glib::DBusProxy>(NAUTILUS_NAME, NAUTILUS_PATH, - "org.gnome.Nautilus.FileOperations"); + if (app_manager_not_synced()) + idle_.reset(new glib::Idle(app_manager_not_synced)); } GnomeFileManager* parent_; glib::DBusProxy filemanager_proxy_; - std::vector<std::string> opened_locations_; + glib::Source::UniquePtr idle_; + std::map<Window, std::string> opened_location_for_xid_; }; @@ -146,23 +164,9 @@ void GnomeFileManager::Open(std::string const& uri, uint64_t timestamp) } } -void GnomeFileManager::OpenActiveChild(std::string const& uri, uint64_t timestamp) -{ - auto const& opened = impl_->GetOpenedPrefix(uri); - - Open(opened.empty() ? uri : opened, timestamp); -} - void GnomeFileManager::OpenTrash(uint64_t timestamp) { - if (IsPrefixOpened(TRASH_PATH)) - { - OpenActiveChild(TRASH_PATH, timestamp); - } - else - { - OpenActiveChild(TRASH_URI, timestamp); - } + Open(TRASH_URI, timestamp); } void GnomeFileManager::Activate(uint64_t timestamp) @@ -252,25 +256,48 @@ void GnomeFileManager::CopyFiles(std::set<std::string> const& uris, std::string } } -std::vector<std::string> GnomeFileManager::OpenedLocations() const +WindowList GnomeFileManager::WindowsForLocation(std::string const& location) const { - return impl_->opened_locations_; -} + std::vector<ApplicationWindowPtr> windows; + auto& app_manager = ApplicationManager::Default(); -bool GnomeFileManager::IsPrefixOpened(std::string const& uri) const -{ - return !impl_->GetOpenedPrefix(uri).empty(); -} + glib::Object<GFile> location_file(g_file_new_for_uri(location.c_str())); -bool GnomeFileManager::IsTrashOpened() const -{ - return (IsPrefixOpened(TRASH_URI) || IsPrefixOpened(TRASH_PATH)); + for (auto const& pair : impl_->opened_location_for_xid_) + { + auto const& loc = pair.second; + bool matches = (loc == location); + + if (!matches) + { + glib::Object<GFile> loc_file(g_file_new_for_uri(loc.c_str())); + glib::String relative(g_file_get_relative_path(location_file, loc_file)); + matches = static_cast<bool>(relative); + } + + if (matches) + { + auto const& win = app_manager.GetWindowForId(pair.first); + + if (win && std::find(windows.rbegin(), windows.rend(), win) == windows.rend()) + windows.push_back(win); + } + } + + return windows; } -bool GnomeFileManager::IsDeviceOpened() const +std::string GnomeFileManager::LocationForWindow(ApplicationWindowPtr const& win) const { - return !impl_->GetOpenedPrefix(DEVICES_PREFIX, false).empty(); -} + if (win) + { + auto it = impl_->opened_location_for_xid_.find(win->window_id()); + if (it != end(impl_->opened_location_for_xid_)) + return it->second; + } + return std::string(); } + +} // namespace unity diff --git a/unity-shared/GnomeFileManager.h b/unity-shared/GnomeFileManager.h index 5b9ac1203..b017ce0ea 100644 --- a/unity-shared/GnomeFileManager.h +++ b/unity-shared/GnomeFileManager.h @@ -33,17 +33,14 @@ public: ~GnomeFileManager(); void Open(std::string const& uri, uint64_t timestamp); - void OpenActiveChild(std::string const& uri, uint64_t timestamp); void OpenTrash(uint64_t timestamp); void CopyFiles(std::set<std::string> const& uris, std::string const& dest, uint64_t timestamp); bool TrashFile(std::string const& uri); void EmptyTrash(uint64_t timestamp); - std::vector<std::string> OpenedLocations() const; - bool IsPrefixOpened(std::string const& uri) const; - bool IsTrashOpened() const; - bool IsDeviceOpened() const; + WindowList WindowsForLocation(std::string const& location) const; + std::string LocationForWindow(ApplicationWindowPtr const&) const; private: GnomeFileManager(); diff --git a/unity-shared/TextInput.cpp b/unity-shared/TextInput.cpp index ee111864b..2eed30cb5 100644 --- a/unity-shared/TextInput.cpp +++ b/unity-shared/TextInput.cpp @@ -54,6 +54,7 @@ const RawPixel TOOLTIP_Y_OFFSET = 3_em; const RawPixel TOOLTIP_OFFSET = 10_em; const RawPixel DEFAULT_ICON_SIZE = 22_em; +std::string ACTIVATOR_ICON = "arrow_right.png"; std::string WARNING_ICON = "dialog-warning-symbolic"; // Fonts const std::string HINT_LABEL_DEFAULT_FONT_NAME = "Ubuntu"; @@ -88,9 +89,15 @@ NUX_IMPLEMENT_OBJECT_TYPE(TextInput); TextInput::TextInput(NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) + , activator_icon(ACTIVATOR_ICON) + , activator_icon_size(DEFAULT_ICON_SIZE) + , background_color(nux::Color(0.0f, 0.0f, 0.0f, 0.35f)) + , border_color(nux::Color(1.0f, 1.0f, 1.0f, 0.7f)) + , border_radius(BORDER_RADIUS) , input_hint("") , hint_font_name(HINT_LABEL_DEFAULT_FONT_NAME) , hint_font_size(HINT_LABEL_FONT_SIZE) + , hint_color(nux::Color(1.0f, 1.0f, 1.0f, 0.5f)) , show_activator(false) , show_lock_warnings(false) , scale(1.0) @@ -109,7 +116,9 @@ TextInput::TextInput(NUX_FILE_LINE_DECL) hint_layout_->SetLeftAndRightPadding(HINT_PADDING.CP(scale), HINT_PADDING.CP(scale)); hint_ = new StaticCairoText(""); - hint_->SetTextColor(nux::Color(1.0f, 1.0f, 1.0f, 0.5f)); + hint_->SetTextColor(hint_color); + hint_color.changed.connect(sigc::hide(sigc::mem_fun(this, &TextInput::UpdateHintColor))); + hint_->SetScale(scale); hint_layout_->AddView(hint_, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL); hint_font_name.changed.connect(sigc::hide(sigc::mem_fun(this, &TextInput::UpdateHintFont))); @@ -146,10 +155,18 @@ TextInput::TextInput(NUX_FILE_LINE_DECL) Settings::Instance().font_scaling.changed.connect(sigc::hide(sigc::mem_fun(this, &TextInput::UpdateSize))); // Activator - activator_ = new IconTexture(LoadActivatorIcon(DEFAULT_ICON_SIZE.CP(scale))); + activator_ = new IconTexture(LoadActivatorIcon(activator_icon(), activator_icon_size().CP(scale))); activator_->SetVisible(show_activator()); layout_->AddView(activator_, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL); + activator_icon.changed.connect([this] (std::string icon) { + activator_->SetTexture(LoadActivatorIcon(icon, activator_icon_size().CP(scale))); + }); + + activator_icon_size.changed.connect([this] (RawPixel icon_size) { + activator_->SetTexture(LoadActivatorIcon(activator_icon(), icon_size.CP(scale))); + }); + show_activator.changed.connect([this] (bool value) { activator_->SetVisible(value); }); @@ -185,6 +202,11 @@ TextInput::TextInput(NUX_FILE_LINE_DECL) warning_->mouse_leave.connect([this] (int x, int y, int button, int key_flags) { tooltip_timeout_ ? tooltip_timeout_.reset() : QueueDraw(); }); + + //background + background_color.changed.connect([this] (nux::Color color) { UpdateBackground(true); }); + border_color.changed.connect([this] (nux::Color color) { UpdateBackground(true); }); + border_radius.changed.connect([this] (int radius) { UpdateBackground(true); }); } void TextInput::UpdateSize() @@ -208,7 +230,7 @@ void TextInput::UpdateScale(double scale) hint_->SetMaximumHeight(pango_entry_->GetMinimumHeight()); spinner_->scale = scale; - activator_->SetTexture(LoadActivatorIcon(DEFAULT_ICON_SIZE.CP(scale))); + activator_->SetTexture(LoadActivatorIcon(activator_icon(), activator_icon_size().CP(scale))); warning_->SetTexture(LoadWarningIcon(DEFAULT_ICON_SIZE.CP(scale))); warning_tooltip_.Release(); @@ -254,10 +276,15 @@ void TextInput::UpdateHintFont() hint_->SetFont((hint_font_name() + " " + std::to_string(hint_font_size())).c_str()); } -nux::ObjectPtr<nux::BaseTexture> TextInput::LoadActivatorIcon(int icon_size) +void TextInput::UpdateHintColor() +{ + hint_->SetTextColor(hint_color); +} + +nux::ObjectPtr<nux::BaseTexture> TextInput::LoadActivatorIcon(std::string const& icon_file, int icon_size) { TextureCache& cache = TextureCache::GetDefault(); - return cache.FindTexture("arrow_right.png", icon_size, icon_size); + return cache.FindTexture(icon_file, icon_size, icon_size); } nux::ObjectPtr<nux::BaseTexture> TextInput::LoadWarningIcon(int icon_size) @@ -459,15 +486,15 @@ void TextInput::UpdateBackground(bool force) cairo_graphics.DrawRoundedRectangle(cr, 1.0f, 0.5, 0.5, - BORDER_RADIUS, + border_radius(), (last_width_/scale) - 1, (last_height_/scale) - 1, false); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - cairo_set_source_rgba(cr, 0.0f, 0.0f, 0.0f, 0.35f); + cairo_set_source_rgba(cr, background_color().red, background_color().green, background_color().blue, background_color().alpha); cairo_fill_preserve(cr); cairo_set_line_width(cr, 1); - cairo_set_source_rgba(cr, 1.0f, 1.0f, 1.0f, 0.7f); + cairo_set_source_rgba(cr, border_color().red, border_color().green, border_color().blue, border_color().alpha); cairo_stroke(cr); auto texture2D = texture_ptr_from_cairo_graphics(cairo_graphics); diff --git a/unity-shared/TextInput.h b/unity-shared/TextInput.h index 969da686d..fc5b13cfa 100644 --- a/unity-shared/TextInput.h +++ b/unity-shared/TextInput.h @@ -26,6 +26,7 @@ #include "Introspectable.h" #include "IMTextEntry.h" +#include "RawPixel.h" #include "SearchBarSpinner.h" namespace nux @@ -57,10 +58,16 @@ public: IMTextEntry* text_entry() const; + nux::Property<std::string> activator_icon; + nux::Property<RawPixel> activator_icon_size; + nux::Property<nux::Color> background_color; + nux::Property<nux::Color> border_color; + nux::Property<int> border_radius; nux::RWProperty<std::string> input_string; nux::Property<std::string> input_hint; nux::Property<std::string> hint_font_name; nux::Property<int> hint_font_size; + nux::Property<nux::Color> hint_color; nux::ROProperty<bool> im_active; nux::ROProperty<bool> im_preedit; nux::Property<bool> show_activator; @@ -70,6 +77,7 @@ public: private: void OnFontChanged(); void UpdateHintFont(); + void UpdateHintColor(); void Draw(nux::GraphicsEngine& GfxContext, bool force_draw); void DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw); void UpdateBackground(bool force); @@ -84,7 +92,7 @@ private: void CheckLocks(); void OnLockStateChanged(bool); - nux::ObjectPtr<nux::BaseTexture> LoadActivatorIcon(int icon_size); + nux::ObjectPtr<nux::BaseTexture> LoadActivatorIcon(std::string const& icon_file, int icon_size); nux::ObjectPtr<nux::BaseTexture> LoadWarningIcon(int icon_size); void LoadWarningTooltip(); diff --git a/unity-shared/UnitySettings.cpp b/unity-shared/UnitySettings.cpp index 0df770d58..7109ebdf3 100644 --- a/unity-shared/UnitySettings.cpp +++ b/unity-shared/UnitySettings.cpp @@ -38,6 +38,7 @@ Settings* settings_instance = nullptr; const std::string SETTINGS_NAME = "com.canonical.Unity"; const std::string FORM_FACTOR = "form-factor"; const std::string DOUBLE_CLICK_ACTIVATE = "double-click-activate"; +const std::string DESKTOP_TYPE = "desktop-type"; const std::string LAUNCHER_SETTINGS = "com.canonical.Unity.Launcher"; const std::string LAUNCHER_POSITION = "launcher-position"; @@ -101,6 +102,7 @@ public: parent_->remote_content.SetGetterFunction(sigc::mem_fun(this, &Impl::GetRemoteContentEnabled)); parent_->launcher_position.SetGetterFunction(sigc::mem_fun(this, &Impl::GetLauncherPosition)); parent_->launcher_position.SetSetterFunction(sigc::mem_fun(this, &Impl::SetLauncherPosition)); + parent_->desktop_type.SetGetterFunction(sigc::mem_fun(this, &Impl::GetDesktopType)); for (unsigned i = 0; i < monitors::MAX; ++i) em_converters_.emplace_back(std::make_shared<EMConverter>()); @@ -247,6 +249,11 @@ public: return false; } + DesktopType GetDesktopType() const + { + return static_cast<DesktopType>(g_settings_get_enum(usettings_, DESKTOP_TYPE.c_str())); + } + int GetFontSize() const { gint font_size; diff --git a/unity-shared/UnitySettings.h b/unity-shared/UnitySettings.h index f9784ae0e..268cf3474 100644 --- a/unity-shared/UnitySettings.h +++ b/unity-shared/UnitySettings.h @@ -41,6 +41,12 @@ enum class LauncherPosition BOTTOM }; +enum class DesktopType +{ + UBUNTU, + UBUNTUKYLIN +}; + class Settings { public: @@ -57,6 +63,7 @@ public: nux::RWProperty<FormFactor> form_factor; nux::Property<bool> is_standalone; + nux::ROProperty<DesktopType> desktop_type; nux::ROProperty<bool> double_click_activate; nux::Property<unsigned> lim_movement_thresold; nux::Property<unsigned> lim_double_click_wait; |
