diff options
Diffstat (limited to 'src/rotation-lock.cpp')
-rw-r--r-- | src/rotation-lock.cpp | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/src/rotation-lock.cpp b/src/rotation-lock.cpp index 0a80085..3bbe12a 100644 --- a/src/rotation-lock.cpp +++ b/src/rotation-lock.cpp @@ -17,3 +17,181 @@ * Charles Kerr <charles.kerr@canonical.com> */ +#include <src/rotation-lock.h> + +#include <glib/gi18n.h> + +class RotationLockIndicator::Impl +{ +public: + + Impl(): + m_settings(g_settings_new(m_schema_name)), + m_action_group(create_action_group()) + { + // build the rotation lock icon + auto icon = g_themed_icon_new_with_default_fallbacks("orientation-lock"); + auto icon_deleter = [](GIcon* o){g_object_unref(G_OBJECT(o));}; + m_icon.reset(icon, icon_deleter); + + // build the phone profile + auto menu_model_deleter = [](GMenuModel* o){g_object_unref(G_OBJECT(o));}; + std::shared_ptr<GMenuModel> phone_menu (create_phone_menu(), menu_model_deleter); + m_phone = std::make_shared<SimpleProfile>("phone", phone_menu); + update_phone_header(); + } + + ~Impl() + { + g_clear_object(&m_action_group); + g_clear_object(&m_settings); + } + + GSimpleActionGroup* action_group() const + { + return m_action_group; + } + + std::vector<std::shared_ptr<Profile>> profiles() + { + std::vector<std::shared_ptr<Profile>> ret; + ret.push_back(m_phone); + return ret; + } + +private: + + /*** + **** Actions + ***/ + + static gboolean settings_to_action_state(GValue *value, + GVariant *variant, + gpointer /*unused*/) + { + bool is_locked = g_strcmp0(g_variant_get_string(variant, nullptr), "none"); + g_value_set_variant(value, g_variant_new_boolean(is_locked)); + return TRUE; + } + + static GVariant* action_state_to_settings(const GValue *value, + const GVariantType * /*expected_type*/, + gpointer /*unused*/) + { + // Toggling to 'on' *should* lock to the screen's current orientation. + // We don't have any way of knowing Screen.orientation in this service, + // so just pick one at random to satisfy the binding's needs. + // + // In practice this doesn't matter since the indicator isn't visible + // when the lock mode is 'none' so the end user won't ever be able + // to toggle the menuitem from None to anything else. + + auto state_is_true = g_variant_get_boolean(g_value_get_variant(value)); + return g_variant_new_string(state_is_true ? "PrimaryOrientation" : "none"); + } + + GSimpleActionGroup* create_action_group() + { + GSimpleActionGroup* group; + GSimpleAction* action; + + group = g_simple_action_group_new(); + action = g_simple_action_new_stateful("rotation-lock", + nullptr, + g_variant_new_boolean(false)); + g_settings_bind_with_mapping(m_settings, "orientation-lock", + action, "state", + G_SETTINGS_BIND_DEFAULT, + settings_to_action_state, + action_state_to_settings, + nullptr, + nullptr); + g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(action)); + g_object_unref(G_OBJECT(action)); + g_signal_connect_swapped(m_settings, "changed::orientation-lock", + G_CALLBACK(on_orientation_lock_setting_changed), this); + + return group; + } + + /*** + **** Phone profile + ***/ + + static void on_orientation_lock_setting_changed (gpointer gself) + { + static_cast<Impl*>(gself)->update_phone_header(); + } + + GMenuModel* create_phone_menu() + { + GMenu* menu; + GMenuItem* menu_item; + + menu = g_menu_new(); + + menu_item = g_menu_item_new(_("Rotation Lock"), "indicator.rotation-lock"); + g_menu_item_set_attribute(menu_item, "x-canonical-type", "s", "com.canonical.indicator.switch"); + g_menu_append_item(menu, menu_item); + g_object_unref(menu_item); + + return G_MENU_MODEL(menu); + } + + void update_phone_header() + { + Header h; + h.title = _("Rotation lock"); + h.a11y = h.title; + h.is_visible = g_settings_get_enum(m_settings, "orientation-lock") != 0; + h.icon = m_icon; + m_phone->header().set(h); + } + + /*** + **** + ***/ + + static constexpr char const * m_schema_name {"com.ubuntu.touch.system"}; + static constexpr char const * m_orientation_lock_icon_name {"orientation-lock"}; + GSettings* m_settings = nullptr; + GSimpleActionGroup* m_action_group = nullptr; + std::shared_ptr<SimpleProfile> m_phone; + std::shared_ptr<GIcon> m_icon; +}; + +/*** +**** +***/ + +RotationLockIndicator::RotationLockIndicator(): + impl(new Impl()) +{ +} + +RotationLockIndicator::~RotationLockIndicator() +{ +} + +std::vector<std::shared_ptr<Profile>> +RotationLockIndicator::profiles() const +{ + return impl->profiles(); +} + +GSimpleActionGroup* +RotationLockIndicator::action_group() const +{ + return impl->action_group(); +} + +const char* +RotationLockIndicator::name() const +{ + return "rotation_lock"; +} + +/*** +**** +***/ + |