We should only enforce single mode, when we have exactly two monitors and the two button UI is used to switch between them in single mode. Move the code to ensure the single configuration into the relevant callback handler, rather than trying to solve this globally.
1242 lines
40 KiB
C
1242 lines
40 KiB
C
/*
|
|
* Copyright (C) 2007, 2008 Red Hat, Inc.
|
|
* Copyright (C) 2013 Intel, Inc.
|
|
*
|
|
* 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; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
*/
|
|
|
|
#include "cc-display-panel.h"
|
|
|
|
#include <gtk/gtk.h>
|
|
#include <glib/gi18n.h>
|
|
#include <stdlib.h>
|
|
#include <gdesktop-enums.h>
|
|
#include <math.h>
|
|
|
|
#define HANDY_USE_UNSTABLE_API 1
|
|
#include <handy.h>
|
|
|
|
#include "shell/cc-object-storage.h"
|
|
#include "list-box-helper.h"
|
|
#include <libupower-glib/upower.h>
|
|
|
|
#include "cc-display-config-manager-dbus.h"
|
|
#include "cc-display-config.h"
|
|
#include "cc-display-arrangement.h"
|
|
#include "cc-night-light-dialog.h"
|
|
#include "cc-display-resources.h"
|
|
#include "cc-display-settings.h"
|
|
|
|
/* The minimum supported size for the panel */
|
|
#define MINIMUM_WIDTH 740
|
|
#define MINIMUM_HEIGHT 530
|
|
|
|
#define PANEL_PADDING 32
|
|
#define SECTION_PADDING 32
|
|
#define HEADING_PADDING 12
|
|
|
|
typedef enum {
|
|
/*< flags >*/
|
|
CC_DISPLAY_CONFIG_SINGLE = 0x1,
|
|
CC_DISPLAY_CONFIG_JOIN = 0x2,
|
|
CC_DISPLAY_CONFIG_CLONE = 0x4,
|
|
} CcDisplayConfigType;
|
|
|
|
struct _CcDisplayPanel
|
|
{
|
|
CcPanel parent_instance;
|
|
|
|
CcDisplayConfigManager *manager;
|
|
CcDisplayConfig *current_config;
|
|
CcDisplayMonitor *current_output;
|
|
|
|
gint rebuilding_counter;
|
|
|
|
CcDisplayArrangement *arrangement;
|
|
CcDisplaySettings *settings;
|
|
|
|
guint focus_id;
|
|
|
|
CcNightLightDialog *night_light_dialog;
|
|
GSettings *settings_color;
|
|
|
|
UpClient *up_client;
|
|
gboolean lid_is_closed;
|
|
|
|
GDBusProxy *shell_proxy;
|
|
GCancellable *shell_cancellable;
|
|
|
|
guint sensor_watch_id;
|
|
GDBusProxy *iio_sensor_proxy;
|
|
gboolean has_accelerometer;
|
|
|
|
gchar *main_title;
|
|
GtkWidget *main_titlebar;
|
|
GtkWidget *apply_titlebar;
|
|
GtkWidget *apply_titlebar_apply;
|
|
GtkWidget *apply_titlebar_warning;
|
|
|
|
GListStore *primary_display_list;
|
|
GtkListStore *output_selection_list;
|
|
|
|
GtkWidget *arrangement_frame;
|
|
GtkAlignment *arrangement_bin;
|
|
GtkRadioButton *config_type_join;
|
|
GtkRadioButton *config_type_mirror;
|
|
GtkRadioButton *config_type_single;
|
|
GtkWidget *config_type_switcher_frame;
|
|
GtkLabel *current_output_label;
|
|
GtkWidget *display_settings_frame;
|
|
GtkLabel *night_light_status_label;
|
|
GtkSwitch *output_enabled_switch;
|
|
GtkComboBox *output_selection_combo;
|
|
GtkStack *output_selection_stack;
|
|
GtkButtonBox *output_selection_two_first;
|
|
GtkButtonBox *output_selection_two_second;
|
|
HdyComboRow *primary_display_row;
|
|
};
|
|
|
|
CC_PANEL_REGISTER (CcDisplayPanel, cc_display_panel)
|
|
|
|
static void
|
|
update_apply_button (CcDisplayPanel *panel);
|
|
static void
|
|
apply_current_configuration (CcDisplayPanel *self);
|
|
static void
|
|
reset_current_config (CcDisplayPanel *panel);
|
|
static void
|
|
rebuild_ui (CcDisplayPanel *panel);
|
|
static void
|
|
set_current_output (CcDisplayPanel *panel,
|
|
CcDisplayMonitor *output,
|
|
gboolean force);
|
|
|
|
|
|
static CcDisplayConfigType
|
|
config_find_types (CcDisplayPanel *panel)
|
|
{
|
|
CcDisplayConfigType types = 0;
|
|
guint n_outputs, n_active_outputs;
|
|
GList *outputs, *l;
|
|
|
|
outputs = cc_display_config_get_ui_sorted_monitors (panel->current_config);
|
|
n_outputs = g_list_length (outputs);
|
|
n_active_outputs = 0;
|
|
for (l = outputs; l; l = l->next)
|
|
{
|
|
CcDisplayMonitor *output = l->data;
|
|
|
|
if (cc_display_monitor_is_useful (output))
|
|
n_active_outputs += 1;
|
|
}
|
|
|
|
if (n_outputs > (panel->lid_is_closed ? 2 : 1))
|
|
{
|
|
if (cc_display_config_is_cloning (panel->current_config))
|
|
types |= CC_DISPLAY_CONFIG_CLONE;
|
|
else
|
|
{
|
|
types |= CC_DISPLAY_CONFIG_JOIN;
|
|
|
|
if (n_active_outputs == 1)
|
|
types |= CC_DISPLAY_CONFIG_SINGLE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
types |= CC_DISPLAY_CONFIG_SINGLE;
|
|
}
|
|
|
|
return types;
|
|
}
|
|
|
|
static CcDisplayConfigType
|
|
config_select_type (CcDisplayPanel *panel)
|
|
{
|
|
CcDisplayConfigType types = config_find_types (panel);
|
|
|
|
if (types & CC_DISPLAY_CONFIG_CLONE)
|
|
return CC_DISPLAY_CONFIG_CLONE;
|
|
if (types & CC_DISPLAY_CONFIG_SINGLE)
|
|
return CC_DISPLAY_CONFIG_SINGLE;
|
|
|
|
return CC_DISPLAY_CONFIG_JOIN;
|
|
}
|
|
|
|
static CcDisplayConfigType
|
|
cc_panel_get_selected_type (CcDisplayPanel *panel)
|
|
{
|
|
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (panel->config_type_join)))
|
|
return CC_DISPLAY_CONFIG_JOIN;
|
|
else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (panel->config_type_mirror)))
|
|
return CC_DISPLAY_CONFIG_CLONE;
|
|
else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (panel->config_type_single)))
|
|
return CC_DISPLAY_CONFIG_SINGLE;
|
|
else
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
static void
|
|
cc_panel_set_selected_type (CcDisplayPanel *panel, CcDisplayConfigType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case CC_DISPLAY_CONFIG_JOIN:
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (panel->config_type_join), TRUE);
|
|
break;
|
|
case CC_DISPLAY_CONFIG_CLONE:
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (panel->config_type_mirror), TRUE);
|
|
break;
|
|
case CC_DISPLAY_CONFIG_SINGLE:
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (panel->config_type_single), TRUE);
|
|
break;
|
|
default:
|
|
g_assert_not_reached ();
|
|
}
|
|
}
|
|
|
|
static void
|
|
config_ensure_of_type (CcDisplayPanel *panel, CcDisplayConfigType type)
|
|
{
|
|
CcDisplayConfigType types = config_find_types (panel);
|
|
GList *outputs, *l;
|
|
|
|
if (type == CC_DISPLAY_CONFIG_SINGLE && (types & CC_DISPLAY_CONFIG_SINGLE))
|
|
return;
|
|
|
|
/* Already compatible and not just "single" mode. */
|
|
if (!(types & CC_DISPLAY_CONFIG_SINGLE) && (types & type))
|
|
return;
|
|
|
|
reset_current_config (panel);
|
|
|
|
outputs = cc_display_config_get_ui_sorted_monitors (panel->current_config);
|
|
|
|
switch (type)
|
|
{
|
|
case CC_DISPLAY_CONFIG_SINGLE:
|
|
g_debug ("Creating new single config");
|
|
/* Disable all but the current primary output */
|
|
cc_display_config_set_cloning (panel->current_config, FALSE);
|
|
for (l = outputs; l; l = l->next)
|
|
{
|
|
CcDisplayMonitor *output = l->data;
|
|
|
|
/* Select the current primary output as the active one */
|
|
if (cc_display_monitor_is_primary (output))
|
|
{
|
|
cc_display_monitor_set_active (output, TRUE);
|
|
cc_display_monitor_set_mode (output, cc_display_monitor_get_preferred_mode (output));
|
|
set_current_output (panel, output, FALSE);
|
|
}
|
|
else
|
|
{
|
|
cc_display_monitor_set_active (output, FALSE);
|
|
cc_display_monitor_set_mode (output, cc_display_monitor_get_preferred_mode (output));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CC_DISPLAY_CONFIG_JOIN:
|
|
g_debug ("Creating new join config");
|
|
/* Enable all usable outputs
|
|
* Note that this might result in invalid configurations as we
|
|
* we might not be able to drive all attached monitors. */
|
|
cc_display_config_set_cloning (panel->current_config, FALSE);
|
|
for (l = outputs; l; l = l->next)
|
|
{
|
|
CcDisplayMonitor *output = l->data;
|
|
|
|
cc_display_monitor_set_active (output, cc_display_monitor_is_usable (output));
|
|
cc_display_monitor_set_mode (output, cc_display_monitor_get_preferred_mode (output));
|
|
}
|
|
break;
|
|
|
|
case CC_DISPLAY_CONFIG_CLONE:
|
|
{
|
|
g_debug ("Creating new clone config");
|
|
GList *modes = cc_display_config_get_cloning_modes (panel->current_config);
|
|
gint bw, bh;
|
|
CcDisplayMode *best = NULL;
|
|
|
|
/* Turn on cloning and select the best mode we can find by default */
|
|
cc_display_config_set_cloning (panel->current_config, TRUE);
|
|
|
|
while (modes)
|
|
{
|
|
CcDisplayMode *mode = modes->data;
|
|
gint w, h;
|
|
|
|
cc_display_mode_get_resolution (mode, &w, &h);
|
|
if (best == NULL || (bw*bh < w*h))
|
|
{
|
|
best = mode;
|
|
cc_display_mode_get_resolution (best, &bw, &bh);
|
|
}
|
|
|
|
modes = modes->next;
|
|
}
|
|
cc_display_config_set_mode_on_all_outputs (panel->current_config, best);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
rebuild_ui (panel);
|
|
}
|
|
|
|
static void
|
|
monitor_labeler_hide (CcDisplayPanel *self)
|
|
{
|
|
if (!self->shell_proxy)
|
|
return;
|
|
|
|
g_dbus_proxy_call (self->shell_proxy,
|
|
"HideMonitorLabels",
|
|
NULL, G_DBUS_CALL_FLAGS_NONE,
|
|
-1, NULL, NULL, NULL);
|
|
}
|
|
|
|
static void
|
|
monitor_labeler_show (CcDisplayPanel *self)
|
|
{
|
|
GList *outputs, *l;
|
|
GVariantBuilder builder;
|
|
gint number = 0;
|
|
|
|
if (!self->shell_proxy || !self->current_config)
|
|
return;
|
|
|
|
outputs = cc_display_config_get_ui_sorted_monitors (self->current_config);
|
|
if (!outputs)
|
|
return;
|
|
|
|
if (cc_display_config_is_cloning (self->current_config))
|
|
return monitor_labeler_hide (self);
|
|
|
|
g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
|
|
g_variant_builder_open (&builder, G_VARIANT_TYPE_ARRAY);
|
|
|
|
for (l = outputs; l != NULL; l = l->next)
|
|
{
|
|
CcDisplayMonitor *output = l->data;
|
|
|
|
number = cc_display_monitor_get_ui_number (output);
|
|
if (number == 0)
|
|
continue;
|
|
|
|
g_variant_builder_add (&builder, "{sv}",
|
|
cc_display_monitor_get_connector_name (output),
|
|
g_variant_new_int32 (number));
|
|
}
|
|
|
|
g_variant_builder_close (&builder);
|
|
|
|
if (number < 2)
|
|
return monitor_labeler_hide (self);
|
|
|
|
g_dbus_proxy_call (self->shell_proxy,
|
|
"ShowMonitorLabels2",
|
|
g_variant_builder_end (&builder),
|
|
G_DBUS_CALL_FLAGS_NONE,
|
|
-1, NULL, NULL, NULL);
|
|
}
|
|
|
|
static void
|
|
ensure_monitor_labels (CcDisplayPanel *self)
|
|
{
|
|
g_autoptr(GList) windows;
|
|
GList *w;
|
|
|
|
windows = gtk_window_list_toplevels ();
|
|
|
|
for (w = windows; w; w = w->next)
|
|
{
|
|
if (gtk_window_has_toplevel_focus (GTK_WINDOW (w->data)))
|
|
{
|
|
monitor_labeler_show (self);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!w)
|
|
monitor_labeler_hide (self);
|
|
}
|
|
|
|
static void
|
|
dialog_toplevel_focus_changed (CcDisplayPanel *self)
|
|
{
|
|
ensure_monitor_labels (self);
|
|
}
|
|
|
|
static void
|
|
reset_titlebar (CcDisplayPanel *self)
|
|
{
|
|
GtkWidget *toplevel = cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (self)));
|
|
|
|
if (self->main_titlebar)
|
|
{
|
|
gtk_window_set_titlebar (GTK_WINDOW (toplevel), self->main_titlebar);
|
|
g_clear_object (&self->main_titlebar);
|
|
|
|
/* The split header bar will not reset the window title, so do that here. */
|
|
gtk_window_set_title (GTK_WINDOW (toplevel), self->main_title);
|
|
g_clear_pointer (&self->main_title, g_free);
|
|
}
|
|
|
|
g_clear_object (&self->apply_titlebar);
|
|
g_clear_object (&self->apply_titlebar_apply);
|
|
g_clear_object (&self->apply_titlebar_warning);
|
|
}
|
|
|
|
static void
|
|
active_panel_changed (CcShell *shell,
|
|
GParamSpec *pspec,
|
|
CcPanel *self)
|
|
{
|
|
g_autoptr(CcPanel) panel = NULL;
|
|
|
|
g_object_get (shell, "active-panel", &panel, NULL);
|
|
if (panel != self)
|
|
reset_titlebar (CC_DISPLAY_PANEL (self));
|
|
}
|
|
|
|
static void
|
|
cc_display_panel_dispose (GObject *object)
|
|
{
|
|
CcDisplayPanel *self = CC_DISPLAY_PANEL (object);
|
|
CcShell *shell;
|
|
GtkWidget *toplevel;
|
|
|
|
reset_titlebar (CC_DISPLAY_PANEL (object));
|
|
|
|
if (self->sensor_watch_id > 0)
|
|
{
|
|
g_bus_unwatch_name (self->sensor_watch_id);
|
|
self->sensor_watch_id = 0;
|
|
}
|
|
|
|
g_clear_object (&self->iio_sensor_proxy);
|
|
|
|
if (self->focus_id)
|
|
{
|
|
shell = cc_panel_get_shell (CC_PANEL (object));
|
|
toplevel = cc_shell_get_toplevel (shell);
|
|
if (toplevel != NULL)
|
|
g_signal_handler_disconnect (G_OBJECT (toplevel),
|
|
self->focus_id);
|
|
self->focus_id = 0;
|
|
monitor_labeler_hide (CC_DISPLAY_PANEL (object));
|
|
}
|
|
|
|
g_clear_object (&self->manager);
|
|
g_clear_object (&self->current_config);
|
|
g_clear_object (&self->up_client);
|
|
g_clear_object (&self->settings_color);
|
|
|
|
g_cancellable_cancel (self->shell_cancellable);
|
|
g_clear_object (&self->shell_cancellable);
|
|
g_clear_object (&self->shell_proxy);
|
|
|
|
g_clear_pointer ((GtkWidget **) &self->night_light_dialog, gtk_widget_destroy);
|
|
|
|
G_OBJECT_CLASS (cc_display_panel_parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
on_arrangement_selected_ouptut_changed_cb (CcDisplayPanel *panel)
|
|
{
|
|
set_current_output (panel, cc_display_arrangement_get_selected_output (panel->arrangement), FALSE);
|
|
}
|
|
|
|
static void
|
|
on_monitor_settings_updated_cb (CcDisplayPanel *panel,
|
|
CcDisplayMonitor *monitor,
|
|
CcDisplaySettings *settings)
|
|
{
|
|
if (monitor)
|
|
cc_display_config_snap_output (panel->current_config, monitor);
|
|
update_apply_button (panel);
|
|
}
|
|
|
|
static void
|
|
on_config_type_toggled_cb (CcDisplayPanel *panel,
|
|
GtkRadioButton *btn)
|
|
{
|
|
CcDisplayConfigType type;
|
|
|
|
if (panel->rebuilding_counter > 0)
|
|
return;
|
|
|
|
if (!panel->current_config)
|
|
return;
|
|
|
|
if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (btn)))
|
|
return;
|
|
|
|
type = cc_panel_get_selected_type (panel);
|
|
config_ensure_of_type (panel, type);
|
|
}
|
|
|
|
static void
|
|
on_night_light_list_box_row_activated_cb (CcDisplayPanel *panel)
|
|
{
|
|
GtkWindow *toplevel;
|
|
toplevel = GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (panel))));
|
|
gtk_window_set_transient_for (GTK_WINDOW (panel->night_light_dialog), toplevel);
|
|
gtk_window_present (GTK_WINDOW (panel->night_light_dialog));
|
|
}
|
|
|
|
static void
|
|
on_output_enabled_active_changed_cb (CcDisplayPanel *panel)
|
|
{
|
|
gboolean active;
|
|
|
|
if (!panel->current_output)
|
|
return;
|
|
|
|
active = gtk_switch_get_active (panel->output_enabled_switch);
|
|
|
|
if (cc_display_monitor_is_active (panel->current_output) == active)
|
|
return;
|
|
|
|
/* Changing the active state requires a UI rebuild. */
|
|
cc_display_monitor_set_active (panel->current_output, active);
|
|
rebuild_ui (panel);
|
|
}
|
|
|
|
static void
|
|
on_output_selection_combo_changed_cb (CcDisplayPanel *panel)
|
|
{
|
|
GtkTreeIter iter;
|
|
g_autoptr(CcDisplayMonitor) output = NULL;
|
|
|
|
if (!panel->current_config)
|
|
return;
|
|
|
|
if (!gtk_combo_box_get_active_iter (panel->output_selection_combo, &iter))
|
|
return;
|
|
|
|
gtk_tree_model_get (GTK_TREE_MODEL (panel->output_selection_list), &iter,
|
|
1, &output,
|
|
-1);
|
|
|
|
set_current_output (panel, output, FALSE);
|
|
}
|
|
|
|
static void
|
|
on_output_selection_two_toggled_cb (CcDisplayPanel *panel, GtkRadioButton *btn)
|
|
{
|
|
CcDisplayMonitor *output;
|
|
|
|
if (panel->rebuilding_counter > 0)
|
|
return;
|
|
|
|
if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (btn)))
|
|
return;
|
|
|
|
output = g_object_get_data (G_OBJECT (btn), "display");
|
|
|
|
/* Stay in single mode when we are in single mode.
|
|
* This UI must never cause a switch between the configuration type.
|
|
* this is in contrast to the combobox monitor selection, which may
|
|
* switch to a disabled output both in SINGLE/MULTI mode without
|
|
* anything changing.
|
|
*/
|
|
if (cc_panel_get_selected_type (panel) == CC_DISPLAY_CONFIG_SINGLE)
|
|
{
|
|
if (panel->current_output)
|
|
cc_display_monitor_set_active (panel->current_output, FALSE);
|
|
if (output)
|
|
cc_display_monitor_set_active (output, TRUE);
|
|
|
|
update_apply_button (panel);
|
|
}
|
|
|
|
set_current_output (panel, g_object_get_data (G_OBJECT (btn), "display"), FALSE);
|
|
}
|
|
|
|
static void
|
|
on_primary_display_selected_index_changed_cb (CcDisplayPanel *panel)
|
|
{
|
|
gint idx = hdy_combo_row_get_selected_index (panel->primary_display_row);
|
|
g_autoptr(CcDisplayMonitor) output = NULL;
|
|
|
|
if (idx < 0 || panel->rebuilding_counter > 0)
|
|
return;
|
|
|
|
output = g_list_model_get_item (G_LIST_MODEL (panel->primary_display_list), idx);
|
|
|
|
if (cc_display_monitor_is_primary (output))
|
|
return;
|
|
|
|
cc_display_monitor_set_primary (output, TRUE);
|
|
update_apply_button (panel);
|
|
}
|
|
|
|
static void
|
|
cc_display_panel_constructed (GObject *object)
|
|
{
|
|
g_signal_connect_object (cc_panel_get_shell (CC_PANEL (object)), "notify::active-panel",
|
|
G_CALLBACK (active_panel_changed), object, 0);
|
|
|
|
G_OBJECT_CLASS (cc_display_panel_parent_class)->constructed (object);
|
|
}
|
|
|
|
static const char *
|
|
cc_display_panel_get_help_uri (CcPanel *panel)
|
|
{
|
|
return "help:gnome-help/prefs-display";
|
|
}
|
|
|
|
static void
|
|
cc_display_panel_class_init (CcDisplayPanelClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
CcPanelClass *panel_class = CC_PANEL_CLASS (klass);
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
|
|
|
panel_class->get_help_uri = cc_display_panel_get_help_uri;
|
|
|
|
object_class->constructed = cc_display_panel_constructed;
|
|
object_class->dispose = cc_display_panel_dispose;
|
|
|
|
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/display/cc-display-panel.ui");
|
|
|
|
gtk_widget_class_bind_template_child (widget_class, CcDisplayPanel, arrangement_frame);
|
|
gtk_widget_class_bind_template_child (widget_class, CcDisplayPanel, arrangement_bin);
|
|
gtk_widget_class_bind_template_child (widget_class, CcDisplayPanel, config_type_switcher_frame);
|
|
gtk_widget_class_bind_template_child (widget_class, CcDisplayPanel, config_type_join);
|
|
gtk_widget_class_bind_template_child (widget_class, CcDisplayPanel, config_type_mirror);
|
|
gtk_widget_class_bind_template_child (widget_class, CcDisplayPanel, config_type_single);
|
|
gtk_widget_class_bind_template_child (widget_class, CcDisplayPanel, current_output_label);
|
|
gtk_widget_class_bind_template_child (widget_class, CcDisplayPanel, display_settings_frame);
|
|
gtk_widget_class_bind_template_child (widget_class, CcDisplayPanel, night_light_status_label);
|
|
gtk_widget_class_bind_template_child (widget_class, CcDisplayPanel, output_enabled_switch);
|
|
gtk_widget_class_bind_template_child (widget_class, CcDisplayPanel, output_selection_combo);
|
|
gtk_widget_class_bind_template_child (widget_class, CcDisplayPanel, output_selection_stack);
|
|
gtk_widget_class_bind_template_child (widget_class, CcDisplayPanel, output_selection_two_first);
|
|
gtk_widget_class_bind_template_child (widget_class, CcDisplayPanel, output_selection_two_second);
|
|
gtk_widget_class_bind_template_child (widget_class, CcDisplayPanel, primary_display_row);
|
|
|
|
gtk_widget_class_bind_template_callback (widget_class, on_config_type_toggled_cb);
|
|
gtk_widget_class_bind_template_callback (widget_class, on_night_light_list_box_row_activated_cb);
|
|
gtk_widget_class_bind_template_callback (widget_class, on_output_enabled_active_changed_cb);
|
|
gtk_widget_class_bind_template_callback (widget_class, on_output_selection_combo_changed_cb);
|
|
gtk_widget_class_bind_template_callback (widget_class, on_output_selection_two_toggled_cb);
|
|
gtk_widget_class_bind_template_callback (widget_class, on_primary_display_selected_index_changed_cb);
|
|
}
|
|
|
|
static void
|
|
set_current_output (CcDisplayPanel *panel,
|
|
CcDisplayMonitor *output,
|
|
gboolean force)
|
|
{
|
|
GtkTreeIter iter;
|
|
gboolean changed;
|
|
|
|
/* Note, this function is also called if the internal UI needs updating after a rebuild. */
|
|
changed = (output != panel->current_output);
|
|
|
|
if (!changed && !force)
|
|
return;
|
|
|
|
panel->rebuilding_counter++;
|
|
|
|
panel->current_output = output;
|
|
|
|
if (panel->current_output)
|
|
{
|
|
gtk_label_set_text (panel->current_output_label, cc_display_monitor_get_ui_name (panel->current_output));
|
|
gtk_switch_set_active (panel->output_enabled_switch, cc_display_monitor_is_active (panel->current_output));
|
|
}
|
|
else
|
|
{
|
|
gtk_label_set_text (panel->current_output_label, "");
|
|
gtk_switch_set_active (panel->output_enabled_switch, FALSE);
|
|
}
|
|
|
|
if (g_object_get_data (G_OBJECT (panel->output_selection_two_first), "display") == output)
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (panel->output_selection_two_first), TRUE);
|
|
if (g_object_get_data (G_OBJECT (panel->output_selection_two_second), "display") == output)
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (panel->output_selection_two_second), TRUE);
|
|
|
|
gtk_tree_model_get_iter_first (GTK_TREE_MODEL (panel->output_selection_list), &iter);
|
|
while (gtk_list_store_iter_is_valid (panel->output_selection_list, &iter))
|
|
{
|
|
g_autoptr(CcDisplayMonitor) o = NULL;
|
|
|
|
gtk_tree_model_get (GTK_TREE_MODEL (panel->output_selection_list), &iter,
|
|
1, &o,
|
|
-1);
|
|
|
|
if (o == panel->current_output)
|
|
{
|
|
gtk_combo_box_set_active_iter (panel->output_selection_combo, &iter);
|
|
break;
|
|
}
|
|
|
|
gtk_tree_model_iter_next (GTK_TREE_MODEL (panel->output_selection_list), &iter);
|
|
}
|
|
|
|
if (changed)
|
|
{
|
|
cc_display_settings_set_selected_output (panel->settings, panel->current_output);
|
|
cc_display_arrangement_set_selected_output (panel->arrangement, panel->current_output);
|
|
}
|
|
|
|
panel->rebuilding_counter--;
|
|
}
|
|
|
|
static void
|
|
rebuild_ui (CcDisplayPanel *panel)
|
|
{
|
|
guint n_outputs, n_active_outputs, n_usable_outputs;
|
|
GList *outputs, *l;
|
|
|
|
panel->rebuilding_counter++;
|
|
|
|
g_list_store_remove_all (panel->primary_display_list);
|
|
gtk_list_store_clear (panel->output_selection_list);
|
|
|
|
n_active_outputs = 0;
|
|
n_usable_outputs = 0;
|
|
outputs = cc_display_config_get_ui_sorted_monitors (panel->current_config);
|
|
for (l = outputs; l; l = l->next)
|
|
{
|
|
GtkTreeIter iter;
|
|
CcDisplayMonitor *output = l->data;
|
|
|
|
if (!cc_display_monitor_is_usable (output))
|
|
continue;
|
|
|
|
n_usable_outputs += 1;
|
|
|
|
if (n_usable_outputs == 1)
|
|
{
|
|
gtk_button_set_label (GTK_BUTTON (panel->output_selection_two_first),
|
|
cc_display_monitor_get_ui_name (output));
|
|
g_object_set_data (G_OBJECT (panel->output_selection_two_first),
|
|
"display",
|
|
output);
|
|
}
|
|
else if (n_usable_outputs == 2)
|
|
{
|
|
gtk_button_set_label (GTK_BUTTON (panel->output_selection_two_second),
|
|
cc_display_monitor_get_ui_name (output));
|
|
g_object_set_data (G_OBJECT (panel->output_selection_two_second),
|
|
"display",
|
|
output);
|
|
}
|
|
|
|
gtk_list_store_append (panel->output_selection_list, &iter);
|
|
gtk_list_store_set (panel->output_selection_list,
|
|
&iter,
|
|
0, cc_display_monitor_get_ui_number_name (output),
|
|
1, output,
|
|
-1);
|
|
|
|
if (cc_display_monitor_is_active (output))
|
|
{
|
|
n_active_outputs += 1;
|
|
|
|
g_list_store_append (panel->primary_display_list, output);
|
|
if (cc_display_monitor_is_primary (output))
|
|
hdy_combo_row_set_selected_index (panel->primary_display_row,
|
|
g_list_model_get_n_items (G_LIST_MODEL (panel->primary_display_list)) - 1);
|
|
|
|
/* Ensure that an output is selected; note that this doesn't ensure
|
|
* the selected output is any useful (i.e. when switching types).
|
|
*/
|
|
if (!panel->current_output)
|
|
set_current_output (panel, output, FALSE);
|
|
}
|
|
}
|
|
|
|
/* Sync the rebuild lists/buttons */
|
|
set_current_output (panel, panel->current_output, TRUE);
|
|
|
|
n_outputs = g_list_length (outputs);
|
|
|
|
/* We only show the top chooser with two outputs (and never if the lid is closed).
|
|
* And only in that mode do we allow mirroring. */
|
|
if (n_outputs == 2 && !panel->lid_is_closed)
|
|
{
|
|
gtk_widget_set_visible (panel->config_type_switcher_frame, TRUE);
|
|
|
|
cc_panel_set_selected_type (panel, config_select_type (panel));
|
|
}
|
|
else
|
|
{
|
|
gtk_widget_set_visible (panel->config_type_switcher_frame, FALSE);
|
|
if (n_outputs == (panel->lid_is_closed ? 2 : 1))
|
|
cc_panel_set_selected_type (panel, CC_DISPLAY_CONFIG_SINGLE);
|
|
else
|
|
cc_panel_set_selected_type (panel, CC_DISPLAY_CONFIG_JOIN);
|
|
}
|
|
|
|
|
|
gtk_widget_set_visible (panel->arrangement_frame, cc_panel_get_selected_type (panel) == CC_DISPLAY_CONFIG_JOIN);
|
|
|
|
if (panel->lid_is_closed)
|
|
{
|
|
if (n_outputs <= 2 || cc_panel_get_selected_type (panel) == CC_DISPLAY_CONFIG_CLONE)
|
|
gtk_stack_set_visible_child_name (panel->output_selection_stack, "no-selection");
|
|
else
|
|
gtk_stack_set_visible_child_name (panel->output_selection_stack, "multi-selection");
|
|
}
|
|
else
|
|
{
|
|
if (n_outputs == 1 || cc_panel_get_selected_type (panel) == CC_DISPLAY_CONFIG_CLONE)
|
|
gtk_stack_set_visible_child_name (panel->output_selection_stack, "no-selection");
|
|
else if (n_outputs == 2)
|
|
gtk_stack_set_visible_child_name (panel->output_selection_stack, "two-selection");
|
|
else
|
|
gtk_stack_set_visible_child_name (panel->output_selection_stack, "multi-selection");
|
|
}
|
|
|
|
panel->rebuilding_counter--;
|
|
update_apply_button (panel);
|
|
}
|
|
|
|
static void
|
|
reset_current_config (CcDisplayPanel *panel)
|
|
{
|
|
CcDisplayConfig *current;
|
|
CcDisplayConfig *old;
|
|
GList *outputs, *l;
|
|
|
|
g_debug ("Resetting current config!");
|
|
|
|
/* We need to hold on to the config until all display references are dropped. */
|
|
old = panel->current_config;
|
|
panel->current_output = NULL;
|
|
|
|
current = cc_display_config_manager_get_current (panel->manager);
|
|
panel->current_config = current;
|
|
|
|
g_list_store_remove_all (panel->primary_display_list);
|
|
gtk_list_store_clear (panel->output_selection_list);
|
|
|
|
if (panel->current_config)
|
|
{
|
|
outputs = cc_display_config_get_ui_sorted_monitors (panel->current_config);
|
|
for (l = outputs; l; l = l->next)
|
|
{
|
|
CcDisplayMonitor *output = l->data;
|
|
|
|
/* Mark any builtin monitor as unusable if the lid is closed. */
|
|
if (cc_display_monitor_is_builtin (output) && panel->lid_is_closed)
|
|
cc_display_monitor_set_usable (output, FALSE);
|
|
}
|
|
}
|
|
|
|
cc_display_arrangement_set_config (panel->arrangement, panel->current_config);
|
|
cc_display_settings_set_config (panel->settings, panel->current_config);
|
|
set_current_output (panel, NULL, FALSE);
|
|
|
|
g_clear_object (&old);
|
|
|
|
update_apply_button (panel);
|
|
}
|
|
|
|
static void
|
|
on_screen_changed (CcDisplayPanel *panel)
|
|
{
|
|
if (!panel->manager)
|
|
return;
|
|
|
|
reset_titlebar (panel);
|
|
|
|
reset_current_config (panel);
|
|
rebuild_ui (panel);
|
|
|
|
if (!panel->current_config)
|
|
return;
|
|
|
|
ensure_monitor_labels (panel);
|
|
}
|
|
|
|
static gboolean
|
|
on_toplevel_key_press (GtkWidget *button,
|
|
GdkEventKey *event)
|
|
{
|
|
if (event->keyval != GDK_KEY_Escape)
|
|
return GDK_EVENT_PROPAGATE;
|
|
|
|
g_signal_emit_by_name (button, "activate");
|
|
return GDK_EVENT_STOP;
|
|
}
|
|
|
|
static void
|
|
show_apply_titlebar (CcDisplayPanel *panel, gboolean is_applicable)
|
|
{
|
|
if (!panel->apply_titlebar)
|
|
{
|
|
g_autoptr(GtkSizeGroup) size_group = NULL;
|
|
GtkWidget *header, *button, *toplevel;
|
|
panel->apply_titlebar = header = gtk_header_bar_new ();
|
|
gtk_widget_show (header);
|
|
|
|
size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
|
|
|
|
button = gtk_button_new_with_mnemonic (_("_Cancel"));
|
|
gtk_widget_show (button);
|
|
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), button);
|
|
gtk_size_group_add_widget (size_group, button);
|
|
g_signal_connect_object (button, "clicked", G_CALLBACK (on_screen_changed),
|
|
panel, G_CONNECT_SWAPPED);
|
|
|
|
toplevel = cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (panel)));
|
|
g_signal_connect_object (toplevel, "key-press-event", G_CALLBACK (on_toplevel_key_press),
|
|
button, G_CONNECT_SWAPPED);
|
|
|
|
panel->apply_titlebar_apply = button = gtk_button_new_with_mnemonic (_("_Apply"));
|
|
gtk_widget_show (button);
|
|
gtk_header_bar_pack_end (GTK_HEADER_BAR (header), button);
|
|
gtk_size_group_add_widget (size_group, button);
|
|
g_signal_connect_object (button, "clicked", G_CALLBACK (apply_current_configuration),
|
|
panel, G_CONNECT_SWAPPED);
|
|
gtk_style_context_add_class (gtk_widget_get_style_context (button),
|
|
GTK_STYLE_CLASS_SUGGESTED_ACTION);
|
|
|
|
header = gtk_window_get_titlebar (GTK_WINDOW (toplevel));
|
|
if (header)
|
|
panel->main_titlebar = g_object_ref (header);
|
|
panel->main_title = g_strdup (gtk_window_get_title (GTK_WINDOW (toplevel)));
|
|
|
|
gtk_window_set_titlebar (GTK_WINDOW (toplevel), panel->apply_titlebar);
|
|
g_object_ref (panel->apply_titlebar);
|
|
g_object_ref (panel->apply_titlebar_apply);
|
|
}
|
|
|
|
if (is_applicable)
|
|
{
|
|
gtk_header_bar_set_title (GTK_HEADER_BAR (panel->apply_titlebar), _("Apply Changes?"));
|
|
gtk_header_bar_set_subtitle (GTK_HEADER_BAR (panel->apply_titlebar), NULL);
|
|
}
|
|
else
|
|
{
|
|
gtk_header_bar_set_title (GTK_HEADER_BAR (panel->apply_titlebar), _("Changes Cannot be Applied"));
|
|
gtk_header_bar_set_subtitle (GTK_HEADER_BAR (panel->apply_titlebar), _("This could be due to hardware limitations."));
|
|
}
|
|
gtk_widget_set_sensitive (panel->apply_titlebar_apply, is_applicable);
|
|
}
|
|
|
|
static void
|
|
update_apply_button (CcDisplayPanel *panel)
|
|
{
|
|
gboolean config_equal;
|
|
g_autoptr(CcDisplayConfig) applied_config = NULL;
|
|
|
|
applied_config = cc_display_config_manager_get_current (panel->manager);
|
|
|
|
config_equal = cc_display_config_equal (panel->current_config,
|
|
applied_config);
|
|
|
|
if (config_equal)
|
|
reset_titlebar (panel);
|
|
else
|
|
show_apply_titlebar (panel, cc_display_config_is_applicable (panel->current_config));
|
|
}
|
|
|
|
static void
|
|
apply_current_configuration (CcDisplayPanel *self)
|
|
{
|
|
g_autoptr(GError) error = NULL;
|
|
|
|
cc_display_config_apply (self->current_config, &error);
|
|
|
|
/* re-read the configuration */
|
|
on_screen_changed (self);
|
|
|
|
if (error)
|
|
g_warning ("Error applying configuration: %s", error->message);
|
|
}
|
|
|
|
static void
|
|
mapped_cb (CcDisplayPanel *panel)
|
|
{
|
|
CcShell *shell;
|
|
GtkWidget *toplevel;
|
|
|
|
shell = cc_panel_get_shell (CC_PANEL (panel));
|
|
toplevel = cc_shell_get_toplevel (shell);
|
|
if (toplevel && !panel->focus_id)
|
|
panel->focus_id = g_signal_connect_swapped (toplevel, "notify::has-toplevel-focus",
|
|
G_CALLBACK (dialog_toplevel_focus_changed), panel);
|
|
}
|
|
|
|
static void
|
|
cc_display_panel_up_client_changed (UpClient *client,
|
|
GParamSpec *pspec,
|
|
CcDisplayPanel *self)
|
|
{
|
|
gboolean lid_is_closed;
|
|
|
|
lid_is_closed = up_client_get_lid_is_closed (client);
|
|
|
|
if (lid_is_closed != self->lid_is_closed)
|
|
{
|
|
self->lid_is_closed = lid_is_closed;
|
|
|
|
on_screen_changed (self);
|
|
}
|
|
}
|
|
|
|
static void
|
|
shell_proxy_ready (GObject *source,
|
|
GAsyncResult *res,
|
|
CcDisplayPanel *self)
|
|
{
|
|
GDBusProxy *proxy;
|
|
g_autoptr(GError) error = NULL;
|
|
|
|
proxy = cc_object_storage_create_dbus_proxy_finish (res, &error);
|
|
if (!proxy)
|
|
{
|
|
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
|
g_warning ("Failed to contact gnome-shell: %s", error->message);
|
|
return;
|
|
}
|
|
|
|
self->shell_proxy = proxy;
|
|
|
|
ensure_monitor_labels (self);
|
|
}
|
|
|
|
static void
|
|
update_has_accel (CcDisplayPanel *self)
|
|
{
|
|
g_autoptr(GVariant) v = NULL;
|
|
|
|
if (self->iio_sensor_proxy == NULL)
|
|
{
|
|
g_debug ("Has no accelerometer");
|
|
self->has_accelerometer = FALSE;
|
|
cc_display_settings_set_has_accelerometer (self->settings, self->has_accelerometer);
|
|
return;
|
|
}
|
|
|
|
v = g_dbus_proxy_get_cached_property (self->iio_sensor_proxy, "HasAccelerometer");
|
|
if (v)
|
|
{
|
|
self->has_accelerometer = g_variant_get_boolean (v);
|
|
}
|
|
else
|
|
{
|
|
self->has_accelerometer = FALSE;
|
|
}
|
|
|
|
cc_display_settings_set_has_accelerometer (self->settings, self->has_accelerometer);
|
|
|
|
g_debug ("Has %saccelerometer", self->has_accelerometer ? "" : "no ");
|
|
}
|
|
|
|
static void
|
|
sensor_proxy_properties_changed_cb (GDBusProxy *proxy,
|
|
GVariant *changed_properties,
|
|
GStrv invalidated_properties,
|
|
CcDisplayPanel *self)
|
|
{
|
|
GVariantDict dict;
|
|
|
|
g_variant_dict_init (&dict, changed_properties);
|
|
|
|
if (g_variant_dict_contains (&dict, "HasAccelerometer"))
|
|
update_has_accel (self);
|
|
}
|
|
|
|
static void
|
|
sensor_proxy_appeared_cb (GDBusConnection *connection,
|
|
const gchar *name,
|
|
const gchar *name_owner,
|
|
gpointer user_data)
|
|
{
|
|
CcDisplayPanel *self = user_data;
|
|
|
|
g_debug ("SensorProxy appeared");
|
|
|
|
self->iio_sensor_proxy = g_dbus_proxy_new_sync (connection,
|
|
G_DBUS_PROXY_FLAGS_NONE,
|
|
NULL,
|
|
"net.hadess.SensorProxy",
|
|
"/net/hadess/SensorProxy",
|
|
"net.hadess.SensorProxy",
|
|
NULL,
|
|
NULL);
|
|
g_return_if_fail (self->iio_sensor_proxy);
|
|
|
|
g_signal_connect (self->iio_sensor_proxy, "g-properties-changed",
|
|
G_CALLBACK (sensor_proxy_properties_changed_cb), self);
|
|
update_has_accel (self);
|
|
}
|
|
|
|
static void
|
|
sensor_proxy_vanished_cb (GDBusConnection *connection,
|
|
const gchar *name,
|
|
gpointer user_data)
|
|
{
|
|
CcDisplayPanel *self = user_data;
|
|
|
|
g_debug ("SensorProxy vanished");
|
|
|
|
g_clear_object (&self->iio_sensor_proxy);
|
|
update_has_accel (self);
|
|
}
|
|
|
|
static void
|
|
night_light_sync_label (GtkWidget *label, GSettings *settings)
|
|
{
|
|
gboolean ret = g_settings_get_boolean (settings, "night-light-enabled");
|
|
gtk_label_set_label (GTK_LABEL (label),
|
|
/* TRANSLATORS: the state of the night light setting */
|
|
ret ? _("On") : _("Off"));
|
|
}
|
|
|
|
static void
|
|
settings_color_changed_cb (GSettings *settings, gchar *key, GtkWidget *label)
|
|
{
|
|
if (g_strcmp0 (key, "night-light-enabled") == 0)
|
|
night_light_sync_label (label, settings);
|
|
}
|
|
|
|
static void
|
|
session_bus_ready (GObject *source,
|
|
GAsyncResult *res,
|
|
CcDisplayPanel *self)
|
|
{
|
|
GDBusConnection *bus;
|
|
g_autoptr(GError) error = NULL;
|
|
|
|
bus = g_bus_get_finish (res, &error);
|
|
if (!bus)
|
|
{
|
|
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
|
{
|
|
g_warning ("Failed to get session bus: %s", error->message);
|
|
}
|
|
return;
|
|
}
|
|
|
|
self->manager = cc_display_config_manager_dbus_new ();
|
|
g_signal_connect_object (self->manager, "changed",
|
|
G_CALLBACK (on_screen_changed),
|
|
self,
|
|
G_CONNECT_SWAPPED);
|
|
}
|
|
|
|
static void
|
|
cc_display_panel_init (CcDisplayPanel *self)
|
|
{
|
|
g_autoptr (GtkCssProvider) provider = NULL;
|
|
GtkCellRenderer *renderer;
|
|
|
|
g_resources_register (cc_display_get_resource ());
|
|
|
|
gtk_widget_init_template (GTK_WIDGET (self));
|
|
|
|
self->arrangement = cc_display_arrangement_new (NULL);
|
|
|
|
gtk_widget_show (GTK_WIDGET (self->arrangement));
|
|
gtk_widget_set_size_request (GTK_WIDGET (self->arrangement), 400, 175);
|
|
gtk_container_add (GTK_CONTAINER (self->arrangement_bin), GTK_WIDGET (self->arrangement));
|
|
|
|
g_signal_connect_object (self->arrangement, "updated",
|
|
G_CALLBACK (update_apply_button), self,
|
|
G_CONNECT_SWAPPED);
|
|
g_signal_connect_object (self->arrangement, "notify::selected-output",
|
|
G_CALLBACK (on_arrangement_selected_ouptut_changed_cb), self,
|
|
G_CONNECT_SWAPPED);
|
|
|
|
self->settings = cc_display_settings_new ();
|
|
gtk_widget_show (GTK_WIDGET (self->settings));
|
|
gtk_container_add (GTK_CONTAINER (self->display_settings_frame), GTK_WIDGET (self->settings));
|
|
g_signal_connect_object (self->settings, "updated",
|
|
G_CALLBACK (on_monitor_settings_updated_cb), self,
|
|
G_CONNECT_SWAPPED);
|
|
|
|
self->primary_display_list = g_list_store_new (CC_TYPE_DISPLAY_MONITOR);
|
|
hdy_combo_row_bind_name_model (self->primary_display_row,
|
|
G_LIST_MODEL (self->primary_display_list),
|
|
(HdyComboRowGetNameFunc) cc_display_monitor_dup_ui_number_name,
|
|
NULL, NULL);
|
|
|
|
self->output_selection_list = gtk_list_store_new (2, G_TYPE_STRING, CC_TYPE_DISPLAY_MONITOR);
|
|
gtk_combo_box_set_model (self->output_selection_combo, GTK_TREE_MODEL (self->output_selection_list));
|
|
gtk_cell_layout_clear (GTK_CELL_LAYOUT (self->output_selection_combo));
|
|
renderer = gtk_cell_renderer_text_new ();
|
|
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (self->output_selection_combo),
|
|
renderer,
|
|
TRUE);
|
|
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (self->output_selection_combo),
|
|
renderer,
|
|
"text",
|
|
0);
|
|
gtk_cell_renderer_set_visible (renderer, TRUE);
|
|
|
|
self->night_light_dialog = cc_night_light_dialog_new ();
|
|
self->settings_color = g_settings_new ("org.gnome.settings-daemon.plugins.color");
|
|
|
|
g_signal_connect_object (self->settings_color, "changed",
|
|
G_CALLBACK (settings_color_changed_cb), self->night_light_status_label, 0);
|
|
night_light_sync_label (GTK_WIDGET (self->night_light_status_label), self->settings_color);
|
|
|
|
self->up_client = up_client_new ();
|
|
if (up_client_get_lid_is_present (self->up_client))
|
|
{
|
|
g_signal_connect (self->up_client, "notify::lid-is-closed",
|
|
G_CALLBACK (cc_display_panel_up_client_changed), self);
|
|
cc_display_panel_up_client_changed (self->up_client, NULL, self);
|
|
}
|
|
else
|
|
g_clear_object (&self->up_client);
|
|
|
|
g_signal_connect (self, "map", G_CALLBACK (mapped_cb), NULL);
|
|
|
|
self->shell_cancellable = g_cancellable_new ();
|
|
cc_object_storage_create_dbus_proxy (G_BUS_TYPE_SESSION,
|
|
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
|
|
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS |
|
|
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
|
"org.gnome.Shell",
|
|
"/org/gnome/Shell",
|
|
"org.gnome.Shell",
|
|
self->shell_cancellable,
|
|
(GAsyncReadyCallback) shell_proxy_ready,
|
|
self);
|
|
|
|
g_bus_get (G_BUS_TYPE_SESSION,
|
|
self->shell_cancellable,
|
|
(GAsyncReadyCallback) session_bus_ready,
|
|
self);
|
|
|
|
self->sensor_watch_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM,
|
|
"net.hadess.SensorProxy",
|
|
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
|
sensor_proxy_appeared_cb,
|
|
sensor_proxy_vanished_cb,
|
|
self,
|
|
NULL);
|
|
|
|
provider = gtk_css_provider_new ();
|
|
gtk_css_provider_load_from_resource (provider, "/org/gnome/control-center/display/display-arrangement.css");
|
|
gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
|
|
GTK_STYLE_PROVIDER (provider),
|
|
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
|
}
|