diff options
Diffstat (limited to 'UnityCore')
32 files changed, 473 insertions, 121 deletions
diff --git a/UnityCore/AppmenuIndicator.cpp b/UnityCore/AppmenuIndicator.cpp index ea1ba90cd..7ddb8c8c9 100644 --- a/UnityCore/AppmenuIndicator.cpp +++ b/UnityCore/AppmenuIndicator.cpp @@ -17,17 +17,81 @@ * Authored by: Marco Trevisan (Treviño) <3v1n0@ubuntu.com> */ +#include <unordered_set> + #include "AppmenuIndicator.h" +#include "ConnectionManager.h" namespace unity { namespace indicator { +namespace +{ +const Indicator::Entries empty_entries_; +} + +struct AppmenuIndicator::Impl +{ + Impl(AppmenuIndicator* parent) + { + connections_.Add(parent->on_entry_added.connect([this] (Entry::Ptr const& entry) { + window_entries_[entry->parent_window()].push_back(entry); + })); + + connections_.Add(parent->on_entry_removed.connect([this] (Entry::Ptr const& entry) { + auto it = window_entries_.find(entry->parent_window()); + + if (it != window_entries_.end()) + { + auto& entries = it->second; + entries.erase(std::remove(entries.begin(), entries.end(), entry), entries.end()); + + if (entries.empty()) + window_entries_.erase(it); + } + })); + } + + connection::Manager connections_; + std::unordered_map<uint32_t, Indicator::Entries> window_entries_; +}; AppmenuIndicator::AppmenuIndicator(std::string const& name) : Indicator(name) + , impl_(new AppmenuIndicator::Impl(this)) +{} + +AppmenuIndicator::~AppmenuIndicator() {} +void AppmenuIndicator::Sync(Indicator::Entries const& entries) +{ + std::unordered_set<uint32_t> changed_windows; + connection::Wrapper added_conn(on_entry_added.connect([this, &changed_windows] (Entry::Ptr const& entry) { + changed_windows.insert(entry->parent_window()); + })); + + connection::Wrapper rm_conn(on_entry_removed.connect([this, &changed_windows] (Entry::Ptr const& entry) { + changed_windows.insert(entry->parent_window()); + })); + + Indicator::Sync(entries); + + for (uint32_t win : changed_windows) + updated_win.emit(win); +} + +Indicator::Entries const& AppmenuIndicator::GetEntriesForWindow(uint32_t parent_window) const +{ + auto it = impl_->window_entries_.find(parent_window); + + if (it != impl_->window_entries_.end()) + return it->second; + + return empty_entries_; +} + void AppmenuIndicator::ShowAppmenu(unsigned int xid, int x, int y) const { on_show_appmenu.emit(xid, x, y); diff --git a/UnityCore/AppmenuIndicator.h b/UnityCore/AppmenuIndicator.h index 6da10ba91..bf5b4a195 100644 --- a/UnityCore/AppmenuIndicator.h +++ b/UnityCore/AppmenuIndicator.h @@ -20,6 +20,7 @@ #ifndef UNITY_APPMENU_INDICATOR_H #define UNITY_APPMENU_INDICATOR_H +#include <NuxCore/Property.h> #include "Indicator.h" namespace unity @@ -33,12 +34,20 @@ public: typedef std::shared_ptr<AppmenuIndicator> Ptr; AppmenuIndicator(std::string const& name); + ~AppmenuIndicator(); - virtual bool IsAppmenu() const { return true; } + bool IsAppmenu() const override { return true; } + void Sync(Entries const&) override; + Entries const& GetEntriesForWindow(uint32_t parent_window) const; void ShowAppmenu(unsigned xid, int x, int y) const; + sigc::signal<void, uint32_t> updated_win; sigc::signal<void, unsigned, int, int> on_show_appmenu; + +private: + struct Impl; + std::unique_ptr<Impl> impl_; }; } diff --git a/UnityCore/CMakeLists.txt b/UnityCore/CMakeLists.txt index f69d5e0a1..92191c0d5 100644 --- a/UnityCore/CMakeLists.txt +++ b/UnityCore/CMakeLists.txt @@ -117,6 +117,7 @@ set (CORE_SOURCES # include_directories(${CORE_DEPS_INCLUDE_DIRS}) include_directories(${CMAKE_BINARY_DIR}) +include_directories(..) set (LIBS ${CORE_DEPS_LDFLAGS} ${PRIVATE_CORE_DEPS_LDFLAGS}) diff --git a/UnityCore/CheckOptionFilter.cpp b/UnityCore/CheckOptionFilter.cpp index f3ea6333f..ef1c50bf2 100644 --- a/UnityCore/CheckOptionFilter.cpp +++ b/UnityCore/CheckOptionFilter.cpp @@ -19,13 +19,10 @@ #include "CheckOptionFilter.h" -#include <NuxCore/Logger.h> - namespace unity { namespace dash { -DECLARE_LOGGER(logger, "unity.dash.filter.checkoption"); CheckOptionFilter::CheckOptionFilter(DeeModel* model, DeeModelIter* iter) : Filter(model, iter) diff --git a/UnityCore/DBusIndicators.cpp b/UnityCore/DBusIndicators.cpp index e924d7ae5..d19a4aec7 100644 --- a/UnityCore/DBusIndicators.cpp +++ b/UnityCore/DBusIndicators.cpp @@ -27,19 +27,29 @@ #include "GLibSource.h" #include "Variant.h" #include "DBusIndicators.h" +#include "services/panel-service-private.h" namespace unity { namespace indicator { -DECLARE_LOGGER(logger, "unity.indicator.dbus"); namespace { -const std::string SERVICE_NAME_DESKTOP("com.canonical.Unity.Panel.Service.Desktop"); -const std::string SERVICE_NAME_LOCKSCREEN("com.canonical.Unity.Panel.Service.LockScreen"); -const std::string SERVICE_PATH("/com/canonical/Unity/Panel/Service"); -const std::string SERVICE_IFACE("com.canonical.Unity.Panel.Service"); +DECLARE_LOGGER(logger, "unity.indicator.dbus"); + +inline bool verify_variant_type(GVariant* value, const gchar* type) +{ + if (!g_variant_is_of_type (value, G_VARIANT_TYPE(type))) + { + LOG_ERROR(logger) << "Got invalid variant type: '" + << g_variant_get_type_string(value) << "' ('" + << type << "' was expected)"; + return false; + } + + return true; +} } // anonymous namespace @@ -55,6 +65,7 @@ struct DBusIndicators::Impl void Sync(GVariant* args, glib::Error const&); void SyncGeometries(std::string const& name, EntryLocationMap const& locations); void ShowEntriesDropdown(Indicator::Entries const&, Entry::Ptr const&, unsigned xid, int x, int y); + void CloseActiveEntry(); void OnConnected(); void OnDisconnected(); @@ -77,15 +88,15 @@ struct DBusIndicators::Impl glib::Source::UniquePtr show_entry_idle_; glib::Source::UniquePtr show_appmenu_idle_; std::vector<std::string> icon_paths_; - std::map<std::string, EntryLocationMap> cached_locations_; + std::unordered_map<std::string, EntryLocationMap> cached_locations_; }; // Public Methods DBusIndicators::Impl::Impl(std::string const& dbus_name, DBusIndicators* owner) : owner_(owner) - , gproxy_(dbus_name, SERVICE_PATH, SERVICE_IFACE, - G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES) + , gproxy_(dbus_name, UPS_PATH, UPS_IFACE, G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES) { gproxy_.Connect("ReSync", sigc::mem_fun(this, &DBusIndicators::Impl::OnReSync)); gproxy_.Connect("IconPathsChanged", sigc::mem_fun(this, &DBusIndicators::Impl::OnIconsPathChanged)); @@ -207,6 +218,9 @@ void DBusIndicators::Impl::OnIconsPathChanged(GVariant*) void DBusIndicators::Impl::OnEntryActivated(GVariant* parameters) { + if (!verify_variant_type(parameters, "(ss(iiuu))")) + return; + glib::String panel; glib::String entry_id; nux::Rect geo; @@ -218,6 +232,9 @@ void DBusIndicators::Impl::OnEntryActivated(GVariant* parameters) void DBusIndicators::Impl::OnEntryActivatedRequest(GVariant* parameters) { + if (!verify_variant_type(parameters, "(s)")) + return; + glib::String entry_name; g_variant_get(parameters, "(s)", &entry_name); @@ -227,6 +244,9 @@ void DBusIndicators::Impl::OnEntryActivatedRequest(GVariant* parameters) void DBusIndicators::Impl::OnEntryShowNowChanged(GVariant* parameters) { + if (!verify_variant_type(parameters, "(sb)")) + return; + glib::String entry_name; gboolean show_now; g_variant_get(parameters, "(sb)", &entry_name, &show_now); @@ -313,15 +333,21 @@ void DBusIndicators::Impl::OnEntryScroll(std::string const& entry_id, int delta) gproxy_.Call("ScrollEntry", g_variant_new("(si)", entry_id.c_str(), delta)); } +void DBusIndicators::Impl::CloseActiveEntry() +{ + gproxy_.Call("CloseActiveEntry"); +} + void DBusIndicators::Impl::Sync(GVariant* args, glib::Error const& error) { if (!args || error) return; GVariantIter* iter = nullptr; - gchar* name_hint = nullptr; gchar* indicator_id = nullptr; gchar* entry_id = nullptr; + gchar* name_hint = nullptr; + guint32 parent_window = 0; gchar* label = nullptr; gboolean label_sensitive = false; gboolean label_visible = false; @@ -331,15 +357,17 @@ void DBusIndicators::Impl::Sync(GVariant* args, glib::Error const& error) gboolean image_visible = false; gint32 priority = -1; - std::map<Indicator::Ptr, Indicator::Entries> indicators; - int wanted_idx = 0; - bool any_different_idx = false; + if (!verify_variant_type(args, "(" ENTRY_ARRAY_SIGNATURE ")")) + return; + + std::unordered_map<Indicator::Ptr, Indicator::Entries> indicators; - g_variant_get(args, "(a(ssssbbusbbi))", &iter); - while (g_variant_iter_loop(iter, "(ssssbbusbbi)", + g_variant_get(args, "(" ENTRY_ARRAY_SIGNATURE ")", &iter); + while (g_variant_iter_loop(iter, ENTRY_SIGNATURE, &indicator_id, &entry_id, &name_hint, + &parent_window, &label, &label_sensitive, &label_visible, @@ -363,27 +391,20 @@ void DBusIndicators::Impl::Sync(GVariant* args, glib::Error const& error) // Empty entries are empty indicators. if (!entry.empty()) { - Entry::Ptr e; - if (!any_different_idx) - { - // Indicators can only add or remove entries, so if - // there is a index change we can't reuse the existing ones - // after that index - if (indicator->EntryIndex(entry_id) == wanted_idx) - { - e = indicator->GetEntry(entry_id); - } - else - { - any_different_idx = true; - } - } + Entry::Ptr e = indicator->GetEntry(entry_id); + int old_priority = e ? e->priority() : -1; + + // Indicators can only add or remove entries, so if + // there is a priority change we can't reuse the existing ones + if (old_priority != priority) + e.reset(); if (!e) { - e = std::make_shared<Entry>(entry, name_hint, label, label_sensitive, - label_visible, image_type, image_data, - image_sensitive, image_visible, priority); + e = std::make_shared<Entry>(entry, name_hint, parent_window, + label, label_sensitive, label_visible, + image_type, image_data, image_sensitive, image_visible, + priority); } else { @@ -393,15 +414,12 @@ void DBusIndicators::Impl::Sync(GVariant* args, glib::Error const& error) } entries.push_back(e); - ++wanted_idx; } } g_variant_iter_free(iter); - for (auto i = indicators.begin(), end = indicators.end(); i != end; ++i) - { - i->first->Sync(indicators[i->first]); - } + for (auto const& i : indicators) + i.first->Sync(i.second); } void DBusIndicators::Impl::SyncGeometries(std::string const& name, @@ -457,7 +475,7 @@ void DBusIndicators::Impl::SyncGeometries(std::string const& name, } DBusIndicators::DBusIndicators() - : pimpl(new Impl(SERVICE_NAME_DESKTOP, this)) + : pimpl(new Impl(UPS_NAME_DESKTOP, this)) {} DBusIndicators::DBusIndicators(std::string const& dbus_name) @@ -465,7 +483,7 @@ DBusIndicators::DBusIndicators(std::string const& dbus_name) {} LockScreenDBusIndicators::LockScreenDBusIndicators() - : DBusIndicators(SERVICE_NAME_LOCKSCREEN) + : DBusIndicators(UPS_NAME_LOCKSCREEN) {} DBusIndicators::~DBusIndicators() @@ -489,6 +507,11 @@ void DBusIndicators::ShowEntriesDropdown(Indicator::Entries const& entries, pimpl->ShowEntriesDropdown(entries, selected, xid, x, y); } +void DBusIndicators::CloseActiveEntry() +{ + pimpl->CloseActiveEntry(); +} + void DBusIndicators::OnEntryScroll(std::string const& entry_id, int delta) { pimpl->OnEntryScroll(entry_id, delta); diff --git a/UnityCore/DBusIndicators.h b/UnityCore/DBusIndicators.h index a888ec86d..fb771a89d 100644 --- a/UnityCore/DBusIndicators.h +++ b/UnityCore/DBusIndicators.h @@ -40,6 +40,7 @@ public: std::vector<std::string> const& IconPaths() const; void ShowEntriesDropdown(Indicator::Entries const&, Entry::Ptr const&, unsigned xid, int x, int y); void SyncGeometries(std::string const& name, EntryLocationMap const& locations); + void CloseActiveEntry(); protected: virtual void OnEntryScroll(std::string const& entry_id, int delta); diff --git a/UnityCore/DesktopUtilities.cpp b/UnityCore/DesktopUtilities.cpp index 0fd90331d..a9a41c5e7 100644 --- a/UnityCore/DesktopUtilities.cpp +++ b/UnityCore/DesktopUtilities.cpp @@ -66,6 +66,18 @@ std::string DesktopUtilities::GetUserCacheDirectory() return ""; } +std::string DesktopUtilities::GetUserConfigDirectory() +{ + const char *config_dir = g_get_user_config_dir(); + auto unity_config = glib::gchar_to_string(config_dir).append(G_DIR_SEPARATOR_S "unity" G_DIR_SEPARATOR_S); + + if (g_mkdir_with_parents(unity_config.c_str(), 0700) >= 0) + return unity_config; + + LOG_ERROR(logger) << "Impossible to create unity config folder '"<< unity_config <<"' !"; + return ""; +} + std::string DesktopUtilities::GetUserRuntimeDirectory() { const char *runtime_dir = g_get_user_runtime_dir(); diff --git a/UnityCore/DesktopUtilities.h b/UnityCore/DesktopUtilities.h index 4bccfa21b..203603ea1 100644 --- a/UnityCore/DesktopUtilities.h +++ b/UnityCore/DesktopUtilities.h @@ -32,6 +32,7 @@ public: static std::string GetUserDataDirectory(); static std::string GetUserCacheDirectory(); static std::string GetUserRuntimeDirectory(); + static std::string GetUserConfigDirectory(); static std::vector<std::string> GetSystemDataDirectories(); static std::vector<std::string> GetDataDirectories(); diff --git a/UnityCore/Filter.cpp b/UnityCore/Filter.cpp index 6e182653d..c34909787 100644 --- a/UnityCore/Filter.cpp +++ b/UnityCore/Filter.cpp @@ -20,8 +20,6 @@ #include "Filter.h" #include "Filters.h" -#include <NuxCore/Logger.h> - #include "CheckOptionFilter.h" #include "MultiRangeFilter.h" #include "RadioOptionFilter.h" @@ -32,7 +30,6 @@ namespace unity { namespace dash { -DECLARE_LOGGER(logger, "unity.dash.filter"); using unity::glib::Signal; diff --git a/UnityCore/GLibDBusProxy.cpp b/UnityCore/GLibDBusProxy.cpp index 18149f20e..fabef7d48 100644 --- a/UnityCore/GLibDBusProxy.cpp +++ b/UnityCore/GLibDBusProxy.cpp @@ -21,7 +21,7 @@ #include "GLibDBusProxy.h" -#include <map> +#include <unordered_map> #include <memory> #include <NuxCore/Logger.h> #include <vector> @@ -30,6 +30,8 @@ #include "GLibSignal.h" #include "GLibSource.h" +#include <gio/gunixfdlist.h> + namespace unity { namespace glib @@ -47,7 +49,7 @@ class DBusProxy::Impl { public: typedef std::vector<ReplyCallback> Callbacks; - typedef std::map<string, Callbacks> SignalHandlers; + typedef std::unordered_map<string, Callbacks> SignalHandlers; Impl(DBusProxy* owner, string const& name, @@ -74,6 +76,12 @@ public: GCancellable *cancellable, GDBusCallFlags flags, int timeout_msec); + void CallWithUnixFdList(std::string const& method_name, + GVariant* parameters, + CallFinishedCallback const& callback, + GCancellable *cancellable, + GDBusCallFlags flags, + int timeout_msec); void Connect(string const& signal_name, ReplyCallback const& callback); void DisconnectSignal(string const& signal_name); @@ -81,10 +89,11 @@ public: void OnProxyNameOwnerChanged(GDBusProxy*, GParamSpec*); void OnProxySignal(GDBusProxy* proxy, const char*, const char*, GVariant*); - void OnPropertyChanged(GDBusProxy*, GVariant*, GStrv*); + void OnPropertyChanged(GDBusProxy*, GVariant*, GStrv); static void OnProxyConnectCallback(GObject* source, GAsyncResult* res, gpointer impl); static void OnCallCallback(GObject* source, GAsyncResult* res, gpointer call_data); + static void OnCallWithUnixFdListCallback(GObject* source, GAsyncResult* res, gpointer call_data); struct CallData { @@ -105,7 +114,7 @@ public: unsigned reconnection_attempts_; glib::Signal<void, GDBusProxy*, const char*, const char*, GVariant*> g_signal_connection_; - glib::Signal<void, GDBusProxy*, GVariant*, GStrv*> g_property_signal_; + glib::Signal<void, GDBusProxy*, GVariant*, GStrv> g_property_signal_; glib::Signal<void, GDBusProxy*, GParamSpec*> name_owner_signal_; glib::Source::UniquePtr reconnect_timeout_; sigc::signal<void> proxy_acquired; @@ -268,7 +277,7 @@ void DBusProxy::Impl::OnProxySignal(GDBusProxy* proxy, const char* sender_name, } } -void DBusProxy::Impl::OnPropertyChanged(GDBusProxy* proxy, GVariant* changed_props, GStrv* invalidated) +void DBusProxy::Impl::OnPropertyChanged(GDBusProxy* proxy, GVariant* changed_props, GStrv invalidated) { LOG_DEBUG(logger) << "Properties changed for proxy (" << object_path_ << ")"; @@ -294,6 +303,19 @@ void DBusProxy::Impl::OnPropertyChanged(GDBusProxy* proxy, GVariant* changed_pro g_variant_iter_free (iter); } + + for (const gchar *property_name = *invalidated; property_name; property_name = *(++invalidated)) + { + LOG_DEBUG(logger) << "Property: '" << property_name << "' invalidated"; + + auto handler_it = property_handlers_.find(property_name); + + if (handler_it != property_handlers_.end()) + { + for (ReplyCallback const& callback : handler_it->second) + callback(nullptr); + } + } } void DBusProxy::Impl::WaitForProxy(GCancellable* cancellable, @@ -399,6 +421,50 @@ void DBusProxy::Impl::Call(string const& method_name, data); } +void DBusProxy::Impl::CallWithUnixFdList(string const& method_name, + GVariant* parameters, + CallFinishedCallback const& callback, + GCancellable* cancellable, + GDBusCallFlags flags, + int timeout_msec) +{ + GCancellable* target_canc = cancellable != NULL ? cancellable : cancellable_; + + if (!proxy_) + { + glib::Variant sinked_parameters(parameters); + glib::Object<GCancellable> canc(target_canc, glib::AddRef()); + WaitForProxy(canc, timeout_msec, [this, method_name, sinked_parameters, callback, canc, flags, timeout_msec] (glib::Error const& err) + { + if (err) + { + callback(glib::Variant(), err); + LOG_WARNING(logger) << "Cannot call method " << method_name + << ": " << err; + } + else + { + CallWithUnixFdList(method_name, sinked_parameters, callback, canc, flags, timeout_msec); + } + }); + return; + } + + CallData* data = new CallData(); + data->callback = callback; + data->method_name = method_name; + + g_dbus_proxy_call_with_unix_fd_list(proxy_, + method_name.c_str(), + parameters, + flags, + timeout_msec, + nullptr, + target_canc, + DBusProxy::Impl::OnCallWithUnixFdListCallback, + data); +} + void DBusProxy::Impl::OnCallCallback(GObject* source, GAsyncResult* res, gpointer call_data) { glib::Error error; @@ -407,7 +473,7 @@ void DBusProxy::Impl::OnCallCallback(GObject* source, GAsyncResult* res, gpointe if (error) { - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { // silently ignore, don't even invoke callback, FIXME: really? return; @@ -425,6 +491,39 @@ void DBusProxy::Impl::OnCallCallback(GObject* source, GAsyncResult* res, gpointe data->callback(result, error); } +void DBusProxy::Impl::OnCallWithUnixFdListCallback(GObject* source, GAsyncResult* res, gpointer call_data) +{ + glib::Object<GUnixFDList> fd_list; + + glib::Error error; + std::unique_ptr<CallData> data(static_cast<CallData*>(call_data)); + glib::Variant result(g_dbus_proxy_call_with_unix_fd_list_finish(G_DBUS_PROXY(source), &fd_list, res, &error), glib::StealRef()); + + if (error) + { + if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + // silently ignore, don't even invoke callback, FIXME: really? + return; + } + else + { + LOG_WARNING(logger) << "Calling method \"" << data->method_name + << "\" on object path: \"" + << g_dbus_proxy_get_object_path(G_DBUS_PROXY(source)) + << "\" failed: " << error; + } + } + + if (data->callback) + { + gint idx; + g_variant_get(result, "(h)", &idx); + gint fd = g_unix_fd_list_get(fd_list, idx, nullptr); + data->callback(glib::Variant(fd), error); + } +} + void DBusProxy::Impl::Connect(std::string const& signal_name, ReplyCallback const& callback) { if (!callback) @@ -487,6 +586,17 @@ void DBusProxy::CallBegin(std::string const& method_name, timeout_msec); } +void DBusProxy::CallWithUnixFdList(std::string const& method_name, + GVariant* parameters, + CallFinishedCallback const& callback, + GCancellable *cancellable, + GDBusCallFlags flags, + int timeout_msec) +{ + pimpl->CallWithUnixFdList(method_name, parameters, callback, cancellable, + flags, timeout_msec); +} + glib::Variant DBusProxy::GetProperty(std::string const& name) const { if (IsConnected()) diff --git a/UnityCore/GLibDBusProxy.h b/UnityCore/GLibDBusProxy.h index 67ccf8559..1ead7a32c 100644 --- a/UnityCore/GLibDBusProxy.h +++ b/UnityCore/GLibDBusProxy.h @@ -64,6 +64,12 @@ public: GCancellable *cancellable = nullptr, GDBusCallFlags flags = G_DBUS_CALL_FLAGS_NONE, int timeout_msec = -1); + void CallWithUnixFdList(std::string const& method_name, + GVariant* parameters = nullptr, + CallFinishedCallback const& callback = nullptr, + GCancellable *cancellable = nullptr, + GDBusCallFlags flags = G_DBUS_CALL_FLAGS_NONE, + int timeout_msec = -1); bool IsConnected() const; diff --git a/UnityCore/GLibDBusServer.cpp b/UnityCore/GLibDBusServer.cpp index 0cd3137c4..6d01f5994 100644 --- a/UnityCore/GLibDBusServer.cpp +++ b/UnityCore/GLibDBusServer.cpp @@ -17,6 +17,7 @@ * Authored by: Marco Trevisan (Treviño) <marco.trevisan@canonical.com> */ +#include <unordered_map> #include <NuxCore/Logger.h> #include "GLibDBusServer.h" @@ -406,8 +407,8 @@ struct DBusObject::Impl GDBusInterfaceVTable interface_vtable_; std::shared_ptr<GDBusInterfaceInfo> interface_info_; - std::map<guint, std::string> registrations_; - std::map<std::string, glib::Object<GDBusConnection>> connection_by_path_; + std::unordered_map<guint, std::string> registrations_; + std::unordered_map<std::string, glib::Object<GDBusConnection>> connection_by_path_; }; DBusObject::DBusObject(std::string const& introspection_xml, std::string const& interface_name) diff --git a/UnityCore/GLibSignal-inl.h b/UnityCore/GLibSignal-inl.h index cd87128bc..e1cab8dd4 100644 --- a/UnityCore/GLibSignal-inl.h +++ b/UnityCore/GLibSignal-inl.h @@ -52,7 +52,11 @@ void Signal<R, G, Ts...>::Connect(G object, std::string const& signal_name, template <typename R, typename G, typename... Ts> R Signal<R, G, Ts...>::Callback(G object, Ts... vs, Signal* self) { - return self->callback_(object, vs...); + /* For some weird reasons, this might not be always true (see bug #1366351) */ + if (reinterpret_cast<GObject*>(object) == self->object_) + return self->callback_(object, vs...); + + return R(); } } diff --git a/UnityCore/GLibSource.h b/UnityCore/GLibSource.h index 373b9ad04..061fa2b69 100644 --- a/UnityCore/GLibSource.h +++ b/UnityCore/GLibSource.h @@ -24,7 +24,7 @@ #include <sigc++/sigc++.h> #include <glib.h> #include <memory> -#include <map> +#include <unordered_map> namespace unity { @@ -223,7 +223,7 @@ public: Source::Ptr GetSource(unsigned int id) const; protected: // For testing purposes - typedef std::map<std::string, Source::Ptr> SourcesMap; + typedef std::unordered_map<std::string, Source::Ptr> SourcesMap; SourcesMap sources_; private: diff --git a/UnityCore/GLibWrapper-inl.h b/UnityCore/GLibWrapper-inl.h index 45eb3fd6c..afeacda0a 100644 --- a/UnityCore/GLibWrapper-inl.h +++ b/UnityCore/GLibWrapper-inl.h @@ -94,6 +94,18 @@ T* Object<T>::operator->() const } template <typename T> +T** Object<T>::operator&() +{ + if (object_) + { + g_object_unref(object_); + object_ = nullptr; + } + + return &object_; +} + +template <typename T> Object<T>::operator bool() const { return bool(object_); diff --git a/UnityCore/GLibWrapper.h b/UnityCore/GLibWrapper.h index fd8fae872..d83300711 100644 --- a/UnityCore/GLibWrapper.h +++ b/UnityCore/GLibWrapper.h @@ -56,6 +56,7 @@ public: operator T* () const; operator bool() const; T* operator->() const; + T** operator&(); T* RawPtr() const; // Release ownership of the object. No unref will occur. T* Release(); diff --git a/UnityCore/GnomeSessionManager.cpp b/UnityCore/GnomeSessionManager.cpp index 107149fd5..2e4c43432 100644 --- a/UnityCore/GnomeSessionManager.cpp +++ b/UnityCore/GnomeSessionManager.cpp @@ -22,6 +22,8 @@ #include <NuxCore/Logger.h> #include "Variant.h" +#include <grp.h> + namespace unity { namespace session @@ -85,18 +87,25 @@ GnomeManager::Impl::Impl(GnomeManager* manager, bool test_mode) , can_hibernate_(false) , pending_action_(shell::Action::NONE) , shell_server_(test_mode_ ? testing::DBUS_NAME : shell::DBUS_NAME) + , open_sessions_(0) { shell_server_.AddObjects(shell::INTROSPECTION_XML, shell::DBUS_OBJECT_PATH); shell_object_ = shell_server_.GetObject(shell::DBUS_INTERFACE); shell_object_->SetMethodsCallsHandler(sigc::mem_fun(this, &Impl::OnShellMethodCall)); + manager_->is_locked = false; + manager_->is_locked.changed.connect([this] (bool locked) { + locked ? manager_->locked.emit() : manager_->unlocked.emit(); + }); + { const char* session_id = test_mode_ ? "id0" : g_getenv("XDG_SESSION_ID"); login_proxy_ = std::make_shared<glib::DBusProxy>(test_mode_ ? testing::DBUS_NAME : "org.freedesktop.login1", "/org/freedesktop/login1/session/" + glib::gchar_to_string(session_id), "org.freedesktop.login1.Session", - test_mode_ ? G_BUS_TYPE_SESSION : G_BUS_TYPE_SYSTEM); + test_mode_ ? G_BUS_TYPE_SESSION : G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES); login_proxy_->Connect("Lock", [this](GVariant*){ manager_->PromptLockScreen(); @@ -105,6 +114,10 @@ GnomeManager::Impl::Impl(GnomeManager* manager, bool test_mode) login_proxy_->Connect("Unlock", [this](GVariant*){ manager_->unlock_requested.emit(); }); + + login_proxy_->ConnectProperty("Active", [this] (GVariant* active) { + manager_->screensaver_requested.emit(!glib::Variant(active).GetBool()); + }); } { @@ -126,6 +139,22 @@ GnomeManager::Impl::Impl(GnomeManager* manager, bool test_mode) }); } + { + dm_proxy_ = std::make_shared<glib::DBusProxy>("org.freedesktop.DisplayManager", + "/org/freedesktop/DisplayManager", + "org.freedesktop.DisplayManager", + G_BUS_TYPE_SYSTEM); + + dm_proxy_->Connect("SessionAdded", sigc::hide(sigc::mem_fun(this, &Impl::UpdateHaveOtherOpenSessions))); + dm_proxy_->Connect("SessionRemoved", sigc::hide(sigc::mem_fun(this, &Impl::UpdateHaveOtherOpenSessions))); + + UpdateHaveOtherOpenSessions(); + + manager_->have_other_open_sessions.SetGetterFunction([this]() { + return open_sessions_ > 1; + }); + } + CallLogindMethod("CanHibernate", nullptr, [this] (GVariant* variant, glib::Error const& err) { if (err) { @@ -404,21 +433,73 @@ void GnomeManager::Impl::LockScreen(bool prompt) { EnsureCancelPendingAction(); - glib::Object<GSettings> lockdown_settings(g_settings_new(GNOME_LOCKDOWN_OPTIONS.c_str())); - - if (g_settings_get_boolean(lockdown_settings, DISABLE_LOCKSCREEN_KEY.c_str())) + if (!manager_->CanLock()) { manager_->ScreenSaverActivate(); return; } - else if (manager_->UserName().find("guest-") == 0) + + prompt ? manager_->prompt_lock_requested.emit() : manager_->lock_requested.emit(); +} + +void GnomeManager::Impl::UpdateHaveOtherOpenSessions() +{ + dm_proxy_->GetProperty("Sessions", [this](GVariant* variant) { + GVariantIter *sessions; + g_variant_get(variant, "ao", &sessions); + int open_sessions = g_variant_iter_n_children(sessions); + + if (open_sessions_ != open_sessions) + { + open_sessions_ = open_sessions; + manager_->have_other_open_sessions.changed.emit(open_sessions_); + } + }); +} + +bool GnomeManager::Impl::HasInhibitors() +{ + glib::Error error; + glib::Object<GDBusConnection> bus(g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, &error)); + + if (error) { - LOG_INFO(logger) << "Impossible to lock a guest session"; - manager_->ScreenSaverActivate(); - return; + LOG_ERROR(logger) << "Impossible to get the session bus, to fetch the inhibitors: " << error; + return false; } - prompt ? manager_->prompt_lock_requested.emit() : manager_->lock_requested.emit(); + enum class Inhibited : unsigned + { + LOGOUT = 1, + USER_SWITCH = 2, + SUSPEND = 4, + IDLE_SET = 8 + }; + + glib::Variant inhibitors(g_dbus_connection_call_sync(bus, test_mode_ ? testing::DBUS_NAME.c_str() : "org.gnome.SessionManager", + "/org/gnome/SessionManager", "org.gnome.SessionManager", + "IsInhibited", g_variant_new("(u)", Inhibited::LOGOUT), nullptr, + G_DBUS_CALL_FLAGS_NONE, 500, nullptr, &error)); + + if (error) + { + LOG_ERROR(logger) << "Impossible to get the inhibitors: " << error; + return false; + } + + return inhibitors.GetBool(); +} + +bool GnomeManager::Impl::IsUserInGroup(std::string const& user_name, std::string const& group_name) +{ + auto group = getgrnam(group_name.c_str()); + + if (group && group->gr_mem) + for (int i = 0; group->gr_mem[i]; ++i) + if (g_strcmp0(group->gr_mem[i], user_name.c_str()) == 0) + return true; + + return false; } // Public implementation @@ -584,6 +665,23 @@ void GnomeManager::Hibernate() }); } +bool GnomeManager::CanLock() const +{ + if (is_locked()) + return true; + + glib::Object<GSettings> lockdown_settings(g_settings_new(GNOME_LOCKDOWN_OPTIONS.c_str())); + + if (g_settings_get_boolean(lockdown_settings, DISABLE_LOCKSCREEN_KEY.c_str()) || + UserName().find("guest-") == 0 || + impl_->IsUserInGroup(UserName(), "nopasswdlogin")) + { + return false; + } + + return true; +} + bool GnomeManager::CanShutdown() const { return impl_->can_shutdown_; @@ -599,6 +697,11 @@ bool GnomeManager::CanHibernate() const return impl_->can_hibernate_; } +bool GnomeManager::HasInhibitors() const +{ + return impl_->HasInhibitors(); +} + void GnomeManager::CancelAction() { impl_->CancelAction(); diff --git a/UnityCore/GnomeSessionManager.h b/UnityCore/GnomeSessionManager.h index 6bb5836b9..df7df1178 100644 --- a/UnityCore/GnomeSessionManager.h +++ b/UnityCore/GnomeSessionManager.h @@ -47,9 +47,11 @@ public: void Suspend(); void Hibernate(); + bool CanLock() const; bool CanShutdown() const; bool CanSuspend() const; bool CanHibernate() const; + bool HasInhibitors() const; void CancelAction(); diff --git a/UnityCore/GnomeSessionManagerImpl.h b/UnityCore/GnomeSessionManagerImpl.h index 1045b78db..ee26c3171 100644 --- a/UnityCore/GnomeSessionManagerImpl.h +++ b/UnityCore/GnomeSessionManagerImpl.h @@ -51,6 +51,7 @@ struct GnomeManager::Impl void ConfirmShutdown(); void CancelAction(); void ClosedDialog(); + bool HasInhibitors(); void EnsureCancelPendingAction(); void LockScreen(bool prompt); @@ -61,6 +62,9 @@ struct GnomeManager::Impl void CallLogindMethod(std::string const& method, GVariant* parameters = nullptr, glib::DBusProxy::CallFinishedCallback const& cb = nullptr); void CallConsoleKitMethod(std::string const& method, GVariant* parameters = nullptr); bool InteractiveMode(); + void UpdateHaveOtherOpenSessions(); + + bool IsUserInGroup(std::string const& user_name, std::string const& group_name); GnomeManager* manager_; bool test_mode_; @@ -73,6 +77,9 @@ struct GnomeManager::Impl glib::DBusObject::Ptr shell_object_; glib::DBusProxy::Ptr login_proxy_; glib::DBusProxy::Ptr presence_proxy_; + glib::DBusProxy::Ptr dm_proxy_; + + int open_sessions_; }; } // namespace session diff --git a/UnityCore/Indicator.cpp b/UnityCore/Indicator.cpp index bcfa90fe0..1bf81c61d 100644 --- a/UnityCore/Indicator.cpp +++ b/UnityCore/Indicator.cpp @@ -36,7 +36,7 @@ Indicator::Indicator(std::string const& name) Indicator::~Indicator() { for (auto const& entry : entries_) - on_entry_removed.emit(entry->id()); + on_entry_removed.emit(entry); } std::string const& Indicator::name() const @@ -51,23 +51,23 @@ Indicator::Entries const& Indicator::GetEntries() const void Indicator::Sync(Indicator::Entries const& new_entries) { - bool added = false; - Entries to_rm; + bool changed = false; - if (!entries_.empty()) + for (auto it = entries_.begin(); it != entries_.end();) { - for (auto const& entry : entries_) + auto entry = *it; + + if (std::find(new_entries.begin(), new_entries.end(), entry) == new_entries.end()) { - if (std::find(new_entries.begin(), new_entries.end(), entry) == new_entries.end()) - to_rm.push_back(entry); + auto entry_id = entry->id(); + entries_connections_.erase(entry); + it = entries_.erase(it); + on_entry_removed.emit(entry); + changed = true; + continue; } - } - for (auto const& entry : to_rm) - { - entries_connections_.erase(entry); - on_entry_removed.emit(entry->id()); - entries_.remove(entry); + ++it; } for (auto const& new_entry : new_entries) @@ -93,10 +93,10 @@ void Indicator::Sync(Indicator::Entries const& new_entries) entries_.push_back(new_entry); on_entry_added.emit(new_entry); - added = true; + changed = true; } - if (!to_rm.empty() || added) + if (changed) updated.emit(); } @@ -109,21 +109,6 @@ Entry::Ptr Indicator::GetEntry(std::string const& entry_id) const return Entry::Ptr(); } -int Indicator::EntryIndex(std::string const& entry_id) const -{ - int i = 0; - for (auto const& entry : entries_) - { - if (entry->id() == entry_id) - { - return i; - } - ++i; - } - - return -1; -} - std::ostream& operator<<(std::ostream& out, Indicator const& i) { out << "<Indicator " << i.name() << std::endl; diff --git a/UnityCore/Indicator.h b/UnityCore/Indicator.h index c69de785a..53c65da66 100644 --- a/UnityCore/Indicator.h +++ b/UnityCore/Indicator.h @@ -38,7 +38,7 @@ class Indicator : public sigc::trackable, boost::noncopyable { public: typedef std::shared_ptr<Indicator> Ptr; - typedef std::list<Entry::Ptr> Entries; + typedef std::vector<Entry::Ptr> Entries; Indicator(std::string const& name); virtual ~Indicator(); @@ -47,15 +47,14 @@ public: virtual bool IsAppmenu() const { return false; } - void Sync(Entries const& new_entries); + virtual void Sync(Entries const&); Entry::Ptr GetEntry(std::string const& entry_id) const; - int EntryIndex(std::string const& entry_id) const; Entries const& GetEntries() const; // Signals sigc::signal<void> updated; sigc::signal<void, Entry::Ptr const&> on_entry_added; - sigc::signal<void, std::string const&> on_entry_removed; + sigc::signal<void, Entry::Ptr const&> on_entry_removed; sigc::signal<void, std::string const&, unsigned, int, int, unsigned> on_show_menu; sigc::signal<void, std::string const&> on_secondary_activate; sigc::signal<void, std::string const&, int> on_scroll; diff --git a/UnityCore/IndicatorEntry.cpp b/UnityCore/IndicatorEntry.cpp index bd5a5422d..e56611505 100644 --- a/UnityCore/IndicatorEntry.cpp +++ b/UnityCore/IndicatorEntry.cpp @@ -30,6 +30,7 @@ namespace indicator Entry::Entry(std::string const& id, std::string const& name_hint, + uint32_t parent_window, std::string const& label, bool label_sensitive, bool label_visible, @@ -40,6 +41,7 @@ Entry::Entry(std::string const& id, int priority) : id_(id) , name_hint_(name_hint) + , parent_window_(parent_window) , label_(label) , label_visible_(label_visible) , label_sensitive_(label_sensitive) @@ -52,9 +54,10 @@ Entry::Entry(std::string const& id, , active_(false) {} -Entry::Entry(std::string const& id, std::string const& name_hint) +Entry::Entry(std::string const& id, std::string const& name_hint, uint32_t parent_window) : id_(id) , name_hint_(name_hint) + , parent_window_(parent_window) , label_visible_(false) , label_sensitive_(false) , image_type_(0) @@ -65,14 +68,19 @@ Entry::Entry(std::string const& id, std::string const& name_hint) , active_(false) {} +std::string const& Entry::id() const +{ + return id_; +} + std::string const& Entry::name_hint() const { return name_hint_; } -std::string const& Entry::id() const +uint32_t Entry::parent_window() const { - return id_; + return parent_window_; } std::string const& Entry::label() const @@ -199,6 +207,7 @@ Entry& Entry::operator=(Entry const& rhs) id_ = rhs.id_; name_hint_ = rhs.name_hint_; + parent_window_ = rhs.parent_window_; label_ = rhs.label_; label_sensitive_ = rhs.label_sensitive_; label_visible_ = rhs.label_visible_; @@ -258,7 +267,7 @@ std::vector<Entry::Ptr> const& Entry::parents() const void Entry::ShowMenu(int x, int y, unsigned button) { - ShowMenu(0, x, y, button); + ShowMenu(parent_window_, x, y, button); } void Entry::ShowMenu(unsigned int xid, int x, int y, unsigned button) @@ -278,7 +287,8 @@ void Entry::Scroll(int delta) std::ostream& operator<<(std::ostream& out, Entry const& e) { - out << "<indicator::Entry " << e.id() << " hint: '" << e.name_hint() << "' " + out << "<indicator::Entry " << e.id() << " hint: '" << e.name_hint() << "'" + << " parent window: " << e.parent_window() << std::boolalpha << " \"" << e.label() << "\" (" << e.label_sensitive() << ", " << e.label_visible() << ") image (" diff --git a/UnityCore/IndicatorEntry.h b/UnityCore/IndicatorEntry.h index 9e7768623..b00d94ef7 100644 --- a/UnityCore/IndicatorEntry.h +++ b/UnityCore/IndicatorEntry.h @@ -44,9 +44,10 @@ class Entry public: typedef std::shared_ptr<Entry> Ptr; - Entry(std::string const& id, std::string const& name_hint = ""); + Entry(std::string const& id, std::string const& name_hint = "", uint32_t parent_window = 0); Entry(std::string const& id, std::string const& name_hint, + uint32_t parent_window, std::string const& label, bool label_sensitive, bool label_visible, @@ -61,6 +62,7 @@ public: std::string const& id() const; std::string const& name_hint() const; + uint32_t parent_window() const; void set_image(int type, std::string const& data, bool sensitive, bool visible); bool image_visible() const; @@ -114,6 +116,7 @@ public: private: std::string id_; std::string name_hint_; + uint32_t parent_window_; std::string label_; bool label_visible_; diff --git a/UnityCore/Indicators.cpp b/UnityCore/Indicators.cpp index a07f9f537..b66b271c0 100644 --- a/UnityCore/Indicators.cpp +++ b/UnityCore/Indicators.cpp @@ -20,6 +20,7 @@ #include "Indicators.h" #include "AppmenuIndicator.h" +#include "services/panel-service-private.h" namespace unity { @@ -143,7 +144,7 @@ Indicator::Ptr Indicators::Impl::AddIndicator(std::string const& name) if (indicator) return indicator; - if (name == "libappmenu.so") + if (name == APPMENU_INDICATOR_NAME) { auto appmenu = std::make_shared<AppmenuIndicator>(name); appmenu->on_show_appmenu.connect(sigc::mem_fun(owner_, &Indicators::OnShowAppMenu)); diff --git a/UnityCore/Indicators.h b/UnityCore/Indicators.h index f87b0c35b..3351f9462 100644 --- a/UnityCore/Indicators.h +++ b/UnityCore/Indicators.h @@ -44,6 +44,7 @@ public: virtual void SyncGeometries(std::string const& panel, EntryLocationMap const&) = 0; virtual void ShowEntriesDropdown(Indicator::Entries const&, Entry::Ptr const&, unsigned xid, int x, int y) = 0; + virtual void CloseActiveEntry() = 0; // Signals sigc::signal<void, Indicator::Ptr const&> on_object_added; diff --git a/UnityCore/MultiRangeFilter.cpp b/UnityCore/MultiRangeFilter.cpp index e7f1e6637..2919fb8a9 100644 --- a/UnityCore/MultiRangeFilter.cpp +++ b/UnityCore/MultiRangeFilter.cpp @@ -19,13 +19,10 @@ #include "MultiRangeFilter.h" -#include <NuxCore/Logger.h> - namespace unity { namespace dash { -DECLARE_LOGGER(logger, "unity.dash.filter.multirange"); MultiRangeFilter::MultiRangeFilter(DeeModel* model, DeeModelIter* iter) : Filter(model, iter) diff --git a/UnityCore/MusicPreview.cpp b/UnityCore/MusicPreview.cpp index 1ff05f4f4..f81c5a417 100644 --- a/UnityCore/MusicPreview.cpp +++ b/UnityCore/MusicPreview.cpp @@ -29,7 +29,6 @@ namespace unity { namespace dash { -DECLARE_LOGGER(logger, "unity.dash.musicpreview"); class MusicPreview::Impl { diff --git a/UnityCore/RadioOptionFilter.cpp b/UnityCore/RadioOptionFilter.cpp index f65dd8c6b..ba664154a 100644 --- a/UnityCore/RadioOptionFilter.cpp +++ b/UnityCore/RadioOptionFilter.cpp @@ -19,13 +19,10 @@ #include "RadioOptionFilter.h" -#include <NuxCore/Logger.h> - namespace unity { namespace dash { -DECLARE_LOGGER(logger, "unity.dash.filter.radiooption"); RadioOptionFilter::RadioOptionFilter(DeeModel* model, DeeModelIter* iter) : Filter(model, iter) diff --git a/UnityCore/Scope.cpp b/UnityCore/Scope.cpp index 35937490c..498722413 100644 --- a/UnityCore/Scope.cpp +++ b/UnityCore/Scope.cpp @@ -32,6 +32,12 @@ namespace dash { DECLARE_LOGGER(logger, "unity.dash.scope"); +GQuark +g_scope_error_quark (void) +{ + return g_quark_from_static_string ("g-scope-error-quark"); +} + class Scope::Impl { public: diff --git a/UnityCore/Scope.h b/UnityCore/Scope.h index 9622f30c5..7c06c285b 100644 --- a/UnityCore/Scope.h +++ b/UnityCore/Scope.h @@ -31,9 +31,8 @@ namespace unity namespace dash { -namespace -{ #define G_SCOPE_ERROR g_scope_error_quark () + typedef enum { G_SCOPE_ERROR_NO_ACTIVATION_HANDLER = (1 << 0), @@ -41,11 +40,7 @@ typedef enum } GScopeError; GQuark -g_scope_error_quark (void) -{ - return g_quark_from_static_string ("g-scope-error-quark"); -} -} +g_scope_error_quark (void); class Scope : public sigc::trackable, boost::noncopyable { diff --git a/UnityCore/SessionManager.h b/UnityCore/SessionManager.h index fb45e5253..f6a0d6933 100644 --- a/UnityCore/SessionManager.h +++ b/UnityCore/SessionManager.h @@ -23,6 +23,8 @@ #include <sigc++/sigc++.h> #include <memory> +#include <NuxCore/Property.h> + namespace unity { namespace session @@ -36,6 +38,9 @@ public: Manager() = default; virtual ~Manager() = default; + nux::ROProperty<bool> have_other_open_sessions; + nux::Property<bool> is_locked; + virtual std::string RealName() const = 0; virtual std::string UserName() const = 0; virtual std::string HostName() const = 0; @@ -50,9 +55,11 @@ public: virtual void Suspend() = 0; virtual void Hibernate() = 0; + virtual bool CanLock() const = 0; virtual bool CanShutdown() const = 0; virtual bool CanSuspend() const = 0; virtual bool CanHibernate() const = 0; + virtual bool HasInhibitors() const = 0; virtual void CancelAction() = 0; diff --git a/UnityCore/pch/unitycore_pch.hh b/UnityCore/pch/unitycore_pch.hh index 6fdf1d30e..d0b76b782 100644 --- a/UnityCore/pch/unitycore_pch.hh +++ b/UnityCore/pch/unitycore_pch.hh @@ -29,6 +29,7 @@ #include <map> #include <memory> #include <unordered_map> +#include <functional> #include <boost/utility.hpp> #include <dee.h> |
