/* * Copyright (C) 2018 Purism SPC * * SPDX-License-Identifier: GPL-3.0-or-later * * Author: Guido Günther * * Once based on maynard's panel which is * Copyright (C) 2014 Collabora Ltd. * * Author: Jonny Lamb */ #define G_LOG_DOMAIN "phosh-shell" #define WWAN_BACKEND_KEY "wwan-backend" #include #include #include #include #include #include #include #include "config.h" #include "shell.h" #include "batteryinfo.h" #include "background-manager.h" #include "bt-manager.h" #include "fader.h" #include "feedback-manager.h" #include "home.h" #include "idle-manager.h" #include "keyboard-events.h" #include "lockscreen-manager.h" #include "monitor-manager.h" #include "monitor/monitor.h" #include "notifications/notify-manager.h" #include "notifications/notification-banner.h" #include "osk-manager.h" #include "panel.h" #include "phosh-wayland.h" #include "polkit-auth-agent.h" #include "proximity.h" #include "sensor-proxy-manager.h" #include "screen-saver-manager.h" #include "session.h" #include "system-prompter.h" #include "torch-manager.h" #include "util.h" #include "wifiinfo.h" #include "wwaninfo.h" #include "wwan/phosh-wwan-ofono.h" #include "wwan/phosh-wwan-mm.h" #include "wwan/phosh-wwan-backend.h" /** * SECTION:shell * @short_description: The shell singleton * @Title: PhoshShell * * #PhoshShell is responsible for instantiating the GUI * parts of the shell#PhoshPanel, #PhoshHome,… and the managers that * interface with DBus #PhoshMonitorManager, #PhoshFeedbackManager, … * and coordinates between them. */ enum { PHOSH_SHELL_PROP_0, PHOSH_SHELL_PROP_TRANSFORM, PHOSH_SHELL_PROP_LOCKED, PHOSH_SHELL_PROP_PRIMARY_MONITOR, PHOSH_SHELL_PROP_LAST_PROP }; static GParamSpec *props[PHOSH_SHELL_PROP_LAST_PROP]; typedef struct { PhoshLayerSurface *panel; PhoshLayerSurface *home; GPtrArray *faders; /* for final fade out */ GtkWidget *notification_banner; PhoshBackgroundManager *background_manager; PhoshMonitor *primary_monitor; PhoshMonitor *builtin_monitor; PhoshMonitorManager *monitor_manager; PhoshLockscreenManager *lockscreen_manager; PhoshIdleManager *idle_manager; PhoshOskManager *osk_manager; PhoshToplevelManager *toplevel_manager; PhoshWifiManager *wifi_manager; PhoshPolkitAuthAgent *polkit_auth_agent; PhoshScreenSaverManager *screen_saver_manager; PhoshNotifyManager *notify_manager; PhoshFeedbackManager *feedback_manager; PhoshBtManager *bt_manager; PhoshWWan *wwan; PhoshTorchManager *torch_manager; PhoshKeyboardEvents *keyboard_events; /* sensors */ PhoshSensorProxyManager *sensor_proxy_manager; PhoshProximity *proximity; gboolean startup_finished; PhoshMonitorTransform transform; /* current rotation of primary monitor */ } PhoshShellPrivate; typedef struct _PhoshShell { GObject parent; } PhoshShell; G_DEFINE_TYPE_WITH_PRIVATE (PhoshShell, phosh_shell, G_TYPE_OBJECT) static void settings_activated_cb (PhoshShell *self, PhoshPanel *window) { PhoshShellPrivate *priv = phosh_shell_get_instance_private (self); g_return_if_fail (PHOSH_IS_PANEL (priv->panel)); phosh_panel_toggle_fold (PHOSH_PANEL(priv->panel)); } void phosh_shell_lock (PhoshShell *self) { phosh_shell_set_locked (self, TRUE); } void phosh_shell_unlock (PhoshShell *self) { phosh_shell_set_locked (self, FALSE); } /** * phosh_shell_get_locked: * @self: The #PhoshShell singleton * * Returns: %TRUE if the shell is currently locked, otherwise %FALSE. */ gboolean phosh_shell_get_locked (PhoshShell *self) { PhoshShellPrivate *priv = phosh_shell_get_instance_private (self); return phosh_lockscreen_manager_get_locked (priv->lockscreen_manager); } /** * phosh_shell_set_locked: * @self: The #PhoshShell singleton * @locked: %TRUE to lock the shell * * Lock the shell. We proxy to lockscreen-manager to avoid * that other parts of the shell need to care about this * abstraction. */ void phosh_shell_set_locked (PhoshShell *self, gboolean locked) { PhoshShellPrivate *priv = phosh_shell_get_instance_private (self); gboolean current; current = phosh_lockscreen_manager_get_locked (priv->lockscreen_manager); if (current == locked) return; phosh_lockscreen_manager_set_locked (priv->lockscreen_manager, locked); g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_SHELL_PROP_LOCKED]); } static void on_home_state_changed (PhoshShell *self, GParamSpec *pspec, PhoshHome *home) { PhoshShellPrivate *priv; PhoshHomeState state; g_return_if_fail (PHOSH_IS_SHELL (self)); g_return_if_fail (PHOSH_IS_HOME (home)); priv = phosh_shell_get_instance_private (self); g_object_get (priv->home, "state", &state, NULL); if (state == PHOSH_HOME_STATE_UNFOLDED) { phosh_panel_fold (PHOSH_PANEL (priv->panel)); phosh_osk_manager_set_visible (priv->osk_manager, FALSE); } } static void panels_create (PhoshShell *self) { PhoshShellPrivate *priv = phosh_shell_get_instance_private (self); PhoshMonitor *monitor; PhoshWayland *wl = phosh_wayland_get_default (); monitor = phosh_shell_get_primary_monitor (self); g_return_if_fail (monitor); priv->panel = PHOSH_LAYER_SURFACE(phosh_panel_new (phosh_wayland_get_zwlr_layer_shell_v1(wl), monitor->wl_output)); gtk_widget_show (GTK_WIDGET (priv->panel)); priv->home = PHOSH_LAYER_SURFACE(phosh_home_new (phosh_wayland_get_zwlr_layer_shell_v1(wl), monitor->wl_output)); gtk_widget_show (GTK_WIDGET (priv->home)); g_signal_connect_swapped ( priv->panel, "settings-activated", G_CALLBACK(settings_activated_cb), self); g_signal_connect_swapped ( priv->home, "notify::state", G_CALLBACK(on_home_state_changed), self); } static void panels_dispose (PhoshShell *self) { PhoshShellPrivate *priv = phosh_shell_get_instance_private (self); g_clear_pointer (&priv->panel, phosh_cp_widget_destroy); g_clear_pointer (&priv->home, phosh_cp_widget_destroy); } static void css_setup (PhoshShell *self) { GtkCssProvider *provider; GFile *file; GError *error = NULL; provider = gtk_css_provider_new (); file = g_file_new_for_uri ("resource:///sm/puri/phosh/style.css"); if (!gtk_css_provider_load_from_file (provider, file, &error)) { g_warning ("Failed to load CSS file: %s", error->message); g_clear_error (&error); g_object_unref (file); return; } gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), GTK_STYLE_PROVIDER (provider), 600); g_object_unref (file); } static void phosh_shell_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { PhoshShell *self = PHOSH_SHELL (object); switch (property_id) { case PHOSH_SHELL_PROP_LOCKED: phosh_shell_set_locked (self, g_value_get_boolean (value)); break; case PHOSH_SHELL_PROP_PRIMARY_MONITOR: phosh_shell_set_primary_monitor (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void phosh_shell_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { PhoshShell *self = PHOSH_SHELL (object); PhoshShellPrivate *priv = phosh_shell_get_instance_private(self); switch (property_id) { case PHOSH_SHELL_PROP_TRANSFORM: g_value_set_enum (value, phosh_monitor_get_transform(priv->primary_monitor)); break; case PHOSH_SHELL_PROP_LOCKED: g_value_set_boolean (value, phosh_lockscreen_manager_get_locked (priv->lockscreen_manager)); break; case PHOSH_SHELL_PROP_PRIMARY_MONITOR: g_value_set_object (value, phosh_shell_get_primary_monitor (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void phosh_shell_dispose (GObject *object) { PhoshShell *self = PHOSH_SHELL (object); PhoshShellPrivate *priv = phosh_shell_get_instance_private(self); if (priv->sensor_proxy_manager) { phosh_dbus_sensor_proxy_call_release_accelerometer_sync ( PHOSH_DBUS_SENSOR_PROXY(priv->sensor_proxy_manager), NULL, NULL); g_clear_object (&priv->sensor_proxy_manager); } panels_dispose (self); g_clear_pointer (&priv->faders, g_ptr_array_unref); g_clear_object (&priv->notification_banner); g_clear_object (&priv->keyboard_events); /* dispose managers in opposite order of declaration */ g_clear_object (&priv->torch_manager); g_clear_object (&priv->wwan); g_clear_object (&priv->bt_manager); g_clear_object (&priv->feedback_manager); g_clear_object (&priv->notify_manager); g_clear_object (&priv->screen_saver_manager); g_clear_object (&priv->polkit_auth_agent); g_clear_object (&priv->wifi_manager); g_clear_object (&priv->toplevel_manager); g_clear_object (&priv->osk_manager); g_clear_object (&priv->idle_manager); g_clear_object (&priv->lockscreen_manager); g_clear_object (&priv->monitor_manager); g_clear_object (&priv->builtin_monitor); g_clear_object (&priv->primary_monitor); g_clear_object (&priv->background_manager); /* sensors */ g_clear_object (&priv->proximity); g_clear_object (&priv->sensor_proxy_manager); phosh_system_prompter_unregister (); phosh_session_unregister (); G_OBJECT_CLASS (phosh_shell_parent_class)->dispose (object); } static void on_num_toplevels_changed (PhoshShell *self, GParamSpec *pspec, PhoshToplevelManager *toplevel_manager) { PhoshShellPrivate *priv; g_return_if_fail (PHOSH_IS_SHELL (self)); g_return_if_fail (PHOSH_IS_TOPLEVEL_MANAGER (toplevel_manager)); priv = phosh_shell_get_instance_private (self); /* all toplevels gone, show the overview */ /* TODO: once we have unfoldable app-drawer unfold that too */ if (!phosh_toplevel_manager_get_num_toplevels (toplevel_manager)) phosh_home_set_state (PHOSH_HOME (priv->home), PHOSH_HOME_STATE_UNFOLDED); } static void on_toplevel_added (PhoshShell *self, GParamSpec *pspec, PhoshToplevelManager *toplevel_manager) { PhoshShellPrivate *priv; g_return_if_fail (PHOSH_IS_SHELL (self)); g_return_if_fail (PHOSH_IS_TOPLEVEL_MANAGER (toplevel_manager)); priv = phosh_shell_get_instance_private (self); phosh_home_set_state (PHOSH_HOME (priv->home), PHOSH_HOME_STATE_FOLDED); } static void on_new_notification (PhoshShell *self, PhoshNotification *notification, PhoshNotifyManager *manager) { PhoshShellPrivate *priv; g_return_if_fail (PHOSH_IS_SHELL (self)); g_return_if_fail (PHOSH_IS_NOTIFICATION (notification)); g_return_if_fail (PHOSH_IS_NOTIFY_MANAGER (manager)); priv = phosh_shell_get_instance_private (self); /* Clear existing banner */ if (priv->notification_banner && GTK_IS_WIDGET (priv->notification_banner)) { gtk_widget_destroy (priv->notification_banner); } if (phosh_notify_manager_get_show_banners (manager) && !phosh_lockscreen_manager_get_locked (priv->lockscreen_manager) && phosh_panel_get_state (PHOSH_PANEL (priv->panel)) == PHOSH_PANEL_STATE_FOLDED) { g_set_weak_pointer (&priv->notification_banner, phosh_notification_banner_new (notification)); gtk_widget_show (GTK_WIDGET (priv->notification_banner)); } } static gboolean on_fade_out_timeout (PhoshShell *self) { PhoshShellPrivate *priv; g_return_val_if_fail (PHOSH_IS_SHELL (self), G_SOURCE_REMOVE); priv = phosh_shell_get_instance_private (self); /* kill all faders if we time out */ priv->faders = g_ptr_array_remove_range (priv->faders, 0, priv->faders->len); return G_SOURCE_REMOVE; } static gboolean setup_idle_cb (PhoshShell *self) { PhoshShellPrivate *priv = phosh_shell_get_instance_private (self); panels_create (self); /* Create background after panel since it needs the panel's size */ priv->background_manager = phosh_background_manager_new (); g_signal_connect_object (priv->toplevel_manager, "notify::num-toplevels", G_CALLBACK(on_num_toplevels_changed), self, G_CONNECT_SWAPPED); on_num_toplevels_changed (self, NULL, priv->toplevel_manager); g_signal_connect_object (priv->toplevel_manager, "toplevel-added", G_CALLBACK(on_toplevel_added), self, G_CONNECT_SWAPPED); /* Screen saver manager needs lock screen manager */ priv->screen_saver_manager = phosh_screen_saver_manager_get_default ( priv->lockscreen_manager); priv->notify_manager = phosh_notify_manager_get_default (); g_signal_connect_object (priv->notify_manager, "new-notification", G_CALLBACK (on_new_notification), self, G_CONNECT_SWAPPED); priv->sensor_proxy_manager = phosh_sensor_proxy_manager_get_default_failable (); if (priv->sensor_proxy_manager) { priv->proximity = phosh_proximity_new (priv->sensor_proxy_manager, priv->lockscreen_manager); /* TODO: accelerometer */ } phosh_session_register (PHOSH_APP_ID); /* If we start rotated, fix this up */ if (phosh_shell_get_transform (self) != PHOSH_MONITOR_TRANSFORM_NORMAL) phosh_shell_set_transform (self, PHOSH_MONITOR_TRANSFORM_NORMAL); priv->startup_finished = TRUE; return FALSE; } /* Load all types that might be used in UI files */ static void type_setup (void) { phosh_battery_info_get_type(); phosh_wifi_info_get_type(); phosh_wwan_info_get_type(); } static void on_builtin_monitor_power_mode_changed (PhoshShell *self, GParamSpec *pspec, PhoshMonitor *monitor) { PhoshMonitorPowerSaveMode mode; g_return_if_fail (PHOSH_IS_SHELL (self)); g_return_if_fail (PHOSH_IS_MONITOR (monitor)); g_object_get (monitor, "power-mode", &mode, NULL); if (mode == PHOSH_MONITOR_POWER_SAVE_MODE_OFF) phosh_shell_lock (self); } static void on_primary_monitor_configured (PhoshShell *self, PhoshMonitor *monitor) { PhoshShellPrivate *priv; PhoshMonitorTransform transform; g_return_if_fail (PHOSH_IS_SHELL (self)); g_return_if_fail (PHOSH_IS_MONITOR (monitor)); priv = phosh_shell_get_instance_private (self); transform = phosh_monitor_get_transform (monitor); if (transform == priv->transform) return; priv->transform = transform; g_debug ("Primary monitor transform %d", transform); g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_SHELL_PROP_TRANSFORM]); } static void on_monitor_removed (PhoshShell *self, PhoshMonitor *monitor) { PhoshShellPrivate *priv; g_return_if_fail (PHOSH_IS_SHELL (self)); g_return_if_fail (PHOSH_IS_MONITOR (monitor)); priv = phosh_shell_get_instance_private (self); if (priv->primary_monitor != monitor) return; g_debug ("Primary monitor removed %p", monitor); /* Prefer built in monitor when primary is gone... */ if (priv->builtin_monitor && monitor != priv->builtin_monitor) { phosh_shell_set_primary_monitor (self, priv->builtin_monitor); return; } /* ...just pick the first one available otherwise */ for (int i = 0; i < phosh_monitor_manager_get_num_monitors (priv->monitor_manager); i++) { PhoshMonitor *new_primary = phosh_monitor_manager_get_monitor (priv->monitor_manager, i); if (new_primary != monitor) { phosh_shell_set_primary_monitor (self, new_primary); break; } } g_assert (priv->primary_monitor && priv->primary_monitor != monitor); } static void phosh_shell_constructed (GObject *object) { PhoshShell *self = PHOSH_SHELL (object); PhoshShellPrivate *priv = phosh_shell_get_instance_private (self); G_OBJECT_CLASS (phosh_shell_parent_class)->constructed (object); /* We bind this early since a wl_display_roundtrip () would make us miss exising toplevels */ priv->toplevel_manager = phosh_toplevel_manager_new (); priv->transform = -1; /* force initial update */ priv->monitor_manager = phosh_monitor_manager_new (); g_signal_connect_swapped (priv->monitor_manager, "monitor-removed", G_CALLBACK (on_monitor_removed), self); if (phosh_monitor_manager_get_num_monitors(priv->monitor_manager)) { PhoshMonitor *monitor = phosh_monitor_manager_get_monitor (priv->monitor_manager, 0); /* Can't invoke phosh_shell_set_primary_monitor () since the shell object does not really exist yet but we need the primary monitor early for the panels */ priv->primary_monitor = g_object_ref (monitor); g_signal_connect_swapped (priv->primary_monitor, "configured", G_CALLBACK (on_primary_monitor_configured), self); } if (phosh_monitor_is_builtin(priv->primary_monitor)) priv->builtin_monitor = priv->primary_monitor; else priv->builtin_monitor = phosh_shell_get_builtin_monitor(self); gtk_icon_theme_add_resource_path (gtk_icon_theme_get_default (), "/sm/puri/phosh/icons"); css_setup (self); type_setup (); priv->lockscreen_manager = phosh_lockscreen_manager_new (); priv->idle_manager = phosh_idle_manager_get_default(); priv->faders = g_ptr_array_new_with_free_func ((GDestroyNotify) (gtk_widget_destroy)); phosh_system_prompter_register (); priv->polkit_auth_agent = phosh_polkit_auth_agent_new (); priv->feedback_manager = phosh_feedback_manager_new (); if (priv->builtin_monitor) { g_signal_connect_swapped ( priv->builtin_monitor, "notify::power-mode", G_CALLBACK(on_builtin_monitor_power_mode_changed), self); } priv->keyboard_events = phosh_keyboard_events_new (); g_idle_add ((GSourceFunc) setup_idle_cb, self); } static void phosh_shell_class_init (PhoshShellClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructed = phosh_shell_constructed; object_class->dispose = phosh_shell_dispose; object_class->set_property = phosh_shell_set_property; object_class->get_property = phosh_shell_get_property; props[PHOSH_SHELL_PROP_TRANSFORM] = g_param_spec_enum ("transform", "Transform", "Monitor transform of the primary monitor", PHOSH_TYPE_MONITOR_TRANSFORM, PHOSH_MONITOR_TRANSFORM_NORMAL, G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY); props[PHOSH_SHELL_PROP_LOCKED] = g_param_spec_boolean ("locked", "Locked", "Whether the screen is locked", FALSE, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); props[PHOSH_SHELL_PROP_PRIMARY_MONITOR] = g_param_spec_object ("primary-monitor", "Primary monitor", "The primary monitor", PHOSH_TYPE_MONITOR, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, PHOSH_SHELL_PROP_LAST_PROP, props); } static void phosh_shell_init (PhoshShell *self) { GtkSettings *gtk_settings; gtk_settings = gtk_settings_get_default (); g_object_set (G_OBJECT (gtk_settings), "gtk-application-prefer-dark-theme", TRUE, NULL); } PhoshMonitorTransform phosh_shell_get_transform (PhoshShell *self) { PhoshShellPrivate *priv; g_return_val_if_fail (PHOSH_IS_SHELL (self), PHOSH_MONITOR_TRANSFORM_NORMAL); priv = phosh_shell_get_instance_private (self); g_return_val_if_fail (priv->primary_monitor, PHOSH_MONITOR_TRANSFORM_NORMAL); return phosh_monitor_get_transform (priv->primary_monitor); } void phosh_shell_set_transform (PhoshShell *self, PhoshMonitorTransform transform) { PhoshShellPrivate *priv = phosh_shell_get_instance_private (self); PhoshMonitorTransform current; g_return_if_fail (priv->primary_monitor); current = phosh_monitor_get_transform (priv->primary_monitor); if (current == transform) return; phosh_monitor_manager_set_monitor_transform (priv->monitor_manager, priv->primary_monitor, transform); phosh_monitor_manager_apply_monitor_config (priv->monitor_manager); /* Notification change signalled in on_primary_monitor_configured */ } void phosh_shell_set_primary_monitor (PhoshShell *self, PhoshMonitor *monitor) { PhoshShellPrivate *priv; PhoshMonitor *m = NULL; PhoshMonitorTransform transform; g_return_if_fail (monitor); g_return_if_fail (PHOSH_IS_SHELL (self)); priv = phosh_shell_get_instance_private (self); if (monitor == priv->primary_monitor) return; for (int i = 0; i < phosh_monitor_manager_get_num_monitors (priv->monitor_manager); i++) { m = phosh_monitor_manager_get_monitor (priv->monitor_manager, i); if (monitor == m) break; } g_return_if_fail (monitor == m); if (priv->primary_monitor) g_signal_handlers_disconnect_by_data (priv->primary_monitor, self); g_clear_object (&priv->primary_monitor); priv->primary_monitor = g_object_ref (monitor); g_debug ("New primary monitor is %s", monitor->name); g_signal_connect_swapped (priv->primary_monitor, "configured", G_CALLBACK (on_primary_monitor_configured), self); /* Catch up if old and new primary monitor's rotation are different */ transform = phosh_monitor_get_transform (priv->primary_monitor); if (transform != priv->transform) on_primary_monitor_configured (self, priv->primary_monitor); /* Move panels to the new monitor by recreating the layer shell surfaces */ panels_dispose (self); panels_create (self); g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_SHELL_PROP_PRIMARY_MONITOR]); } PhoshMonitor * phosh_shell_get_builtin_monitor (PhoshShell *self) { PhoshShellPrivate *priv; PhoshMonitor *monitor = NULL; g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); priv = phosh_shell_get_instance_private (self); if (priv->builtin_monitor) return priv->builtin_monitor; for (int i = 0; i < phosh_monitor_manager_get_num_monitors (priv->monitor_manager); i++) { monitor = phosh_monitor_manager_get_monitor (priv->monitor_manager, i); if (phosh_monitor_is_builtin (monitor)) break; } if (!monitor) monitor = phosh_monitor_manager_get_monitor (priv->monitor_manager, 0); g_return_val_if_fail (monitor, NULL); return monitor; } PhoshMonitor * phosh_shell_get_primary_monitor (PhoshShell *self) { PhoshShellPrivate *priv; PhoshMonitor *monitor; g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); priv = phosh_shell_get_instance_private (self); if (priv->primary_monitor) return priv->primary_monitor; /* When the shell started up we might not have had all monitors */ monitor = phosh_monitor_manager_get_monitor (priv->monitor_manager, 0); g_return_val_if_fail (monitor, NULL); return monitor; } PhoshLockscreenManager * phosh_shell_get_lockscreen_manager (PhoshShell *self) { PhoshShellPrivate *priv; g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); priv = phosh_shell_get_instance_private (self); g_return_val_if_fail (PHOSH_IS_LOCKSCREEN_MANAGER (priv->lockscreen_manager), NULL); return priv->lockscreen_manager; } PhoshMonitorManager * phosh_shell_get_monitor_manager (PhoshShell *self) { PhoshShellPrivate *priv; g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); priv = phosh_shell_get_instance_private (self); g_return_val_if_fail (PHOSH_IS_MONITOR_MANAGER (priv->monitor_manager), NULL); return priv->monitor_manager; } PhoshWifiManager * phosh_shell_get_wifi_manager (PhoshShell *self) { PhoshShellPrivate *priv; g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); priv = phosh_shell_get_instance_private (self); if (!priv->wifi_manager) priv->wifi_manager = phosh_wifi_manager_new (); g_return_val_if_fail (PHOSH_IS_WIFI_MANAGER (priv->wifi_manager), NULL); return priv->wifi_manager; } PhoshBtManager * phosh_shell_get_bt_manager (PhoshShell *self) { PhoshShellPrivate *priv; g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); priv = phosh_shell_get_instance_private (self); if (!priv->bt_manager) priv->bt_manager = phosh_bt_manager_new (); g_return_val_if_fail (PHOSH_IS_BT_MANAGER (priv->bt_manager), NULL); return priv->bt_manager; } PhoshOskManager * phosh_shell_get_osk_manager (PhoshShell *self) { PhoshShellPrivate *priv; g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); priv = phosh_shell_get_instance_private (self); if (!priv->osk_manager) priv->osk_manager = phosh_osk_manager_new (); g_return_val_if_fail (PHOSH_IS_OSK_MANAGER (priv->osk_manager), NULL); return priv->osk_manager; } PhoshToplevelManager * phosh_shell_get_toplevel_manager (PhoshShell *self) { PhoshShellPrivate *priv; g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); priv = phosh_shell_get_instance_private (self); g_return_val_if_fail (PHOSH_IS_TOPLEVEL_MANAGER (priv->toplevel_manager), NULL); return priv->toplevel_manager; } PhoshFeedbackManager * phosh_shell_get_feedback_manager (PhoshShell *self) { PhoshShellPrivate *priv; g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); priv = phosh_shell_get_instance_private (self); g_return_val_if_fail (PHOSH_IS_FEEDBACK_MANAGER (priv->feedback_manager), NULL); return priv->feedback_manager; } PhoshWWan * phosh_shell_get_wwan (PhoshShell *self) { PhoshShellPrivate *priv; g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); priv = phosh_shell_get_instance_private (self); if (!priv->wwan) { g_autoptr (GSettings) settings = g_settings_new ("sm.puri.phosh"); PhoshWWanBackend backend = g_settings_get_enum (settings, WWAN_BACKEND_KEY); switch (backend) { default: case PHOSH_WWAN_BACKEND_MM: priv->wwan = PHOSH_WWAN (phosh_wwan_mm_new()); break; case PHOSH_WWAN_BACKEND_OFONO: priv->wwan = PHOSH_WWAN (phosh_wwan_ofono_new()); break; } } g_return_val_if_fail (PHOSH_IS_WWAN (priv->wwan), NULL); return priv->wwan; } PhoshTorchManager * phosh_shell_get_torch_manager (PhoshShell *self) { PhoshShellPrivate *priv; g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); priv = phosh_shell_get_instance_private (self); if (!priv->torch_manager) priv->torch_manager = phosh_torch_manager_new (); g_return_val_if_fail (PHOSH_IS_TORCH_MANAGER (priv->torch_manager), NULL); return priv->torch_manager; } /** * Returns the usable area in pixels usable by a client on the phone * display */ void phosh_shell_get_usable_area (PhoshShell *self, int *x, int *y, int *width, int *height) { PhoshMonitor *monitor; PhoshMonitorMode *mode; int w, h; int scale; g_return_if_fail (PHOSH_IS_SHELL (self)); monitor = phosh_shell_get_primary_monitor (self); g_return_if_fail(monitor); mode = phosh_monitor_get_current_mode (monitor); g_return_if_fail (mode != NULL); scale = monitor->scale ? monitor->scale : 1; g_debug ("Primary monitor %p scale is %d, transform is %d", monitor, monitor->scale, monitor->transform); switch (phosh_monitor_get_transform(monitor)) { case PHOSH_MONITOR_TRANSFORM_NORMAL: case PHOSH_MONITOR_TRANSFORM_180: case PHOSH_MONITOR_TRANSFORM_FLIPPED: case PHOSH_MONITOR_TRANSFORM_FLIPPED_180: w = mode->width / scale; h = mode->height / scale - PHOSH_PANEL_HEIGHT - PHOSH_HOME_BUTTON_HEIGHT; break; default: w = mode->height / scale; h = mode->width / scale - PHOSH_PANEL_HEIGHT - PHOSH_HOME_BUTTON_HEIGHT; break; } if (x) *x = 0; if (y) *y = PHOSH_PANEL_HEIGHT; if (width) *width = w; if (height) *height = h; } PhoshShell * phosh_shell_get_default (void) { static PhoshShell *instance; if (instance == NULL) { g_debug("Creating shell"); instance = g_object_new (PHOSH_TYPE_SHELL, NULL); g_object_add_weak_pointer (G_OBJECT (instance), (gpointer *)&instance); } return instance; } void phosh_shell_fade_out (PhoshShell *self, guint timeout) { PhoshShellPrivate *priv; PhoshWayland *wl = phosh_wayland_get_default (); PhoshMonitorManager *monitor_manager; g_debug ("Fading out..."); g_return_if_fail (PHOSH_IS_SHELL (self)); monitor_manager = phosh_shell_get_monitor_manager (self); g_return_if_fail (PHOSH_IS_MONITOR_MANAGER (monitor_manager)); priv = phosh_shell_get_instance_private (self); for (int i = 0; i < phosh_monitor_manager_get_num_monitors (monitor_manager); i++) { PhoshFader *fader; PhoshMonitor *monitor = phosh_monitor_manager_get_monitor (monitor_manager, i); fader = phosh_fader_new (phosh_wayland_get_zwlr_layer_shell_v1 (wl), monitor->wl_output); g_ptr_array_add (priv->faders, fader); gtk_widget_show (GTK_WIDGET (fader)); if (timeout > 0) g_timeout_add_seconds (timeout, (GSourceFunc) on_fade_out_timeout, self); } } /** * phosh_shell_set_power_save: * @self: The shell * @enable: Wether power save mode should be enabled * * Enter power saving mode. This currently blanks all monitors. */ void phosh_shell_enable_power_save (PhoshShell *self, gboolean enable) { g_debug ("Entering power save mode"); g_return_if_fail (PHOSH_IS_SHELL (self)); /* * Locking the outputs instructs g-s-d to tell us to put * outputs into power save mode via org.gnome.Mutter.DisplayConfig */ phosh_shell_set_locked(self, enable); /* TODO: other means of power saving */ } /** * phosh_shell_started_by_display_manager: * @self: The shell * * Returns: %TRUE if we were started from a display manager. %FALSE otherwise. */ gboolean phosh_shell_started_by_display_manager(PhoshShell *self) { g_return_val_if_fail (PHOSH_IS_SHELL (self), FALSE); if (!g_strcmp0 (g_getenv ("GDMSESSION"), "phosh")) return TRUE; return FALSE; } /** * phosh_shell_is_startup_finished: * @self: The shell * * Returns: %TRUE if the shell finished startup. %FALSE otherwise. */ gboolean phosh_shell_is_startup_finished(PhoshShell *self) { PhoshShellPrivate *priv; g_return_val_if_fail (PHOSH_IS_SHELL (self), FALSE); priv = phosh_shell_get_instance_private (self); return priv->startup_finished; } void phosh_shell_add_global_keyboard_action_entries (PhoshShell *self, const GActionEntry *entries, gint n_entries, gpointer user_data) { PhoshShellPrivate *priv; g_return_if_fail (PHOSH_IS_SHELL (self)); priv = phosh_shell_get_instance_private (self); g_return_if_fail (priv->keyboard_events); g_action_map_add_action_entries (G_ACTION_MAP (priv->keyboard_events), entries, n_entries, user_data); } void phosh_shell_remove_global_keyboard_action_entries (PhoshShell *self, const GActionEntry *entries, gint n_entries) { PhoshShellPrivate *priv; g_return_if_fail (PHOSH_IS_SHELL (self)); priv = phosh_shell_get_instance_private (self); g_return_if_fail (priv->keyboard_events); for (int i = 0; i < n_entries; i++) { g_action_map_remove_action (G_ACTION_MAP (priv->keyboard_events), entries[i].name); } }