From abcbf6b7ff2f09fc0351b32e9977db9a1d7a0e1b Mon Sep 17 00:00:00 2001 From: Robert Tari Date: Mon, 9 Oct 2023 18:37:07 +0200 Subject: Rename Indicator Service --- data/CMakeLists.txt | 2 +- data/org.ayatana.indicator.display | 13 +++++++++++++ data/org.ayatana.indicator.rotation_lock | 13 ------------- 3 files changed, 14 insertions(+), 14 deletions(-) create mode 100644 data/org.ayatana.indicator.display delete mode 100644 data/org.ayatana.indicator.rotation_lock diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt index 81b13f4..38ba788 100644 --- a/data/CMakeLists.txt +++ b/data/CMakeLists.txt @@ -51,7 +51,7 @@ install (FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.desktop" DESTI set (AYATANA_INDICATOR_DIR "${CMAKE_INSTALL_FULL_DATAROOTDIR}/ayatana/indicators") message (STATUS "${AYATANA_INDICATOR_DIR} is the Ayatana Indicator install dir") -set (AYATANA_INDICATOR_NAME "org.ayatana.indicator.rotation_lock") +set (AYATANA_INDICATOR_NAME "org.ayatana.indicator.display") set (AYATANA_INDICATOR_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${AYATANA_INDICATOR_NAME}") install (FILES "${AYATANA_INDICATOR_FILE}" diff --git a/data/org.ayatana.indicator.display b/data/org.ayatana.indicator.display new file mode 100644 index 0000000..cc4fe85 --- /dev/null +++ b/data/org.ayatana.indicator.display @@ -0,0 +1,13 @@ +[Indicator Service] +Name=ayatana-indicator-display +ObjectPath=/org/ayatana/indicator/display +Position=90 + +[phone] +ObjectPath=/org/ayatana/indicator/display/phone + +[phone_greeter] +ObjectPath=/org/ayatana/indicator/display/phone + +[desktop] +ObjectPath=/org/ayatana/indicator/display/desktop diff --git a/data/org.ayatana.indicator.rotation_lock b/data/org.ayatana.indicator.rotation_lock deleted file mode 100644 index 050f1a0..0000000 --- a/data/org.ayatana.indicator.rotation_lock +++ /dev/null @@ -1,13 +0,0 @@ -[Indicator Service] -Name=ayatana-indicator-rotation-lock -ObjectPath=/org/ayatana/indicator/rotation_lock -Position=90 - -[phone] -ObjectPath=/org/ayatana/indicator/rotation_lock/phone - -[phone_greeter] -ObjectPath=/org/ayatana/indicator/rotation_lock/phone - -[desktop] -ObjectPath=/org/ayatana/indicator/rotation_lock/desktop -- cgit v1.2.3 From 132a445a9eb633d611f18f27f2f8e5742aa537f3 Mon Sep 17 00:00:00 2001 From: Robert Tari Date: Mon, 9 Oct 2023 18:41:46 +0200 Subject: Rename indicator class and service source files --- po/POTFILES.in | 2 +- src/CMakeLists.txt | 2 +- src/main.cpp | 8 +- src/rotation-lock.cpp | 757 -------------------------------------- src/rotation-lock.h | 42 --- src/service.cpp | 757 ++++++++++++++++++++++++++++++++++++++ src/service.h | 44 +++ tests/unit/rotation-lock-test.cpp | 6 +- 8 files changed, 809 insertions(+), 809 deletions(-) delete mode 100644 src/rotation-lock.cpp delete mode 100644 src/rotation-lock.h create mode 100644 src/service.cpp create mode 100644 src/service.h diff --git a/po/POTFILES.in b/po/POTFILES.in index 1cb6f88..1802d8d 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -4,7 +4,7 @@ src/exporter.cpp src/greeter.cpp src/indicator.cpp src/main.cpp -src/rotation-lock.cpp +src/service.cpp src/usb-manager.cpp src/usb-monitor.cpp src/usb-snap.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d66cc1c..f0158ea 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,7 +7,7 @@ add_compile_options( set (SERVICE_LIB_SOURCES exporter.cpp indicator.cpp - rotation-lock.cpp + service.cpp ) if (ENABLE_LOMIRI_FEATURES) diff --git a/src/main.cpp b/src/main.cpp index 03c72c6..49832c6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,6 @@ /* * Copyright 2014 Canonical Ltd. - * Copyright 2022 Robert Tari + * Copyright 2022-2023 Robert Tari * * 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 @@ -20,7 +20,7 @@ */ #include -#include +#include #ifdef LOMIRI_FEATURES_ENABLED #include @@ -57,11 +57,9 @@ main(int /*argc*/, char** /*argv*/) g_main_loop_quit(loop); }; - // build all our indicators. - // Right now we've only got one -- rotation lock -- but hey, we can dream. std::vector> indicators; std::vector> exporters; - indicators.push_back(std::make_shared()); + indicators.push_back(std::make_shared()); for (auto& indicator : indicators) { auto exporter = std::make_shared(indicator); exporter->name_lost().connect(on_name_lost); diff --git a/src/rotation-lock.cpp b/src/rotation-lock.cpp deleted file mode 100644 index 9e2971b..0000000 --- a/src/rotation-lock.cpp +++ /dev/null @@ -1,757 +0,0 @@ -/* - * Copyright 2014 Canonical Ltd. - * Copyright 2023 Robert Tari - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 3. - * - * 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - * - * Authors: - * Charles Kerr - * Robert Tari - */ - -#include -#include - -#ifdef COLOR_TEMP_ENABLED -#include -#endif - -extern "C" -{ - #include - - #ifdef COLOR_TEMP_ENABLED - #include "solar.h" - #endif -} - -#ifdef COLOR_TEMP_ENABLED -typedef struct -{ - guint nTempLow; - guint nTempHigh; - gchar *sName; -} TempProfile; - -TempProfile m_lTempProfiles[] = -{ - {0, 0, _("Manual")}, - {4500, 6500, _("Adaptive (Colder)")}, - {3627, 4913, _("Adaptive")}, - {3058, 4913, _("Adaptive (Warmer)")}, - {0, 0, NULL} -}; -#endif - -class RotationLockIndicator::Impl -{ -public: - - Impl() - { - GSettingsSchemaSource *pSource = g_settings_schema_source_get_default(); - const gchar *sTest = g_getenv ("TEST_NAME"); - this->bTest = (sTest != NULL && g_str_equal (sTest, "rotation-lock-test")); - - if (pSource != NULL) - { - if (ayatana_common_utils_is_lomiri()) { - - GSettingsSchema *pSchema = g_settings_schema_source_lookup(pSource, "com.lomiri.touch.system", FALSE); - - if (pSchema != NULL) - { - g_settings_schema_unref(pSchema); - m_settings = g_settings_new("com.lomiri.touch.system"); - } - else - { - g_error("No schema could be found"); - } - - } - else { - - GSettingsSchema *pSchema = g_settings_schema_source_lookup(pSource, "org.ayatana.indicator.display", FALSE); - - if (pSchema != NULL) - { - g_settings_schema_unref(pSchema); - m_settings = g_settings_new("org.ayatana.indicator.display"); - } - else - { - g_error("No schema could be found"); - } - - const gchar *sSchema = NULL; - - if (this->bTest) - { - sSchema = "org.ayatana.indicator.display"; - } - else - { - if (ayatana_common_utils_is_mate ()) - { - sSchema = "org.mate.interface"; - } - else - { - sSchema = "org.gnome.desktop.interface"; - } - } - - pSchema = g_settings_schema_source_lookup (pSource, sSchema, FALSE); - - if (pSchema != NULL) - { - g_settings_schema_unref (pSchema); - pThemeSettings = g_settings_new (sSchema); - } - else - { - g_error("No %s schema could be found", sSchema); - } - - if (this->bTest) - { - sSchema = "org.ayatana.indicator.display"; - } - else - { - sSchema = "org.gnome.desktop.interface"; - } - - pSchema = g_settings_schema_source_lookup (pSource, sSchema, FALSE); - - if (pSchema != NULL) - { - g_settings_schema_unref (pSchema); - pColorSchemeSettings = g_settings_new (sSchema); - } - else - { - g_error("No %s schema could be found", sSchema); - } - } - } - - m_action_group = create_action_group(); - - // build the icon - const char *rotation_lock_icon_name {"orientation-lock"}; - - if (!ayatana_common_utils_is_lomiri()) - { - rotation_lock_icon_name = "display-panel"; - } - - auto icon = g_themed_icon_new_with_default_fallbacks(rotation_lock_icon_name); - 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 phone_menu (create_phone_menu(), menu_model_deleter); - m_phone = std::make_shared("phone", phone_menu); - update_phone_header(); - - // build the desktop profile - std::shared_ptr desktop_menu (create_desktop_menu(), menu_model_deleter); - m_desktop = std::make_shared("desktop", desktop_menu); - update_desktop_header(); - -#ifdef COLOR_TEMP_ENABLED - if (ayatana_common_utils_is_lomiri() == FALSE) - { - if (!this->bTest) - { - this->fLatitude = g_settings_get_double (this->m_settings, "latitude"); - this->fLongitude = g_settings_get_double (this->m_settings, "longitude"); - gclue_simple_new ("ayatana-indicator-display", GCLUE_ACCURACY_LEVEL_CITY, NULL, onGeoClueLoaded, this); - this->nCallback = g_timeout_add_seconds (60, updateColor, this); - updateColor (this); - } - } -#endif - } - - ~Impl() - { - if (nCallback) - { - g_source_remove (nCallback); - } - - g_signal_handlers_disconnect_by_data(m_settings, this); - g_clear_object(&m_action_group); - g_clear_object(&m_settings); - - if (sLastTheme) - { - g_free (sLastTheme); - } - - if (pThemeSettings) - { - g_clear_object (&pThemeSettings); - } - - if (pColorSchemeSettings) - { - g_clear_object (&pColorSchemeSettings); - } - } - - GSimpleActionGroup* action_group() const - { - return m_action_group; - } - - std::vector> profiles() - { - std::vector> ret; - ret.push_back(m_phone); - ret.push_back(m_desktop); - return ret; - } - -private: - -#ifdef COLOR_TEMP_ENABLED - static gboolean updateColor (gpointer pData) - { - RotationLockIndicator::Impl *pImpl = (RotationLockIndicator::Impl*) pData; - guint nProfile = 0; - g_settings_get (pImpl->m_settings, "color-temp-profile", "q", &nProfile); - gdouble fBrightness = g_settings_get_double (pImpl->m_settings, "brightness"); - gchar *sThemeProfile = g_settings_get_string (pImpl->m_settings, "theme-profile"); - gboolean bThemeAdaptive = g_str_equal (sThemeProfile, "adaptive"); - guint nTemperature = 0; - const gchar *sColorScheme = NULL; - gchar *sTheme = NULL; - gint64 nNow = g_get_real_time (); - gdouble fElevation = solar_elevation((gdouble) nNow / 1000000.0, pImpl->fLatitude, pImpl->fLongitude); - - if (nProfile == 0) - { - g_settings_get (pImpl->m_settings, "color-temp", "q", &nTemperature); - } - else - { - gdouble fShifting = 0.0; - - if (fElevation < SOLAR_CIVIL_TWILIGHT_ELEV) - { - fShifting = 1.0; - } - else if (fElevation < 3.0) - { - fShifting = 1.0 - ((SOLAR_CIVIL_TWILIGHT_ELEV - fElevation) / (SOLAR_CIVIL_TWILIGHT_ELEV - 3.0)); - } - - nTemperature = m_lTempProfiles[nProfile].nTempHigh - (m_lTempProfiles[nProfile].nTempHigh - m_lTempProfiles[nProfile].nTempLow) * fShifting; - pImpl->bAutoSliderUpdate = TRUE; - } - - if (!bThemeAdaptive) - { - gchar *sThemeKey = g_strdup_printf ("%s-theme", sThemeProfile); - sTheme = g_settings_get_string (pImpl->m_settings, sThemeKey); - g_free (sThemeKey); - - gboolean bLightTheme = g_str_equal (sThemeProfile, "light"); - - if (bLightTheme) - { - sColorScheme = "prefer-light"; - } - else - { - sColorScheme = "prefer-dark"; - } - } - else - { - if (fElevation < SOLAR_CIVIL_TWILIGHT_ELEV) - { - sColorScheme = "prefer-dark"; - sTheme = g_settings_get_string (pImpl->m_settings, "dark-theme"); - } - else - { - sColorScheme = "prefer-light"; - sTheme = g_settings_get_string (pImpl->m_settings, "light-theme"); - } - } - - if (pImpl->fLastBrightness != fBrightness || pImpl->nLasColorTemp != nTemperature) - { - g_debug ("Calling xsct with %u %f", nTemperature, fBrightness); - - GAction *pAction = g_action_map_lookup_action (G_ACTION_MAP (pImpl->m_action_group), "color-temp"); - GVariant *pTemperature = g_variant_new_double (nTemperature); - g_action_change_state (pAction, pTemperature); - - GError *pError = NULL; - gchar *sCommand = g_strdup_printf ("xsct %u %f", nTemperature, fBrightness); - gboolean bSuccess = g_spawn_command_line_sync (sCommand, NULL, NULL, NULL, &pError); - - if (!bSuccess) - { - g_error ("The call to '%s' failed: %s", sCommand, pError->message); - g_error_free (pError); - } - - pImpl->fLastBrightness = fBrightness; - pImpl->nLasColorTemp = nTemperature; - g_free (sCommand); - } - - gboolean bSameColorScheme = g_str_equal (sColorScheme, pImpl->sLastColorScheme); - - if (!bSameColorScheme) - { - g_debug ("Changing color scheme to %s", sColorScheme); - - g_settings_set_string (pImpl->pColorSchemeSettings, "color-scheme", sColorScheme); - pImpl->sLastColorScheme = sColorScheme; - } - - gboolean bSameTheme = FALSE; - - if (pImpl->sLastTheme) - { - bSameTheme = g_str_equal (pImpl->sLastTheme, sTheme); - } - - gboolean bCurrentTheme = g_str_equal ("current", sTheme); - - if (!bSameTheme && !bCurrentTheme) - { - g_debug ("Changing theme to %s", sTheme); - - g_settings_set_string (pImpl->pThemeSettings, "gtk-theme", sTheme); - - if (pImpl->sLastTheme) - { - g_free (pImpl->sLastTheme); - } - - pImpl->sLastTheme = g_strdup (sTheme); - } - - g_free (sTheme); - g_free (sThemeProfile); - - return G_SOURCE_CONTINUE; - } - - static void onGeoClueLoaded (GObject *pObject, GAsyncResult *pResult, gpointer pData) - { - RotationLockIndicator::Impl *pImpl = (RotationLockIndicator::Impl*) pData; - GError *pError = NULL; - GClueSimple *pSimple = gclue_simple_new_finish (pResult, &pError); - - if (pError != NULL) - { - g_warning ("Failed to connect to GeoClue2 service: %s", pError->message); - } - else - { - GClueLocation *pLocation = gclue_simple_get_location (pSimple); - pImpl->fLatitude = gclue_location_get_latitude (pLocation); - pImpl->fLongitude = gclue_location_get_longitude (pLocation); - g_settings_set_double (pImpl->m_settings, "latitude", pImpl->fLatitude); - g_settings_set_double (pImpl->m_settings, "longitude", pImpl->fLongitude); - } - - updateColor (pImpl); - } - - static void onColorTempSettings (GSettings *pSettings, const gchar *sKey, gpointer pData) - { - GVariant *pProfile = g_variant_new_uint16 (0); - g_settings_set_value (pSettings, "color-temp-profile", pProfile); - - updateColor (pData); - } - - static gboolean settingsIntToActionStateString (GValue *pValue, GVariant *pVariant, gpointer pData) - { - guint16 nVariant = g_variant_get_uint16 (pVariant); - gchar *sVariant = g_strdup_printf ("%u", nVariant); - GVariant *pVariantString = g_variant_new_string (sVariant); - g_free (sVariant); - g_value_set_variant (pValue, pVariantString); - - return TRUE; - } - - static GVariant* actionStateStringToSettingsInt (const GValue *pValue, const GVariantType *pVariantType, gpointer pData) - { - GVariant *pVariantString = g_value_get_variant (pValue); - const gchar *sValue = g_variant_get_string (pVariantString, NULL); - guint16 nValue = (guint16) g_ascii_strtoull (sValue, NULL, 10); - GVariant *pVariantInt = g_variant_new_uint16 (nValue); - GValue cValue = G_VALUE_INIT; - g_value_init (&cValue, G_TYPE_VARIANT); - g_value_set_variant (&cValue, pVariantInt); - - return g_value_dup_variant (&cValue); - } - - static void onColorTempState (GSimpleAction *pAction, GVariant *pVariant, gpointer pData) - { - g_simple_action_set_state (pAction, pVariant); - - RotationLockIndicator::Impl *pImpl = (RotationLockIndicator::Impl*) pData; - - if (pImpl->bAutoSliderUpdate) - { - pImpl->bAutoSliderUpdate = FALSE; - - return; - } - - GVariant *pProfile = g_variant_new_uint16 (0); - g_settings_set_value (pImpl->m_settings, "color-temp-profile", pProfile); - - guint16 nTemperature = (guint16) g_variant_get_double (pVariant); - GVariant *pTemperature = g_variant_new_uint16 (nTemperature); - g_settings_set_value (pImpl->m_settings, "color-temp", pTemperature); - } -#endif - - /*** - **** Actions - ***/ - - static gboolean settings_to_action_state(GValue *value, - GVariant *variant, - gpointer /*unused*/) - { - g_value_set_variant(value, variant); - return TRUE; - } - - static GVariant* action_state_to_settings(const GValue *value, - const GVariantType * /*expected_type*/, - gpointer /*unused*/) - { - return g_value_dup_variant(value); - } - - GSimpleActionGroup* create_action_group() - { - GSimpleActionGroup* group; - GSimpleAction* action; - - group = g_simple_action_group_new(); - GVariantType *pVariantType = g_variant_type_new("b"); - action = g_simple_action_new_stateful("rotation-lock", - pVariantType, - g_variant_new_boolean(false)); - g_variant_type_free(pVariantType); - g_settings_bind_with_mapping(m_settings, "rotation-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::rotation-lock", - G_CALLBACK(on_rotation_lock_setting_changed), this); - -#ifdef COLOR_TEMP_ENABLED - if (ayatana_common_utils_is_lomiri() == FALSE) - { - pVariantType = g_variant_type_new ("d"); - action = g_simple_action_new_stateful ("color-temp", pVariantType, g_variant_new_double (0)); - g_variant_type_free (pVariantType); - g_action_map_add_action (G_ACTION_MAP (group), G_ACTION (action)); - g_signal_connect (m_settings, "changed::color-temp", G_CALLBACK (onColorTempSettings), this); - g_signal_connect (action, "change-state", G_CALLBACK (onColorTempState), this); - g_object_unref(G_OBJECT (action)); - - pVariantType = g_variant_type_new ("s"); - action = g_simple_action_new_stateful ("profile", pVariantType, g_variant_new_string ("0")); - g_variant_type_free (pVariantType); - g_settings_bind_with_mapping (this->m_settings, "color-temp-profile", action, "state", G_SETTINGS_BIND_DEFAULT, settingsIntToActionStateString, actionStateStringToSettingsInt, NULL, NULL); - 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::color-temp-profile", G_CALLBACK (updateColor), this); - - pVariantType = g_variant_type_new("d"); - action = g_simple_action_new_stateful ("brightness", pVariantType, g_variant_new_double (0)); - g_variant_type_free(pVariantType); - g_settings_bind_with_mapping (m_settings, "brightness", action, "state", G_SETTINGS_BIND_DEFAULT, settings_to_action_state, action_state_to_settings, NULL, NULL); - 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::brightness", G_CALLBACK (updateColor), this); - - pVariantType = g_variant_type_new ("s"); - action = g_simple_action_new_stateful ("theme", pVariantType, g_variant_new_string ("light")); - g_variant_type_free (pVariantType); - g_settings_bind_with_mapping (this->m_settings, "theme-profile", action, "state", G_SETTINGS_BIND_DEFAULT, settings_to_action_state, action_state_to_settings, NULL, NULL); - 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::theme-profile", G_CALLBACK (updateColor), this); - g_signal_connect_swapped (m_settings, "changed::light-theme", G_CALLBACK (updateColor), this); - g_signal_connect_swapped (m_settings, "changed::dark-theme", G_CALLBACK (updateColor), this); - } -#endif - - action = g_simple_action_new ("settings", NULL); - g_action_map_add_action (G_ACTION_MAP (group), G_ACTION (action)); - g_signal_connect (action, "activate", G_CALLBACK (onSettings), this); - g_object_unref (G_OBJECT (action)); - - return group; - } - - /*** - **** Phone profile - ***/ - - static void on_rotation_lock_setting_changed (gpointer gself) - { - static_cast(gself)->update_phone_header(); - } - - GMenuModel* create_phone_menu() - { - GMenu* menu; - GMenu* section; - GMenuItem* menu_item; - - menu = g_menu_new(); - section = g_menu_new(); - menu_item = g_menu_item_new(_("Rotation Lock"), "indicator.rotation-lock(true)"); - g_menu_item_set_attribute(menu_item, "x-ayatana-type", "s", "org.ayatana.indicator.switch"); - g_menu_append_item(section, menu_item); - g_menu_append_section(menu, NULL, G_MENU_MODEL(section)); - g_object_unref(section); - g_object_unref(menu_item); - - return G_MENU_MODEL(menu); - } - - static void onSettings (GSimpleAction *pAction, GVariant *pVariant, gpointer pData) - { - if (ayatana_common_utils_is_mate ()) - { - ayatana_common_utils_execute_command ("mate-display-properties"); - } - else if (ayatana_common_utils_is_xfce ()) - { - ayatana_common_utils_execute_command ("xfce4-display-settings"); - } - else - { - ayatana_common_utils_execute_command ("gnome-control-center display"); - } - } - - GMenuModel* create_desktop_menu() - { - GMenu* menu; - GMenu* section; - GMenuItem* menu_item; - - menu = g_menu_new(); - - if (ayatana_common_utils_is_lomiri()) - { - section = g_menu_new(); - menu_item = g_menu_item_new(_("Rotation Lock"), "indicator.rotation-lock(true)"); - g_menu_item_set_attribute(menu_item, "x-ayatana-type", "s", "org.ayatana.indicator.switch"); - g_menu_append_item(section, menu_item); - g_menu_append_section(menu, NULL, G_MENU_MODEL(section)); - g_object_unref(section); - g_object_unref(menu_item); - } - else - { -#ifdef COLOR_TEMP_ENABLED - section = g_menu_new (); - - GIcon *pIconMin = g_themed_icon_new_with_default_fallbacks ("ayatana-indicator-display-brightness-low"); - GIcon *pIconMax = g_themed_icon_new_with_default_fallbacks ("ayatana-indicator-display-brightness-high"); - GVariant *pIconMinSerialised = g_icon_serialize (pIconMin); - GVariant *pIconMaxSerialised = g_icon_serialize (pIconMax); - menu_item = g_menu_item_new (_("Brightness"), "indicator.brightness"); - g_menu_item_set_attribute (menu_item, "x-ayatana-type", "s", "org.ayatana.indicator.slider"); - g_menu_item_set_attribute (menu_item, "x-ayatana-type", "s", "org.ayatana.indicator.slider"); - g_menu_item_set_attribute_value (menu_item, "min-icon", pIconMinSerialised); - g_menu_item_set_attribute_value (menu_item, "max-icon", pIconMaxSerialised); - g_menu_item_set_attribute (menu_item, "min-value", "d", 0.5); - g_menu_item_set_attribute (menu_item, "max-value", "d", 1.0); - g_menu_item_set_attribute (menu_item, "step", "d", 0.005); - g_menu_append_item (section, menu_item); - - pIconMin = g_themed_icon_new_with_default_fallbacks ("ayatana-indicator-display-colortemp-on"); - pIconMax = g_themed_icon_new_with_default_fallbacks ("ayatana-indicator-display-colortemp-off"); - pIconMinSerialised = g_icon_serialize (pIconMin); - pIconMaxSerialised = g_icon_serialize (pIconMax); - menu_item = g_menu_item_new (_("Color temperature"), "indicator.color-temp"); - g_menu_item_set_attribute (menu_item, "x-ayatana-type", "s", "org.ayatana.indicator.slider"); - g_menu_item_set_attribute (menu_item, "x-ayatana-type", "s", "org.ayatana.indicator.slider"); - g_menu_item_set_attribute_value (menu_item, "min-icon", pIconMinSerialised); - g_menu_item_set_attribute_value (menu_item, "max-icon", pIconMaxSerialised); - g_menu_item_set_attribute (menu_item, "min-value", "d", 3000.0); - g_menu_item_set_attribute (menu_item, "max-value", "d", 6500.0); - g_menu_item_set_attribute (menu_item, "step", "d", 100.0); - g_menu_append_item (section, menu_item); - - GMenu *pMenuProfiles = g_menu_new (); - GMenuItem *pItemProfiles = g_menu_item_new_submenu (_("Color temperature profile"), G_MENU_MODEL (pMenuProfiles)); - guint nProfile = 0; - - while (m_lTempProfiles[nProfile].sName != NULL) - { - gchar *sAction = g_strdup_printf ("indicator.profile::%u", nProfile); - GMenuItem *pItemProfile = g_menu_item_new (m_lTempProfiles[nProfile].sName, sAction); - g_free(sAction); - g_menu_append_item (pMenuProfiles, pItemProfile); - g_object_unref (pItemProfile); - - nProfile++; - } - - g_menu_append_item (section, pItemProfiles); - g_object_unref (pItemProfiles); - g_object_unref (pMenuProfiles); - - g_menu_append_section (menu, NULL, G_MENU_MODEL (section)); - g_object_unref (pIconMin); - g_object_unref (pIconMax); - g_variant_unref (pIconMinSerialised); - g_variant_unref (pIconMaxSerialised); - g_object_unref (section); - g_object_unref (menu_item); - - section = g_menu_new (); - pMenuProfiles = g_menu_new (); - pItemProfiles = g_menu_item_new_submenu (_("Theme profile"), G_MENU_MODEL (pMenuProfiles)); - GMenuItem *pItemProfile = g_menu_item_new (_("Light"), "indicator.theme::light"); - g_menu_append_item (pMenuProfiles, pItemProfile); - g_object_unref (pItemProfile); - pItemProfile = g_menu_item_new (_("Dark"), "indicator.theme::dark"); - g_menu_append_item (pMenuProfiles, pItemProfile); - g_object_unref (pItemProfile); - pItemProfile = g_menu_item_new (_("Adaptive"), "indicator.theme::adaptive"); - g_menu_append_item (pMenuProfiles, pItemProfile); - g_object_unref (pItemProfile); - g_menu_append_item (section, pItemProfiles); - g_object_unref (pItemProfiles); - g_object_unref (pMenuProfiles); - g_menu_append_section (menu, NULL, G_MENU_MODEL (section)); - g_object_unref (section); -#endif - section = g_menu_new (); - menu_item = g_menu_item_new (_("Display settingsā€¦"), "indicator.settings"); - g_menu_append_item (section, menu_item); - g_menu_append_section (menu, NULL, G_MENU_MODEL (section)); - g_object_unref (section); - g_object_unref (menu_item); - } - - return G_MENU_MODEL(menu); - } - - void update_phone_header() - { - Header h; - h.title = _("Rotation"); - h.tooltip = h.title; - h.a11y = h.title; - h.is_visible = g_settings_get_boolean(m_settings, "rotation-lock"); - h.icon = m_icon; - m_phone->header().set(h); - } - - void update_desktop_header() - { - Header h; - h.title = _("Display"); - h.tooltip = _("Display settings and features"); - h.a11y = h.title; - h.is_visible = TRUE; - h.icon = m_icon; - m_desktop->header().set(h); - } - - /*** - **** - ***/ - - GSettings* m_settings = nullptr; - GSimpleActionGroup* m_action_group = nullptr; - std::shared_ptr m_phone; - std::shared_ptr m_desktop; - std::shared_ptr m_icon; -#ifdef COLOR_TEMP_ENABLED - gdouble fLatitude = 0.0; - gdouble fLongitude = 0.0; - gboolean bAutoSliderUpdate = FALSE; - guint nCallback = 0; - gdouble fLastBrightness = 0.0; - guint nLasColorTemp = 0; - gchar *sLastTheme = NULL; - const gchar *sLastColorScheme = "default"; - GSettings *pThemeSettings = NULL; - GSettings *pColorSchemeSettings = NULL; - gboolean bTest; -#endif -}; - -/*** -**** -***/ - -RotationLockIndicator::RotationLockIndicator(): - impl(new Impl()) -{ -} - -RotationLockIndicator::~RotationLockIndicator() -{ -} - -std::vector> -RotationLockIndicator::profiles() const -{ - return impl->profiles(); -} - -GSimpleActionGroup* -RotationLockIndicator::action_group() const -{ - return impl->action_group(); -} - -const char* -RotationLockIndicator::name() const -{ - return "rotation_lock"; -} - -/*** -**** -***/ - diff --git a/src/rotation-lock.h b/src/rotation-lock.h deleted file mode 100644 index 7bdfb14..0000000 --- a/src/rotation-lock.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2014 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 warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . - * - * Authors: - * Charles Kerr - */ - -#ifndef INDICATOR_DISPLAY_ROTATION_LOCK_H -#define INDICATOR_DISPLAY_ROTATION_LOCK_H - -#include - -#include // std::unique_ptr - -class RotationLockIndicator: public Indicator -{ -public: - RotationLockIndicator(); - ~RotationLockIndicator(); - - const char* name() const override; - GSimpleActionGroup* action_group() const override; - std::vector> profiles() const override; - -protected: - class Impl; - std::unique_ptr impl; -}; - -#endif diff --git a/src/service.cpp b/src/service.cpp new file mode 100644 index 0000000..121bbac --- /dev/null +++ b/src/service.cpp @@ -0,0 +1,757 @@ +/* + * Copyright 2014 Canonical Ltd. + * Copyright 2023 Robert Tari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Authors: + * Charles Kerr + * Robert Tari + */ + +#include +#include + +#ifdef COLOR_TEMP_ENABLED +#include +#endif + +extern "C" +{ + #include + + #ifdef COLOR_TEMP_ENABLED + #include "solar.h" + #endif +} + +#ifdef COLOR_TEMP_ENABLED +typedef struct +{ + guint nTempLow; + guint nTempHigh; + gchar *sName; +} TempProfile; + +TempProfile m_lTempProfiles[] = +{ + {0, 0, _("Manual")}, + {4500, 6500, _("Adaptive (Colder)")}, + {3627, 4913, _("Adaptive")}, + {3058, 4913, _("Adaptive (Warmer)")}, + {0, 0, NULL} +}; +#endif + +class DisplayIndicator::Impl +{ +public: + + Impl() + { + GSettingsSchemaSource *pSource = g_settings_schema_source_get_default(); + const gchar *sTest = g_getenv ("TEST_NAME"); + this->bTest = (sTest != NULL && g_str_equal (sTest, "rotation-lock-test")); + + if (pSource != NULL) + { + if (ayatana_common_utils_is_lomiri()) { + + GSettingsSchema *pSchema = g_settings_schema_source_lookup(pSource, "com.lomiri.touch.system", FALSE); + + if (pSchema != NULL) + { + g_settings_schema_unref(pSchema); + m_settings = g_settings_new("com.lomiri.touch.system"); + } + else + { + g_error("No schema could be found"); + } + + } + else { + + GSettingsSchema *pSchema = g_settings_schema_source_lookup(pSource, "org.ayatana.indicator.display", FALSE); + + if (pSchema != NULL) + { + g_settings_schema_unref(pSchema); + m_settings = g_settings_new("org.ayatana.indicator.display"); + } + else + { + g_error("No schema could be found"); + } + + const gchar *sSchema = NULL; + + if (this->bTest) + { + sSchema = "org.ayatana.indicator.display"; + } + else + { + if (ayatana_common_utils_is_mate ()) + { + sSchema = "org.mate.interface"; + } + else + { + sSchema = "org.gnome.desktop.interface"; + } + } + + pSchema = g_settings_schema_source_lookup (pSource, sSchema, FALSE); + + if (pSchema != NULL) + { + g_settings_schema_unref (pSchema); + pThemeSettings = g_settings_new (sSchema); + } + else + { + g_error("No %s schema could be found", sSchema); + } + + if (this->bTest) + { + sSchema = "org.ayatana.indicator.display"; + } + else + { + sSchema = "org.gnome.desktop.interface"; + } + + pSchema = g_settings_schema_source_lookup (pSource, sSchema, FALSE); + + if (pSchema != NULL) + { + g_settings_schema_unref (pSchema); + pColorSchemeSettings = g_settings_new (sSchema); + } + else + { + g_error("No %s schema could be found", sSchema); + } + } + } + + m_action_group = create_action_group(); + + // build the icon + const char *icon_name {"orientation-lock"}; + + if (!ayatana_common_utils_is_lomiri()) + { + icon_name = "display-panel"; + } + + auto icon = g_themed_icon_new_with_default_fallbacks(icon_name); + 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 phone_menu (create_phone_menu(), menu_model_deleter); + m_phone = std::make_shared("phone", phone_menu); + update_phone_header(); + + // build the desktop profile + std::shared_ptr desktop_menu (create_desktop_menu(), menu_model_deleter); + m_desktop = std::make_shared("desktop", desktop_menu); + update_desktop_header(); + +#ifdef COLOR_TEMP_ENABLED + if (ayatana_common_utils_is_lomiri() == FALSE) + { + if (!this->bTest) + { + this->fLatitude = g_settings_get_double (this->m_settings, "latitude"); + this->fLongitude = g_settings_get_double (this->m_settings, "longitude"); + gclue_simple_new ("ayatana-indicator-display", GCLUE_ACCURACY_LEVEL_CITY, NULL, onGeoClueLoaded, this); + this->nCallback = g_timeout_add_seconds (60, updateColor, this); + updateColor (this); + } + } +#endif + } + + ~Impl() + { + if (nCallback) + { + g_source_remove (nCallback); + } + + g_signal_handlers_disconnect_by_data(m_settings, this); + g_clear_object(&m_action_group); + g_clear_object(&m_settings); + + if (sLastTheme) + { + g_free (sLastTheme); + } + + if (pThemeSettings) + { + g_clear_object (&pThemeSettings); + } + + if (pColorSchemeSettings) + { + g_clear_object (&pColorSchemeSettings); + } + } + + GSimpleActionGroup* action_group() const + { + return m_action_group; + } + + std::vector> profiles() + { + std::vector> ret; + ret.push_back(m_phone); + ret.push_back(m_desktop); + return ret; + } + +private: + +#ifdef COLOR_TEMP_ENABLED + static gboolean updateColor (gpointer pData) + { + DisplayIndicator::Impl *pImpl = (DisplayIndicator::Impl*) pData; + guint nProfile = 0; + g_settings_get (pImpl->m_settings, "color-temp-profile", "q", &nProfile); + gdouble fBrightness = g_settings_get_double (pImpl->m_settings, "brightness"); + gchar *sThemeProfile = g_settings_get_string (pImpl->m_settings, "theme-profile"); + gboolean bThemeAdaptive = g_str_equal (sThemeProfile, "adaptive"); + guint nTemperature = 0; + const gchar *sColorScheme = NULL; + gchar *sTheme = NULL; + gint64 nNow = g_get_real_time (); + gdouble fElevation = solar_elevation((gdouble) nNow / 1000000.0, pImpl->fLatitude, pImpl->fLongitude); + + if (nProfile == 0) + { + g_settings_get (pImpl->m_settings, "color-temp", "q", &nTemperature); + } + else + { + gdouble fShifting = 0.0; + + if (fElevation < SOLAR_CIVIL_TWILIGHT_ELEV) + { + fShifting = 1.0; + } + else if (fElevation < 3.0) + { + fShifting = 1.0 - ((SOLAR_CIVIL_TWILIGHT_ELEV - fElevation) / (SOLAR_CIVIL_TWILIGHT_ELEV - 3.0)); + } + + nTemperature = m_lTempProfiles[nProfile].nTempHigh - (m_lTempProfiles[nProfile].nTempHigh - m_lTempProfiles[nProfile].nTempLow) * fShifting; + pImpl->bAutoSliderUpdate = TRUE; + } + + if (!bThemeAdaptive) + { + gchar *sThemeKey = g_strdup_printf ("%s-theme", sThemeProfile); + sTheme = g_settings_get_string (pImpl->m_settings, sThemeKey); + g_free (sThemeKey); + + gboolean bLightTheme = g_str_equal (sThemeProfile, "light"); + + if (bLightTheme) + { + sColorScheme = "prefer-light"; + } + else + { + sColorScheme = "prefer-dark"; + } + } + else + { + if (fElevation < SOLAR_CIVIL_TWILIGHT_ELEV) + { + sColorScheme = "prefer-dark"; + sTheme = g_settings_get_string (pImpl->m_settings, "dark-theme"); + } + else + { + sColorScheme = "prefer-light"; + sTheme = g_settings_get_string (pImpl->m_settings, "light-theme"); + } + } + + if (pImpl->fLastBrightness != fBrightness || pImpl->nLasColorTemp != nTemperature) + { + g_debug ("Calling xsct with %u %f", nTemperature, fBrightness); + + GAction *pAction = g_action_map_lookup_action (G_ACTION_MAP (pImpl->m_action_group), "color-temp"); + GVariant *pTemperature = g_variant_new_double (nTemperature); + g_action_change_state (pAction, pTemperature); + + GError *pError = NULL; + gchar *sCommand = g_strdup_printf ("xsct %u %f", nTemperature, fBrightness); + gboolean bSuccess = g_spawn_command_line_sync (sCommand, NULL, NULL, NULL, &pError); + + if (!bSuccess) + { + g_error ("The call to '%s' failed: %s", sCommand, pError->message); + g_error_free (pError); + } + + pImpl->fLastBrightness = fBrightness; + pImpl->nLasColorTemp = nTemperature; + g_free (sCommand); + } + + gboolean bSameColorScheme = g_str_equal (sColorScheme, pImpl->sLastColorScheme); + + if (!bSameColorScheme) + { + g_debug ("Changing color scheme to %s", sColorScheme); + + g_settings_set_string (pImpl->pColorSchemeSettings, "color-scheme", sColorScheme); + pImpl->sLastColorScheme = sColorScheme; + } + + gboolean bSameTheme = FALSE; + + if (pImpl->sLastTheme) + { + bSameTheme = g_str_equal (pImpl->sLastTheme, sTheme); + } + + gboolean bCurrentTheme = g_str_equal ("current", sTheme); + + if (!bSameTheme && !bCurrentTheme) + { + g_debug ("Changing theme to %s", sTheme); + + g_settings_set_string (pImpl->pThemeSettings, "gtk-theme", sTheme); + + if (pImpl->sLastTheme) + { + g_free (pImpl->sLastTheme); + } + + pImpl->sLastTheme = g_strdup (sTheme); + } + + g_free (sTheme); + g_free (sThemeProfile); + + return G_SOURCE_CONTINUE; + } + + static void onGeoClueLoaded (GObject *pObject, GAsyncResult *pResult, gpointer pData) + { + DisplayIndicator::Impl *pImpl = (DisplayIndicator::Impl*) pData; + GError *pError = NULL; + GClueSimple *pSimple = gclue_simple_new_finish (pResult, &pError); + + if (pError != NULL) + { + g_warning ("Failed to connect to GeoClue2 service: %s", pError->message); + } + else + { + GClueLocation *pLocation = gclue_simple_get_location (pSimple); + pImpl->fLatitude = gclue_location_get_latitude (pLocation); + pImpl->fLongitude = gclue_location_get_longitude (pLocation); + g_settings_set_double (pImpl->m_settings, "latitude", pImpl->fLatitude); + g_settings_set_double (pImpl->m_settings, "longitude", pImpl->fLongitude); + } + + updateColor (pImpl); + } + + static void onColorTempSettings (GSettings *pSettings, const gchar *sKey, gpointer pData) + { + GVariant *pProfile = g_variant_new_uint16 (0); + g_settings_set_value (pSettings, "color-temp-profile", pProfile); + + updateColor (pData); + } + + static gboolean settingsIntToActionStateString (GValue *pValue, GVariant *pVariant, gpointer pData) + { + guint16 nVariant = g_variant_get_uint16 (pVariant); + gchar *sVariant = g_strdup_printf ("%u", nVariant); + GVariant *pVariantString = g_variant_new_string (sVariant); + g_free (sVariant); + g_value_set_variant (pValue, pVariantString); + + return TRUE; + } + + static GVariant* actionStateStringToSettingsInt (const GValue *pValue, const GVariantType *pVariantType, gpointer pData) + { + GVariant *pVariantString = g_value_get_variant (pValue); + const gchar *sValue = g_variant_get_string (pVariantString, NULL); + guint16 nValue = (guint16) g_ascii_strtoull (sValue, NULL, 10); + GVariant *pVariantInt = g_variant_new_uint16 (nValue); + GValue cValue = G_VALUE_INIT; + g_value_init (&cValue, G_TYPE_VARIANT); + g_value_set_variant (&cValue, pVariantInt); + + return g_value_dup_variant (&cValue); + } + + static void onColorTempState (GSimpleAction *pAction, GVariant *pVariant, gpointer pData) + { + g_simple_action_set_state (pAction, pVariant); + + DisplayIndicator::Impl *pImpl = (DisplayIndicator::Impl*) pData; + + if (pImpl->bAutoSliderUpdate) + { + pImpl->bAutoSliderUpdate = FALSE; + + return; + } + + GVariant *pProfile = g_variant_new_uint16 (0); + g_settings_set_value (pImpl->m_settings, "color-temp-profile", pProfile); + + guint16 nTemperature = (guint16) g_variant_get_double (pVariant); + GVariant *pTemperature = g_variant_new_uint16 (nTemperature); + g_settings_set_value (pImpl->m_settings, "color-temp", pTemperature); + } +#endif + + /*** + **** Actions + ***/ + + static gboolean settings_to_action_state(GValue *value, + GVariant *variant, + gpointer /*unused*/) + { + g_value_set_variant(value, variant); + return TRUE; + } + + static GVariant* action_state_to_settings(const GValue *value, + const GVariantType * /*expected_type*/, + gpointer /*unused*/) + { + return g_value_dup_variant(value); + } + + GSimpleActionGroup* create_action_group() + { + GSimpleActionGroup* group; + GSimpleAction* action; + + group = g_simple_action_group_new(); + GVariantType *pVariantType = g_variant_type_new("b"); + action = g_simple_action_new_stateful("rotation-lock", + pVariantType, + g_variant_new_boolean(false)); + g_variant_type_free(pVariantType); + g_settings_bind_with_mapping(m_settings, "rotation-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::rotation-lock", + G_CALLBACK(on_rotation_lock_setting_changed), this); + +#ifdef COLOR_TEMP_ENABLED + if (ayatana_common_utils_is_lomiri() == FALSE) + { + pVariantType = g_variant_type_new ("d"); + action = g_simple_action_new_stateful ("color-temp", pVariantType, g_variant_new_double (0)); + g_variant_type_free (pVariantType); + g_action_map_add_action (G_ACTION_MAP (group), G_ACTION (action)); + g_signal_connect (m_settings, "changed::color-temp", G_CALLBACK (onColorTempSettings), this); + g_signal_connect (action, "change-state", G_CALLBACK (onColorTempState), this); + g_object_unref(G_OBJECT (action)); + + pVariantType = g_variant_type_new ("s"); + action = g_simple_action_new_stateful ("profile", pVariantType, g_variant_new_string ("0")); + g_variant_type_free (pVariantType); + g_settings_bind_with_mapping (this->m_settings, "color-temp-profile", action, "state", G_SETTINGS_BIND_DEFAULT, settingsIntToActionStateString, actionStateStringToSettingsInt, NULL, NULL); + 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::color-temp-profile", G_CALLBACK (updateColor), this); + + pVariantType = g_variant_type_new("d"); + action = g_simple_action_new_stateful ("brightness", pVariantType, g_variant_new_double (0)); + g_variant_type_free(pVariantType); + g_settings_bind_with_mapping (m_settings, "brightness", action, "state", G_SETTINGS_BIND_DEFAULT, settings_to_action_state, action_state_to_settings, NULL, NULL); + 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::brightness", G_CALLBACK (updateColor), this); + + pVariantType = g_variant_type_new ("s"); + action = g_simple_action_new_stateful ("theme", pVariantType, g_variant_new_string ("light")); + g_variant_type_free (pVariantType); + g_settings_bind_with_mapping (this->m_settings, "theme-profile", action, "state", G_SETTINGS_BIND_DEFAULT, settings_to_action_state, action_state_to_settings, NULL, NULL); + 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::theme-profile", G_CALLBACK (updateColor), this); + g_signal_connect_swapped (m_settings, "changed::light-theme", G_CALLBACK (updateColor), this); + g_signal_connect_swapped (m_settings, "changed::dark-theme", G_CALLBACK (updateColor), this); + } +#endif + + action = g_simple_action_new ("settings", NULL); + g_action_map_add_action (G_ACTION_MAP (group), G_ACTION (action)); + g_signal_connect (action, "activate", G_CALLBACK (onSettings), this); + g_object_unref (G_OBJECT (action)); + + return group; + } + + /*** + **** Phone profile + ***/ + + static void on_rotation_lock_setting_changed (gpointer gself) + { + static_cast(gself)->update_phone_header(); + } + + GMenuModel* create_phone_menu() + { + GMenu* menu; + GMenu* section; + GMenuItem* menu_item; + + menu = g_menu_new(); + section = g_menu_new(); + menu_item = g_menu_item_new(_("Rotation Lock"), "indicator.rotation-lock(true)"); + g_menu_item_set_attribute(menu_item, "x-ayatana-type", "s", "org.ayatana.indicator.switch"); + g_menu_append_item(section, menu_item); + g_menu_append_section(menu, NULL, G_MENU_MODEL(section)); + g_object_unref(section); + g_object_unref(menu_item); + + return G_MENU_MODEL(menu); + } + + static void onSettings (GSimpleAction *pAction, GVariant *pVariant, gpointer pData) + { + if (ayatana_common_utils_is_mate ()) + { + ayatana_common_utils_execute_command ("mate-display-properties"); + } + else if (ayatana_common_utils_is_xfce ()) + { + ayatana_common_utils_execute_command ("xfce4-display-settings"); + } + else + { + ayatana_common_utils_execute_command ("gnome-control-center display"); + } + } + + GMenuModel* create_desktop_menu() + { + GMenu* menu; + GMenu* section; + GMenuItem* menu_item; + + menu = g_menu_new(); + + if (ayatana_common_utils_is_lomiri()) + { + section = g_menu_new(); + menu_item = g_menu_item_new(_("Rotation Lock"), "indicator.rotation-lock(true)"); + g_menu_item_set_attribute(menu_item, "x-ayatana-type", "s", "org.ayatana.indicator.switch"); + g_menu_append_item(section, menu_item); + g_menu_append_section(menu, NULL, G_MENU_MODEL(section)); + g_object_unref(section); + g_object_unref(menu_item); + } + else + { +#ifdef COLOR_TEMP_ENABLED + section = g_menu_new (); + + GIcon *pIconMin = g_themed_icon_new_with_default_fallbacks ("ayatana-indicator-display-brightness-low"); + GIcon *pIconMax = g_themed_icon_new_with_default_fallbacks ("ayatana-indicator-display-brightness-high"); + GVariant *pIconMinSerialised = g_icon_serialize (pIconMin); + GVariant *pIconMaxSerialised = g_icon_serialize (pIconMax); + menu_item = g_menu_item_new (_("Brightness"), "indicator.brightness"); + g_menu_item_set_attribute (menu_item, "x-ayatana-type", "s", "org.ayatana.indicator.slider"); + g_menu_item_set_attribute (menu_item, "x-ayatana-type", "s", "org.ayatana.indicator.slider"); + g_menu_item_set_attribute_value (menu_item, "min-icon", pIconMinSerialised); + g_menu_item_set_attribute_value (menu_item, "max-icon", pIconMaxSerialised); + g_menu_item_set_attribute (menu_item, "min-value", "d", 0.5); + g_menu_item_set_attribute (menu_item, "max-value", "d", 1.0); + g_menu_item_set_attribute (menu_item, "step", "d", 0.005); + g_menu_append_item (section, menu_item); + + pIconMin = g_themed_icon_new_with_default_fallbacks ("ayatana-indicator-display-colortemp-on"); + pIconMax = g_themed_icon_new_with_default_fallbacks ("ayatana-indicator-display-colortemp-off"); + pIconMinSerialised = g_icon_serialize (pIconMin); + pIconMaxSerialised = g_icon_serialize (pIconMax); + menu_item = g_menu_item_new (_("Color temperature"), "indicator.color-temp"); + g_menu_item_set_attribute (menu_item, "x-ayatana-type", "s", "org.ayatana.indicator.slider"); + g_menu_item_set_attribute (menu_item, "x-ayatana-type", "s", "org.ayatana.indicator.slider"); + g_menu_item_set_attribute_value (menu_item, "min-icon", pIconMinSerialised); + g_menu_item_set_attribute_value (menu_item, "max-icon", pIconMaxSerialised); + g_menu_item_set_attribute (menu_item, "min-value", "d", 3000.0); + g_menu_item_set_attribute (menu_item, "max-value", "d", 6500.0); + g_menu_item_set_attribute (menu_item, "step", "d", 100.0); + g_menu_append_item (section, menu_item); + + GMenu *pMenuProfiles = g_menu_new (); + GMenuItem *pItemProfiles = g_menu_item_new_submenu (_("Color temperature profile"), G_MENU_MODEL (pMenuProfiles)); + guint nProfile = 0; + + while (m_lTempProfiles[nProfile].sName != NULL) + { + gchar *sAction = g_strdup_printf ("indicator.profile::%u", nProfile); + GMenuItem *pItemProfile = g_menu_item_new (m_lTempProfiles[nProfile].sName, sAction); + g_free(sAction); + g_menu_append_item (pMenuProfiles, pItemProfile); + g_object_unref (pItemProfile); + + nProfile++; + } + + g_menu_append_item (section, pItemProfiles); + g_object_unref (pItemProfiles); + g_object_unref (pMenuProfiles); + + g_menu_append_section (menu, NULL, G_MENU_MODEL (section)); + g_object_unref (pIconMin); + g_object_unref (pIconMax); + g_variant_unref (pIconMinSerialised); + g_variant_unref (pIconMaxSerialised); + g_object_unref (section); + g_object_unref (menu_item); + + section = g_menu_new (); + pMenuProfiles = g_menu_new (); + pItemProfiles = g_menu_item_new_submenu (_("Theme profile"), G_MENU_MODEL (pMenuProfiles)); + GMenuItem *pItemProfile = g_menu_item_new (_("Light"), "indicator.theme::light"); + g_menu_append_item (pMenuProfiles, pItemProfile); + g_object_unref (pItemProfile); + pItemProfile = g_menu_item_new (_("Dark"), "indicator.theme::dark"); + g_menu_append_item (pMenuProfiles, pItemProfile); + g_object_unref (pItemProfile); + pItemProfile = g_menu_item_new (_("Adaptive"), "indicator.theme::adaptive"); + g_menu_append_item (pMenuProfiles, pItemProfile); + g_object_unref (pItemProfile); + g_menu_append_item (section, pItemProfiles); + g_object_unref (pItemProfiles); + g_object_unref (pMenuProfiles); + g_menu_append_section (menu, NULL, G_MENU_MODEL (section)); + g_object_unref (section); +#endif + section = g_menu_new (); + menu_item = g_menu_item_new (_("Display settingsā€¦"), "indicator.settings"); + g_menu_append_item (section, menu_item); + g_menu_append_section (menu, NULL, G_MENU_MODEL (section)); + g_object_unref (section); + g_object_unref (menu_item); + } + + return G_MENU_MODEL(menu); + } + + void update_phone_header() + { + Header h; + h.title = _("Rotation"); + h.tooltip = h.title; + h.a11y = h.title; + h.is_visible = g_settings_get_boolean(m_settings, "rotation-lock"); + h.icon = m_icon; + m_phone->header().set(h); + } + + void update_desktop_header() + { + Header h; + h.title = _("Display"); + h.tooltip = _("Display settings and features"); + h.a11y = h.title; + h.is_visible = TRUE; + h.icon = m_icon; + m_desktop->header().set(h); + } + + /*** + **** + ***/ + + GSettings* m_settings = nullptr; + GSimpleActionGroup* m_action_group = nullptr; + std::shared_ptr m_phone; + std::shared_ptr m_desktop; + std::shared_ptr m_icon; +#ifdef COLOR_TEMP_ENABLED + gdouble fLatitude = 0.0; + gdouble fLongitude = 0.0; + gboolean bAutoSliderUpdate = FALSE; + guint nCallback = 0; + gdouble fLastBrightness = 0.0; + guint nLasColorTemp = 0; + gchar *sLastTheme = NULL; + const gchar *sLastColorScheme = "default"; + GSettings *pThemeSettings = NULL; + GSettings *pColorSchemeSettings = NULL; + gboolean bTest; +#endif +}; + +/*** +**** +***/ + +DisplayIndicator::DisplayIndicator(): + impl(new Impl()) +{ +} + +DisplayIndicator::~DisplayIndicator() +{ +} + +std::vector> +DisplayIndicator::profiles() const +{ + return impl->profiles(); +} + +GSimpleActionGroup* +DisplayIndicator::action_group() const +{ + return impl->action_group(); +} + +const char* +DisplayIndicator::name() const +{ + return "display"; +} + +/*** +**** +***/ + diff --git a/src/service.h b/src/service.h new file mode 100644 index 0000000..da8d8ba --- /dev/null +++ b/src/service.h @@ -0,0 +1,44 @@ +/* + * Copyright 2014 Canonical Ltd. + * Copyright 2023 Robert Tari + * + * 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 warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . + * + * Authors: + * Charles Kerr + * Robert Tari + */ + +#ifndef INDICATOR_DISPLAY_SERVICE_H +#define INDICATOR_DISPLAY_SERVICE_H + +#include + +#include // std::unique_ptr + +class DisplayIndicator: public Indicator +{ +public: + DisplayIndicator(); + ~DisplayIndicator(); + + const char* name() const override; + GSimpleActionGroup* action_group() const override; + std::vector> profiles() const override; + +protected: + class Impl; + std::unique_ptr impl; +}; + +#endif diff --git a/tests/unit/rotation-lock-test.cpp b/tests/unit/rotation-lock-test.cpp index a4ce388..7bf2e45 100644 --- a/tests/unit/rotation-lock-test.cpp +++ b/tests/unit/rotation-lock-test.cpp @@ -19,7 +19,7 @@ #include -#include +#include class RotationLockFixture: public TestDBusFixture { @@ -45,9 +45,9 @@ protected: TEST_F(RotationLockFixture, CheckIndicator) { - RotationLockIndicator indicator; + DisplayIndicator indicator; - ASSERT_STREQ("rotation_lock", indicator.name()); + ASSERT_STREQ("display", indicator.name()); auto actions = indicator.action_group(); ASSERT_TRUE(actions != nullptr); ASSERT_TRUE(g_action_group_has_action(G_ACTION_GROUP(actions), "rotation-lock")); -- cgit v1.2.3 From f8ee1db7c062b321d9ea742500a7e0fb2e023d18 Mon Sep 17 00:00:00 2001 From: Robert Tari Date: Mon, 9 Oct 2023 20:01:52 +0200 Subject: tests/CMakeLists.txt: Suppress useless override buggy cppcheck warning --- tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6b25955..5bd645f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -28,7 +28,7 @@ endif() add_compile_options(${CXX_WARNING_ARGS}) -add_test(cppcheck cppcheck --enable=all -USCHEMA_DIR --error-exitcode=2 --inline-suppr --library=qt -I${CMAKE_SOURCE_DIR} -i${CMAKE_SOURCE_DIR}/tests/utils/qmain.cpp -i${CMAKE_SOURCE_DIR}/tests/gmock ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/tests --suppress=missingIncludeSystem --suppress=uninitDerivedMemberVar --suppress=unmatchedSuppression --suppress=constParameter --suppress=unusedFunction) +add_test(cppcheck cppcheck --enable=all -USCHEMA_DIR --error-exitcode=2 --inline-suppr --library=qt -I${CMAKE_SOURCE_DIR} -i${CMAKE_SOURCE_DIR}/tests/utils/qmain.cpp -i${CMAKE_SOURCE_DIR}/tests/gmock ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/tests --suppress=missingIncludeSystem --suppress=uninitDerivedMemberVar --suppress=unmatchedSuppression --suppress=constParameter --suppress=unusedFunction --suppress=uselessOverride) if (ENABLE_LOMIRI_FEATURES) add_subdirectory (integration) -- cgit v1.2.3 From bb479fd0def20ceee01b6f65b69de24bf18028fe Mon Sep 17 00:00:00 2001 From: Robert Tari Date: Mon, 9 Oct 2023 20:06:34 +0200 Subject: src/indicator.h: Fix multiple definitions of header property --- src/indicator.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/indicator.h b/src/indicator.h index 7379b32..c9ccb1e 100644 --- a/src/indicator.h +++ b/src/indicator.h @@ -1,5 +1,6 @@ /* * Copyright 2014-2016 Canonical Ltd. + * Copyright 2023 Robert Tari * * 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 @@ -15,6 +16,7 @@ * * Authors: * Charles Kerr + * Robert Tari */ #pragma once @@ -50,7 +52,7 @@ class Profile { public: virtual std::string name() const =0; - virtual const core::Property
& header() const =0; + virtual core::Property
& header() =0; virtual std::shared_ptr menu_model() const =0; virtual ~Profile(); @@ -66,8 +68,7 @@ public: virtual ~SimpleProfile(); std::string name() const override {return m_name;} - core::Property
& header() {return m_header;} - const core::Property
& header() const override {return m_header;} + core::Property
& header() override {return m_header;} std::shared_ptr menu_model() const override {return m_menu;} protected: @@ -86,4 +87,3 @@ public: virtual GSimpleActionGroup* action_group() const =0; virtual std::vector> profiles() const =0; }; - -- cgit v1.2.3 From 15d318fe93fb8419b1f03052f62c8feceb45356b Mon Sep 17 00:00:00 2001 From: Robert Tari Date: Mon, 9 Oct 2023 20:30:20 +0200 Subject: Update documentation --- INSTALL.md | 1 + README.md | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index 89e1b81..8a11f7a 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -9,6 +9,7 @@ - glib-2.0 (>= 2.36) - gudev-1.0 - properties-cpp + - libgeoclue-2.0 - gtest (>= 1.6.0) - **For testing** - qt5-base5 - **For testing** - libqtdbusmock1 - **For testing** diff --git a/README.md b/README.md index c41e33b..18099db 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,8 @@ https://ayatana-indicators.org ## The Display Ayatana System Indicator The -display Ayatana System Indicator is the display menu indicator for -Lomiri (Currently rotation-lock only, but we are planning to add further -functionality for desktops, e.g. MATE, XFCE, LXDE). Its behavior and features will be listed at +MATE and Lomiri (optionally for others, e.g. XFCE, LXDE). Its behavior +and features will be listed at https://wiki.ayatana-indicators.org/AyatanaIndicatorDisplay ## License and Copyright -- cgit v1.2.3