Line |
Branch |
Exec |
Source |
1 |
|
|
/* cc-display-settings.c |
2 |
|
|
* |
3 |
|
|
* Copyright (C) 2007, 2008, 2018, 2019 Red Hat, Inc. |
4 |
|
|
* Copyright (C) 2013 Intel, Inc. |
5 |
|
|
* |
6 |
|
|
* Written by: Benjamin Berg <bberg@redhat.com> |
7 |
|
|
* |
8 |
|
|
* This program is free software; you can redistribute it and/or modify |
9 |
|
|
* it under the terms of the GNU General Public License as published by |
10 |
|
|
* the Free Software Foundation; either version 2, or (at your option) |
11 |
|
|
* any later version. |
12 |
|
|
* |
13 |
|
|
* This program is distributed in the hope that it will be useful, |
14 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 |
|
|
* GNU General Public License for more details. |
17 |
|
|
* |
18 |
|
|
* You should have received a copy of the GNU General Public License |
19 |
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>. |
20 |
|
|
*/ |
21 |
|
|
|
22 |
|
|
#include <float.h> |
23 |
|
|
#include <glib/gi18n.h> |
24 |
|
|
#include <float.h> |
25 |
|
|
#include <math.h> |
26 |
|
|
#include "cc-display-settings.h" |
27 |
|
|
#include "cc-display-config.h" |
28 |
|
|
|
29 |
|
|
#define MAX_SCALE_BUTTONS 5 |
30 |
|
|
|
31 |
|
|
struct _CcDisplaySettings |
32 |
|
|
{ |
33 |
|
|
GtkBox object; |
34 |
|
|
|
35 |
|
|
gboolean updating; |
36 |
|
|
gboolean num_scales; |
37 |
|
|
gboolean collapsed; |
38 |
|
|
guint idle_udpate_id; |
39 |
|
|
|
40 |
|
|
gboolean has_accelerometer; |
41 |
|
|
CcDisplayConfig *config; |
42 |
|
|
CcDisplayMonitor *selected_output; |
43 |
|
|
|
44 |
|
|
GListModel *orientation_list; |
45 |
|
|
GListStore *refresh_rate_list; |
46 |
|
|
GListStore *resolution_list; |
47 |
|
|
GListModel *scale_list; |
48 |
|
|
|
49 |
|
|
GtkWidget *enabled_listbox; |
50 |
|
|
AdwSwitchRow *enabled_row; |
51 |
|
|
GtkWidget *orientation_row; |
52 |
|
|
GtkWidget *refresh_rate_row; |
53 |
|
|
AdwExpanderRow *refresh_rate_expander_row; |
54 |
|
|
GtkLabel *refresh_rate_expander_suffix_label; |
55 |
|
|
AdwSwitchRow *variable_refresh_rate_row; |
56 |
|
|
AdwComboRow *preferred_refresh_rate_row; |
57 |
|
|
GtkWidget *resolution_row; |
58 |
|
|
GtkWidget *scale_bbox; |
59 |
|
|
GtkWidget *scale_buttons_row; |
60 |
|
|
GtkWidget *scale_combo_row; |
61 |
|
|
AdwSwitchRow *underscanning_row; |
62 |
|
|
}; |
63 |
|
|
|
64 |
|
|
typedef struct _CcDisplaySettings CcDisplaySettings; |
65 |
|
|
|
66 |
|
|
enum { |
67 |
|
|
PROP_0, |
68 |
|
|
PROP_HAS_ACCELEROMETER, |
69 |
|
|
PROP_CONFIG, |
70 |
|
|
PROP_SELECTED_OUTPUT, |
71 |
|
|
PROP_LAST |
72 |
|
|
}; |
73 |
|
|
|
74 |
|
✗ |
G_DEFINE_TYPE (CcDisplaySettings, cc_display_settings, GTK_TYPE_BOX) |
75 |
|
|
|
76 |
|
|
static GParamSpec *props[PROP_LAST]; |
77 |
|
|
|
78 |
|
|
static void on_scale_btn_active_changed_cb (CcDisplaySettings *self, |
79 |
|
|
GParamSpec *pspec, |
80 |
|
|
GtkWidget *widget); |
81 |
|
|
|
82 |
|
|
static gboolean |
83 |
|
✗ |
should_show_rotation (CcDisplaySettings *self) |
84 |
|
|
{ |
85 |
|
|
gboolean supports_rotation; |
86 |
|
|
|
87 |
|
✗ |
supports_rotation = cc_display_monitor_supports_rotation (self->selected_output, |
88 |
|
|
CC_DISPLAY_ROTATION_90 | |
89 |
|
|
CC_DISPLAY_ROTATION_180 | |
90 |
|
|
CC_DISPLAY_ROTATION_270); |
91 |
|
|
|
92 |
|
|
/* Doesn't support rotation at all */ |
93 |
|
✗ |
if (!supports_rotation) |
94 |
|
✗ |
return FALSE; |
95 |
|
|
|
96 |
|
|
/* We can always rotate displays that aren't builtin */ |
97 |
|
✗ |
if (!cc_display_monitor_is_builtin (self->selected_output)) |
98 |
|
✗ |
return TRUE; |
99 |
|
|
|
100 |
|
|
/* Only offer rotation if there's no accelerometer */ |
101 |
|
✗ |
return !self->has_accelerometer; |
102 |
|
|
} |
103 |
|
|
|
104 |
|
|
static const gchar * |
105 |
|
✗ |
string_for_rotation (CcDisplayRotation rotation) |
106 |
|
|
{ |
107 |
|
✗ |
switch (rotation) |
108 |
|
|
{ |
109 |
|
✗ |
case CC_DISPLAY_ROTATION_NONE: |
110 |
|
|
case CC_DISPLAY_ROTATION_180_FLIPPED: |
111 |
|
✗ |
return C_("Display rotation", "Landscape"); |
112 |
|
✗ |
case CC_DISPLAY_ROTATION_90: |
113 |
|
|
case CC_DISPLAY_ROTATION_270_FLIPPED: |
114 |
|
✗ |
return C_("Display rotation", "Portrait Right"); |
115 |
|
✗ |
case CC_DISPLAY_ROTATION_270: |
116 |
|
|
case CC_DISPLAY_ROTATION_90_FLIPPED: |
117 |
|
✗ |
return C_("Display rotation", "Portrait Left"); |
118 |
|
✗ |
case CC_DISPLAY_ROTATION_180: |
119 |
|
|
case CC_DISPLAY_ROTATION_FLIPPED: |
120 |
|
✗ |
return C_("Display rotation", "Landscape (flipped)"); |
121 |
|
|
} |
122 |
|
✗ |
return ""; |
123 |
|
|
} |
124 |
|
|
|
125 |
|
|
static const gchar * |
126 |
|
✗ |
make_aspect_string (gint width, |
127 |
|
|
gint height) |
128 |
|
|
{ |
129 |
|
|
int ratio; |
130 |
|
✗ |
const gchar *aspect = NULL; |
131 |
|
|
|
132 |
|
|
/* We use a number of Unicode characters below: |
133 |
|
|
* ∶ is U+2236 RATIO |
134 |
|
|
* is U+2009 THIN SPACE, |
135 |
|
|
* × is U+00D7 MULTIPLICATION SIGN |
136 |
|
|
*/ |
137 |
|
✗ |
if (width && height) { |
138 |
|
✗ |
if (width > height) |
139 |
|
✗ |
ratio = width * 10 / height; |
140 |
|
|
else |
141 |
|
✗ |
ratio = height * 10 / width; |
142 |
|
|
|
143 |
|
✗ |
switch (ratio) { |
144 |
|
✗ |
case 13: |
145 |
|
✗ |
aspect = "4∶3"; |
146 |
|
✗ |
break; |
147 |
|
✗ |
case 16: |
148 |
|
✗ |
aspect = "16∶10"; |
149 |
|
✗ |
break; |
150 |
|
✗ |
case 17: |
151 |
|
✗ |
aspect = "16∶9"; |
152 |
|
✗ |
break; |
153 |
|
✗ |
case 23: |
154 |
|
✗ |
aspect = "21∶9"; |
155 |
|
✗ |
break; |
156 |
|
✗ |
case 35: |
157 |
|
✗ |
aspect = "32∶9"; |
158 |
|
✗ |
break; |
159 |
|
✗ |
case 12: |
160 |
|
✗ |
aspect = "5∶4"; |
161 |
|
✗ |
break; |
162 |
|
|
/* This catches 1.5625 as well (1600x1024) when maybe it shouldn't. */ |
163 |
|
✗ |
case 15: |
164 |
|
✗ |
aspect = "3∶2"; |
165 |
|
✗ |
break; |
166 |
|
✗ |
case 18: |
167 |
|
✗ |
aspect = "9∶5"; |
168 |
|
✗ |
break; |
169 |
|
✗ |
case 10: |
170 |
|
✗ |
aspect = "1∶1"; |
171 |
|
✗ |
break; |
172 |
|
|
} |
173 |
|
|
} |
174 |
|
|
|
175 |
|
✗ |
return aspect; |
176 |
|
|
} |
177 |
|
|
|
178 |
|
|
static gchar * |
179 |
|
✗ |
make_refresh_rate_string (CcDisplayMode *mode) |
180 |
|
|
{ |
181 |
|
✗ |
return g_strdup_printf (_("%.2lf Hz"), cc_display_mode_get_freq_f (mode)); |
182 |
|
|
} |
183 |
|
|
|
184 |
|
|
static gchar * |
185 |
|
✗ |
make_variable_refresh_rate_string (CcDisplayMonitor *output, |
186 |
|
|
CcDisplayMode *mode) |
187 |
|
|
{ |
188 |
|
|
int min_freq; |
189 |
|
|
|
190 |
|
✗ |
min_freq = cc_display_monitor_get_min_freq (output); |
191 |
|
✗ |
if (min_freq > 0) |
192 |
|
|
{ |
193 |
|
|
/* Translators: |
194 |
|
|
* 1. "Variable" is an adjective that refers to the refresh rate |
195 |
|
|
* 2. The formatting sequence is a range separated by an en-dash |
196 |
|
|
* (unicode "\u2013"). For example: "Variable (48–144.97 Hz)" |
197 |
|
|
*/ |
198 |
|
✗ |
return g_strdup_printf (_("Variable (%d\u2013%.2lf Hz)"), |
199 |
|
|
min_freq, |
200 |
|
|
cc_display_mode_get_freq_f (mode)); |
201 |
|
|
} |
202 |
|
|
else |
203 |
|
|
{ |
204 |
|
|
/* Translators: "Variable" is an adjective that refers to the refresh rate */ |
205 |
|
✗ |
return g_strdup_printf (_("Variable (up to %.2lf Hz)"), |
206 |
|
|
cc_display_mode_get_freq_f (mode)); |
207 |
|
|
} |
208 |
|
|
} |
209 |
|
|
|
210 |
|
|
static gchar * |
211 |
|
✗ |
make_expander_refresh_rate_string (CcDisplayMonitor *output, |
212 |
|
|
CcDisplayMode *mode) |
213 |
|
|
{ |
214 |
|
✗ |
switch (cc_display_mode_get_refresh_rate_mode (mode)) |
215 |
|
|
{ |
216 |
|
✗ |
case MODE_REFRESH_RATE_MODE_FIXED: |
217 |
|
✗ |
return make_refresh_rate_string (mode); |
218 |
|
✗ |
case MODE_REFRESH_RATE_MODE_VARIABLE: |
219 |
|
✗ |
return make_variable_refresh_rate_string (output, mode); |
220 |
|
✗ |
default: |
221 |
|
✗ |
g_assert_not_reached(); |
222 |
|
|
} |
223 |
|
|
|
224 |
|
|
return NULL; |
225 |
|
|
} |
226 |
|
|
|
227 |
|
|
static gboolean |
228 |
|
✗ |
mode_to_refresh_rate_transform_func (GBinding *binding, |
229 |
|
|
const GValue *source_value, |
230 |
|
|
GValue *target_value, |
231 |
|
|
CcDisplaySettings *self) |
232 |
|
|
{ |
233 |
|
|
CcDisplayMode *mode; |
234 |
|
|
gchar *refresh_rate_string; |
235 |
|
|
|
236 |
|
✗ |
if (!G_VALUE_HOLDS_OBJECT (source_value)) |
237 |
|
✗ |
return FALSE; |
238 |
|
|
|
239 |
|
✗ |
if (!G_VALUE_HOLDS_STRING (target_value)) |
240 |
|
✗ |
return FALSE; |
241 |
|
|
|
242 |
|
✗ |
mode = CC_DISPLAY_MODE (g_value_get_object (source_value)); |
243 |
|
✗ |
g_return_val_if_fail (mode != NULL, FALSE); |
244 |
|
|
|
245 |
|
|
refresh_rate_string = |
246 |
|
✗ |
make_expander_refresh_rate_string (self->selected_output, mode); |
247 |
|
|
|
248 |
|
✗ |
g_value_take_string (target_value, refresh_rate_string); |
249 |
|
|
|
250 |
|
✗ |
return TRUE; |
251 |
|
|
} |
252 |
|
|
|
253 |
|
|
static gchar * |
254 |
|
✗ |
make_resolution_string (CcDisplayMode *mode) |
255 |
|
|
{ |
256 |
|
|
const char *interlaced; |
257 |
|
|
const char *aspect; |
258 |
|
|
int width, height; |
259 |
|
|
|
260 |
|
✗ |
cc_display_mode_get_resolution (mode, &width, &height); |
261 |
|
✗ |
aspect = make_aspect_string (width, height); |
262 |
|
✗ |
interlaced = cc_display_mode_is_interlaced (mode) ? "i" : ""; |
263 |
|
|
|
264 |
|
✗ |
if (aspect != NULL) |
265 |
|
✗ |
return g_strdup_printf ("%d × %d%s (%s)", width, height, interlaced, aspect); |
266 |
|
|
else |
267 |
|
✗ |
return g_strdup_printf ("%d × %d%s", width, height, interlaced); |
268 |
|
|
} |
269 |
|
|
|
270 |
|
|
static double |
271 |
|
✗ |
round_scale_for_ui (double scale) |
272 |
|
|
{ |
273 |
|
|
/* Keep in sync with mutter */ |
274 |
|
✗ |
return round (scale*4)/4; |
275 |
|
|
} |
276 |
|
|
|
277 |
|
|
static gchar * |
278 |
|
✗ |
make_scale_string (gdouble scale) |
279 |
|
|
{ |
280 |
|
✗ |
return g_strdup_printf ("%d %%", (int) (round_scale_for_ui (scale)*100)); |
281 |
|
|
} |
282 |
|
|
|
283 |
|
|
static gint |
284 |
|
✗ |
sort_modes_by_area_desc (CcDisplayMode *a, CcDisplayMode *b) |
285 |
|
|
{ |
286 |
|
|
gint wa, ha, wb, hb; |
287 |
|
|
gint res; |
288 |
|
|
|
289 |
|
✗ |
cc_display_mode_get_resolution (a, &wa, &ha); |
290 |
|
✗ |
cc_display_mode_get_resolution (b, &wb, &hb); |
291 |
|
|
|
292 |
|
|
/* Sort first by width, then height. |
293 |
|
|
* We used to sort by area, but that can be confusing. */ |
294 |
|
✗ |
res = wb - wa; |
295 |
|
✗ |
if (res) |
296 |
|
✗ |
return res; |
297 |
|
✗ |
return hb - ha; |
298 |
|
|
} |
299 |
|
|
|
300 |
|
|
static gint |
301 |
|
✗ |
sort_modes_by_refresh_rate_desc (CcDisplayMode *a, CcDisplayMode *b) |
302 |
|
|
{ |
303 |
|
✗ |
if (cc_display_mode_get_refresh_rate_mode (a) != cc_display_mode_get_refresh_rate_mode (b)) |
304 |
|
|
{ |
305 |
|
✗ |
if (cc_display_mode_get_refresh_rate_mode (a) == MODE_REFRESH_RATE_MODE_VARIABLE) |
306 |
|
✗ |
return -1; |
307 |
|
|
else |
308 |
|
✗ |
return 1; |
309 |
|
|
} |
310 |
|
|
|
311 |
|
✗ |
double delta = (cc_display_mode_get_freq_f (b) - cc_display_mode_get_freq_f (a))*1000.; |
312 |
|
|
|
313 |
|
✗ |
return delta; |
314 |
|
|
} |
315 |
|
|
|
316 |
|
|
static gboolean |
317 |
|
✗ |
cc_display_settings_rebuild_ui (CcDisplaySettings *self) |
318 |
|
|
{ |
319 |
|
|
GtkWidget *child; |
320 |
|
✗ |
g_autolist(CcDisplayMode) clone_modes = NULL; |
321 |
|
|
GList *modes; |
322 |
|
|
GList *item; |
323 |
|
|
gint width, height; |
324 |
|
|
CcDisplayMode *current_mode; |
325 |
|
✗ |
GtkToggleButton *group = NULL; |
326 |
|
✗ |
g_autoptr(GArray) scales = NULL; |
327 |
|
|
gint i; |
328 |
|
|
|
329 |
|
✗ |
self->idle_udpate_id = 0; |
330 |
|
|
|
331 |
|
✗ |
if (!self->config || !self->selected_output) |
332 |
|
|
{ |
333 |
|
✗ |
gtk_widget_set_visible (self->enabled_listbox, FALSE); |
334 |
|
✗ |
gtk_widget_set_visible (self->orientation_row, FALSE); |
335 |
|
✗ |
gtk_widget_set_visible (self->refresh_rate_row, FALSE); |
336 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->refresh_rate_expander_row), FALSE); |
337 |
|
✗ |
gtk_widget_set_visible (self->resolution_row, FALSE); |
338 |
|
✗ |
gtk_widget_set_visible (self->scale_combo_row, FALSE); |
339 |
|
✗ |
gtk_widget_set_visible (self->scale_buttons_row, FALSE); |
340 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->underscanning_row), FALSE); |
341 |
|
|
|
342 |
|
✗ |
return G_SOURCE_REMOVE; |
343 |
|
|
} |
344 |
|
|
|
345 |
|
✗ |
g_object_freeze_notify ((GObject*) self->enabled_row); |
346 |
|
✗ |
g_object_freeze_notify ((GObject*) self->orientation_row); |
347 |
|
✗ |
g_object_freeze_notify ((GObject*) self->refresh_rate_row); |
348 |
|
✗ |
g_object_freeze_notify ((GObject*) self->refresh_rate_expander_row); |
349 |
|
✗ |
g_object_freeze_notify ((GObject*) self->variable_refresh_rate_row); |
350 |
|
✗ |
g_object_freeze_notify ((GObject*) self->preferred_refresh_rate_row); |
351 |
|
✗ |
g_object_freeze_notify ((GObject*) self->resolution_row); |
352 |
|
✗ |
g_object_freeze_notify ((GObject*) self->scale_combo_row); |
353 |
|
✗ |
g_object_freeze_notify ((GObject*) self->underscanning_row); |
354 |
|
|
|
355 |
|
✗ |
cc_display_monitor_get_geometry (self->selected_output, NULL, NULL, &width, &height); |
356 |
|
|
|
357 |
|
|
/* Selecte the first mode we can find if the monitor is disabled. */ |
358 |
|
✗ |
current_mode = cc_display_monitor_get_mode (self->selected_output); |
359 |
|
✗ |
if (current_mode == NULL) |
360 |
|
✗ |
current_mode = cc_display_monitor_get_preferred_mode (self->selected_output); |
361 |
|
✗ |
if (current_mode == NULL) { |
362 |
|
✗ |
modes = cc_display_monitor_get_modes (self->selected_output); |
363 |
|
|
/* Lets assume that a monitor always has at least one mode. */ |
364 |
|
✗ |
g_assert (modes); |
365 |
|
✗ |
current_mode = CC_DISPLAY_MODE (modes->data); |
366 |
|
|
} |
367 |
|
|
|
368 |
|
|
/* Enabled Switch */ |
369 |
|
✗ |
adw_preferences_row_set_title (ADW_PREFERENCES_ROW (self->enabled_row), |
370 |
|
|
cc_display_monitor_get_ui_name (self->selected_output)); |
371 |
|
✗ |
adw_switch_row_set_active (self->enabled_row, |
372 |
|
|
cc_display_monitor_is_active (self->selected_output)); |
373 |
|
|
|
374 |
|
✗ |
if (should_show_rotation (self)) |
375 |
|
|
{ |
376 |
|
|
guint i; |
377 |
|
✗ |
CcDisplayRotation rotations[] = { CC_DISPLAY_ROTATION_NONE, |
378 |
|
|
CC_DISPLAY_ROTATION_90, |
379 |
|
|
CC_DISPLAY_ROTATION_270, |
380 |
|
|
CC_DISPLAY_ROTATION_180 }; |
381 |
|
|
|
382 |
|
✗ |
gtk_widget_set_visible (self->orientation_row, TRUE); |
383 |
|
|
|
384 |
|
✗ |
gtk_string_list_splice (GTK_STRING_LIST (self->orientation_list), |
385 |
|
|
0, |
386 |
|
|
g_list_model_get_n_items (self->orientation_list), |
387 |
|
|
NULL); |
388 |
|
✗ |
for (i = 0; i < G_N_ELEMENTS (rotations); i++) |
389 |
|
|
{ |
390 |
|
✗ |
g_autoptr(GObject) obj = NULL; |
391 |
|
|
|
392 |
|
✗ |
if (!cc_display_monitor_supports_rotation (self->selected_output, rotations[i])) |
393 |
|
✗ |
continue; |
394 |
|
|
|
395 |
|
✗ |
gtk_string_list_append (GTK_STRING_LIST (self->orientation_list), |
396 |
|
✗ |
string_for_rotation (rotations[i])); |
397 |
|
✗ |
obj = g_list_model_get_item (self->orientation_list, i); |
398 |
|
✗ |
g_object_set_data (G_OBJECT (obj), "rotation-value", GINT_TO_POINTER (rotations[i])); |
399 |
|
|
|
400 |
|
✗ |
if (cc_display_monitor_get_rotation (self->selected_output) == rotations[i]) |
401 |
|
✗ |
adw_combo_row_set_selected (ADW_COMBO_ROW (self->orientation_row), |
402 |
|
✗ |
g_list_model_get_n_items (G_LIST_MODEL (self->orientation_list)) - 1); |
403 |
|
|
} |
404 |
|
|
} |
405 |
|
|
else |
406 |
|
|
{ |
407 |
|
✗ |
gtk_widget_set_visible (self->orientation_row, FALSE); |
408 |
|
|
} |
409 |
|
|
|
410 |
|
|
/* Only show refresh rate if we are not in cloning mode. */ |
411 |
|
✗ |
if (!cc_display_config_is_cloning (self->config)) |
412 |
|
|
{ |
413 |
|
|
GList *item; |
414 |
|
|
gdouble current_freq; |
415 |
|
|
CcDisplayModeRefreshRateMode current_refresh_rate_mode; |
416 |
|
✗ |
gboolean has_variable_refresh_rate_modes = FALSE; |
417 |
|
|
|
418 |
|
✗ |
current_freq = cc_display_mode_get_freq_f (current_mode); |
419 |
|
✗ |
current_refresh_rate_mode = cc_display_mode_get_refresh_rate_mode (current_mode); |
420 |
|
|
|
421 |
|
✗ |
modes = cc_display_monitor_get_modes (self->selected_output); |
422 |
|
|
|
423 |
|
✗ |
g_list_store_remove_all (self->refresh_rate_list); |
424 |
|
|
|
425 |
|
✗ |
for (item = modes; item != NULL; item = item->next) |
426 |
|
|
{ |
427 |
|
|
gint w, h; |
428 |
|
|
guint new; |
429 |
|
✗ |
CcDisplayMode *mode = CC_DISPLAY_MODE (item->data); |
430 |
|
|
CcDisplayModeRefreshRateMode refresh_rate_mode; |
431 |
|
|
|
432 |
|
✗ |
cc_display_mode_get_resolution (mode, &w, &h); |
433 |
|
✗ |
if (w != width || h != height) |
434 |
|
✗ |
continue; |
435 |
|
|
|
436 |
|
✗ |
refresh_rate_mode = cc_display_mode_get_refresh_rate_mode (mode); |
437 |
|
|
|
438 |
|
✗ |
if (refresh_rate_mode == MODE_REFRESH_RATE_MODE_VARIABLE) |
439 |
|
✗ |
has_variable_refresh_rate_modes = TRUE; |
440 |
|
|
|
441 |
|
✗ |
if (current_refresh_rate_mode != refresh_rate_mode) |
442 |
|
✗ |
continue; |
443 |
|
|
|
444 |
|
|
/* At some point we used to filter very close resolutions, |
445 |
|
|
* but we don't anymore these days. |
446 |
|
|
*/ |
447 |
|
✗ |
new = g_list_store_insert_sorted (self->refresh_rate_list, |
448 |
|
|
mode, |
449 |
|
|
(GCompareDataFunc) sort_modes_by_refresh_rate_desc, |
450 |
|
|
NULL); |
451 |
|
|
|
452 |
|
✗ |
if (current_freq != cc_display_mode_get_freq_f (mode)) |
453 |
|
✗ |
continue; |
454 |
|
|
|
455 |
|
✗ |
adw_combo_row_set_selected (ADW_COMBO_ROW (self->refresh_rate_row), new); |
456 |
|
✗ |
adw_combo_row_set_selected (self->preferred_refresh_rate_row, new); |
457 |
|
|
} |
458 |
|
|
|
459 |
|
✗ |
adw_switch_row_set_active (self->variable_refresh_rate_row, |
460 |
|
|
current_refresh_rate_mode == MODE_REFRESH_RATE_MODE_VARIABLE); |
461 |
|
✗ |
gtk_widget_set_sensitive (GTK_WIDGET (self->variable_refresh_rate_row), |
462 |
|
|
has_variable_refresh_rate_modes); |
463 |
|
|
|
464 |
|
✗ |
if (cc_display_monitor_supports_variable_refresh_rate (self->selected_output)) |
465 |
|
|
{ |
466 |
|
✗ |
gtk_widget_set_visible (self->refresh_rate_row, FALSE); |
467 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->refresh_rate_expander_row), TRUE); |
468 |
|
|
} |
469 |
|
|
else |
470 |
|
|
{ |
471 |
|
✗ |
gtk_widget_set_visible (self->refresh_rate_row, TRUE); |
472 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->refresh_rate_expander_row), FALSE); |
473 |
|
|
} |
474 |
|
|
} |
475 |
|
|
else |
476 |
|
|
{ |
477 |
|
✗ |
gtk_widget_set_visible (self->refresh_rate_row, FALSE); |
478 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->refresh_rate_expander_row), FALSE); |
479 |
|
|
} |
480 |
|
|
|
481 |
|
|
|
482 |
|
|
/* Resolutions are always shown. */ |
483 |
|
✗ |
gtk_widget_set_visible (self->resolution_row, TRUE); |
484 |
|
✗ |
if (cc_display_config_is_cloning (self->config)) |
485 |
|
|
{ |
486 |
|
✗ |
clone_modes = cc_display_config_generate_cloning_modes (self->config); |
487 |
|
✗ |
modes = clone_modes; |
488 |
|
|
} |
489 |
|
|
else |
490 |
|
|
{ |
491 |
|
✗ |
modes = cc_display_monitor_get_modes (self->selected_output); |
492 |
|
|
} |
493 |
|
|
|
494 |
|
✗ |
g_list_store_remove_all (self->resolution_list); |
495 |
|
✗ |
g_list_store_append (self->resolution_list, current_mode); |
496 |
|
✗ |
adw_combo_row_set_selected (ADW_COMBO_ROW (self->resolution_row), 0); |
497 |
|
✗ |
for (item = modes; item != NULL; item = item->next) |
498 |
|
|
{ |
499 |
|
|
gint ins; |
500 |
|
|
gint w, h; |
501 |
|
✗ |
CcDisplayMode *mode = CC_DISPLAY_MODE (item->data); |
502 |
|
|
|
503 |
|
✗ |
cc_display_mode_get_resolution (mode, &w, &h); |
504 |
|
|
|
505 |
|
|
/* Find the appropriate insertion point. */ |
506 |
|
✗ |
for (ins = 0; ins < g_list_model_get_n_items (G_LIST_MODEL (self->resolution_list)); ins++) |
507 |
|
|
{ |
508 |
|
✗ |
g_autoptr(CcDisplayMode) m = NULL; |
509 |
|
|
gint cmp; |
510 |
|
|
|
511 |
|
✗ |
m = g_list_model_get_item (G_LIST_MODEL (self->resolution_list), ins); |
512 |
|
|
|
513 |
|
✗ |
cmp = sort_modes_by_area_desc (mode, m); |
514 |
|
|
/* Next item is smaller, insert at this point. */ |
515 |
|
✗ |
if (cmp < 0) |
516 |
|
✗ |
break; |
517 |
|
|
|
518 |
|
|
/* Don't insert if it is already in the list */ |
519 |
|
✗ |
if (cmp == 0) |
520 |
|
|
{ |
521 |
|
✗ |
ins = -1; |
522 |
|
✗ |
break; |
523 |
|
|
} |
524 |
|
|
} |
525 |
|
|
|
526 |
|
✗ |
if (ins >= 0) |
527 |
|
✗ |
g_list_store_insert (self->resolution_list, ins, mode); |
528 |
|
|
} |
529 |
|
|
|
530 |
|
|
|
531 |
|
|
/* Scale row is usually shown. */ |
532 |
|
✗ |
while ((child = gtk_widget_get_first_child (self->scale_bbox)) != NULL) |
533 |
|
✗ |
gtk_box_remove (GTK_BOX (self->scale_bbox), child); |
534 |
|
|
|
535 |
|
✗ |
gtk_string_list_splice (GTK_STRING_LIST (self->scale_list), |
536 |
|
|
0, |
537 |
|
|
g_list_model_get_n_items (self->scale_list), |
538 |
|
|
NULL); |
539 |
|
✗ |
scales = cc_display_mode_get_supported_scales (current_mode); |
540 |
|
✗ |
self->num_scales = scales->len; |
541 |
|
✗ |
for (i = 0; i < scales->len; i++) |
542 |
|
|
{ |
543 |
|
✗ |
g_autofree gchar *scale_str = NULL; |
544 |
|
✗ |
g_autoptr(GObject) value_object = NULL; |
545 |
|
✗ |
double scale = g_array_index (scales, double, i); |
546 |
|
|
GtkWidget *scale_btn; |
547 |
|
|
gboolean is_selected; |
548 |
|
|
|
549 |
|
|
/* ComboRow */ |
550 |
|
✗ |
scale_str = make_scale_string (scale); |
551 |
|
✗ |
is_selected = G_APPROX_VALUE (cc_display_monitor_get_scale (self->selected_output), |
552 |
|
|
scale, DBL_EPSILON); |
553 |
|
|
|
554 |
|
✗ |
gtk_string_list_append (GTK_STRING_LIST (self->scale_list), scale_str); |
555 |
|
✗ |
value_object = g_list_model_get_item (self->scale_list, i); |
556 |
|
✗ |
g_object_set_data_full (G_OBJECT (value_object), "scale", |
557 |
|
|
g_memdup2 (&scale, sizeof (double)), g_free); |
558 |
|
✗ |
if (is_selected) |
559 |
|
✗ |
adw_combo_row_set_selected (ADW_COMBO_ROW (self->scale_combo_row), |
560 |
|
✗ |
g_list_model_get_n_items (G_LIST_MODEL (self->scale_list)) - 1); |
561 |
|
|
|
562 |
|
|
/* ButtonBox */ |
563 |
|
✗ |
scale_btn = gtk_toggle_button_new_with_label (scale_str); |
564 |
|
✗ |
gtk_toggle_button_set_group (GTK_TOGGLE_BUTTON (scale_btn), group); |
565 |
|
✗ |
g_object_set_data_full (G_OBJECT (scale_btn), "scale", |
566 |
|
|
g_memdup2 (&scale, sizeof (double)), g_free); |
567 |
|
|
|
568 |
|
✗ |
if (!group) |
569 |
|
✗ |
group = GTK_TOGGLE_BUTTON (scale_btn); |
570 |
|
✗ |
gtk_box_append (GTK_BOX (self->scale_bbox), scale_btn); |
571 |
|
|
/* Set active before connecting the signal */ |
572 |
|
✗ |
if (is_selected) |
573 |
|
✗ |
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (scale_btn), TRUE); |
574 |
|
|
|
575 |
|
✗ |
g_signal_connect_object (scale_btn, |
576 |
|
|
"notify::active", |
577 |
|
|
G_CALLBACK (on_scale_btn_active_changed_cb), |
578 |
|
|
self, G_CONNECT_SWAPPED); |
579 |
|
|
} |
580 |
|
✗ |
cc_display_settings_refresh_layout (self, self->collapsed); |
581 |
|
|
|
582 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->underscanning_row), |
583 |
|
✗ |
cc_display_monitor_supports_underscanning (self->selected_output) && |
584 |
|
✗ |
!cc_display_config_is_cloning (self->config)); |
585 |
|
✗ |
adw_switch_row_set_active (self->underscanning_row, |
586 |
|
|
cc_display_monitor_get_underscanning (self->selected_output)); |
587 |
|
|
|
588 |
|
✗ |
self->updating = TRUE; |
589 |
|
✗ |
g_object_thaw_notify ((GObject*) self->enabled_row); |
590 |
|
✗ |
g_object_thaw_notify ((GObject*) self->orientation_row); |
591 |
|
✗ |
g_object_thaw_notify ((GObject*) self->refresh_rate_row); |
592 |
|
✗ |
g_object_thaw_notify ((GObject*) self->refresh_rate_expander_row); |
593 |
|
✗ |
g_object_thaw_notify ((GObject*) self->variable_refresh_rate_row); |
594 |
|
✗ |
g_object_thaw_notify ((GObject*) self->preferred_refresh_rate_row); |
595 |
|
✗ |
g_object_thaw_notify ((GObject*) self->resolution_row); |
596 |
|
✗ |
g_object_thaw_notify ((GObject*) self->scale_combo_row); |
597 |
|
✗ |
g_object_thaw_notify ((GObject*) self->underscanning_row); |
598 |
|
✗ |
self->updating = FALSE; |
599 |
|
|
|
600 |
|
✗ |
return G_SOURCE_REMOVE; |
601 |
|
|
} |
602 |
|
|
|
603 |
|
|
static void |
604 |
|
✗ |
on_output_changed_cb (CcDisplaySettings *self, |
605 |
|
|
GParamSpec *pspec, |
606 |
|
|
CcDisplayMonitor *output) |
607 |
|
|
{ |
608 |
|
|
/* Do this frmo an idle handler, because otherwise we may create an |
609 |
|
|
* infinite loop triggering the notify::selected-index from the |
610 |
|
|
* combo rows. */ |
611 |
|
✗ |
if (self->idle_udpate_id) |
612 |
|
✗ |
return; |
613 |
|
|
|
614 |
|
✗ |
self->idle_udpate_id = g_idle_add ((GSourceFunc) cc_display_settings_rebuild_ui, self); |
615 |
|
|
} |
616 |
|
|
|
617 |
|
|
static void |
618 |
|
✗ |
on_enabled_row_active_changed_cb (CcDisplaySettings *self) |
619 |
|
|
{ |
620 |
|
✗ |
if (self->updating) |
621 |
|
✗ |
return; |
622 |
|
|
|
623 |
|
✗ |
cc_display_monitor_set_active (self->selected_output, |
624 |
|
|
adw_switch_row_get_active (self->enabled_row)); |
625 |
|
|
|
626 |
|
✗ |
g_signal_emit_by_name (G_OBJECT (self), "updated", self->selected_output); |
627 |
|
|
} |
628 |
|
|
|
629 |
|
|
static void |
630 |
|
✗ |
on_orientation_selection_changed_cb (CcDisplaySettings *self) |
631 |
|
|
{ |
632 |
|
|
gint idx; |
633 |
|
✗ |
g_autoptr(GObject) obj = NULL; |
634 |
|
|
|
635 |
|
✗ |
if (self->updating) |
636 |
|
✗ |
return; |
637 |
|
|
|
638 |
|
✗ |
idx = adw_combo_row_get_selected (ADW_COMBO_ROW (self->orientation_row)); |
639 |
|
✗ |
obj = g_list_model_get_item (G_LIST_MODEL (self->orientation_list), idx); |
640 |
|
|
|
641 |
|
✗ |
if (!obj) |
642 |
|
✗ |
return; |
643 |
|
|
|
644 |
|
✗ |
cc_display_monitor_set_rotation (self->selected_output, |
645 |
|
✗ |
GPOINTER_TO_INT (g_object_get_data (G_OBJECT (obj), "rotation-value"))); |
646 |
|
|
|
647 |
|
✗ |
g_signal_emit_by_name (G_OBJECT (self), "updated", self->selected_output); |
648 |
|
|
} |
649 |
|
|
|
650 |
|
|
static void |
651 |
|
✗ |
on_refresh_rate_selection_changed_cb (CcDisplaySettings *self) |
652 |
|
|
{ |
653 |
|
|
gint idx; |
654 |
|
✗ |
g_autoptr(CcDisplayMode) mode = NULL; |
655 |
|
|
|
656 |
|
✗ |
if (self->updating) |
657 |
|
✗ |
return; |
658 |
|
|
|
659 |
|
✗ |
idx = adw_combo_row_get_selected (ADW_COMBO_ROW (self->refresh_rate_row)); |
660 |
|
✗ |
mode = g_list_model_get_item (G_LIST_MODEL (self->refresh_rate_list), idx); |
661 |
|
|
|
662 |
|
✗ |
if (!mode) |
663 |
|
✗ |
return; |
664 |
|
|
|
665 |
|
✗ |
cc_display_monitor_set_mode (self->selected_output, mode); |
666 |
|
|
|
667 |
|
✗ |
g_signal_emit_by_name (G_OBJECT (self), "updated", self->selected_output); |
668 |
|
|
} |
669 |
|
|
|
670 |
|
|
static void |
671 |
|
✗ |
on_variable_refresh_rate_active_changed_cb (CcDisplaySettings *self) |
672 |
|
|
{ |
673 |
|
✗ |
if (self->updating) |
674 |
|
✗ |
return; |
675 |
|
|
|
676 |
|
✗ |
if (!adw_switch_row_get_active (self->variable_refresh_rate_row)) |
677 |
|
|
{ |
678 |
|
✗ |
cc_display_monitor_set_refresh_rate_mode (self->selected_output, |
679 |
|
|
MODE_REFRESH_RATE_MODE_FIXED); |
680 |
|
|
} |
681 |
|
|
else |
682 |
|
|
{ |
683 |
|
✗ |
cc_display_monitor_set_refresh_rate_mode (self->selected_output, |
684 |
|
|
MODE_REFRESH_RATE_MODE_VARIABLE); |
685 |
|
|
} |
686 |
|
|
|
687 |
|
✗ |
g_signal_emit_by_name (G_OBJECT (self), "updated", self->selected_output); |
688 |
|
|
} |
689 |
|
|
|
690 |
|
|
static void |
691 |
|
✗ |
on_resolution_selection_changed_cb (CcDisplaySettings *self) |
692 |
|
|
{ |
693 |
|
|
gint idx; |
694 |
|
✗ |
g_autoptr(CcDisplayMode) mode = NULL; |
695 |
|
|
|
696 |
|
✗ |
if (self->updating) |
697 |
|
✗ |
return; |
698 |
|
|
|
699 |
|
✗ |
idx = adw_combo_row_get_selected (ADW_COMBO_ROW (self->resolution_row)); |
700 |
|
✗ |
mode = g_list_model_get_item (G_LIST_MODEL (self->resolution_list), idx); |
701 |
|
|
|
702 |
|
✗ |
if (!mode) |
703 |
|
✗ |
return; |
704 |
|
|
|
705 |
|
|
/* This is the only row that can be changed when in cloning mode. */ |
706 |
|
✗ |
if (!cc_display_config_is_cloning (self->config)) |
707 |
|
✗ |
cc_display_monitor_set_mode (self->selected_output, mode); |
708 |
|
|
else |
709 |
|
✗ |
cc_display_config_set_mode_on_all_outputs (self->config, mode); |
710 |
|
|
|
711 |
|
✗ |
g_signal_emit_by_name (G_OBJECT (self), "updated", self->selected_output); |
712 |
|
|
} |
713 |
|
|
|
714 |
|
|
static void |
715 |
|
✗ |
on_scale_btn_active_changed_cb (CcDisplaySettings *self, |
716 |
|
|
GParamSpec *pspec, |
717 |
|
|
GtkWidget *widget) |
718 |
|
|
{ |
719 |
|
|
gdouble scale; |
720 |
|
✗ |
if (self->updating) |
721 |
|
✗ |
return; |
722 |
|
|
|
723 |
|
✗ |
if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) |
724 |
|
✗ |
return; |
725 |
|
|
|
726 |
|
✗ |
scale = *(gdouble*) g_object_get_data (G_OBJECT (widget), "scale"); |
727 |
|
✗ |
cc_display_monitor_set_scale (self->selected_output, |
728 |
|
|
scale); |
729 |
|
|
|
730 |
|
✗ |
g_signal_emit_by_name (G_OBJECT (self), "updated", self->selected_output); |
731 |
|
|
} |
732 |
|
|
|
733 |
|
|
static void |
734 |
|
✗ |
on_scale_selection_changed_cb (CcDisplaySettings *self) |
735 |
|
|
{ |
736 |
|
|
int idx; |
737 |
|
|
double scale; |
738 |
|
✗ |
g_autoptr(GObject) obj = NULL; |
739 |
|
|
|
740 |
|
✗ |
if (self->updating) |
741 |
|
✗ |
return; |
742 |
|
|
|
743 |
|
✗ |
idx = adw_combo_row_get_selected (ADW_COMBO_ROW (self->scale_combo_row)); |
744 |
|
✗ |
obj = g_list_model_get_item (G_LIST_MODEL (self->scale_list), idx); |
745 |
|
✗ |
if (!obj) |
746 |
|
✗ |
return; |
747 |
|
✗ |
scale = *(gdouble*) g_object_get_data (G_OBJECT (obj), "scale"); |
748 |
|
|
|
749 |
|
✗ |
cc_display_monitor_set_scale (self->selected_output, scale); |
750 |
|
|
|
751 |
|
✗ |
g_signal_emit_by_name (G_OBJECT (self), "updated", self->selected_output); |
752 |
|
|
} |
753 |
|
|
|
754 |
|
|
static void |
755 |
|
✗ |
on_underscanning_row_active_changed_cb (CcDisplaySettings *self) |
756 |
|
|
{ |
757 |
|
✗ |
if (self->updating) |
758 |
|
✗ |
return; |
759 |
|
|
|
760 |
|
✗ |
cc_display_monitor_set_underscanning (self->selected_output, |
761 |
|
|
adw_switch_row_get_active (self->underscanning_row)); |
762 |
|
|
|
763 |
|
✗ |
g_signal_emit_by_name (G_OBJECT (self), "updated", self->selected_output); |
764 |
|
|
} |
765 |
|
|
|
766 |
|
|
static void |
767 |
|
✗ |
cc_display_settings_get_property (GObject *object, |
768 |
|
|
guint prop_id, |
769 |
|
|
GValue *value, |
770 |
|
|
GParamSpec *pspec) |
771 |
|
|
{ |
772 |
|
✗ |
CcDisplaySettings *self = CC_DISPLAY_SETTINGS (object); |
773 |
|
|
|
774 |
|
✗ |
switch (prop_id) |
775 |
|
|
{ |
776 |
|
✗ |
case PROP_HAS_ACCELEROMETER: |
777 |
|
✗ |
g_value_set_boolean (value, cc_display_settings_get_has_accelerometer (self)); |
778 |
|
✗ |
break; |
779 |
|
|
|
780 |
|
✗ |
case PROP_CONFIG: |
781 |
|
✗ |
g_value_set_object (value, self->config); |
782 |
|
✗ |
break; |
783 |
|
|
|
784 |
|
✗ |
case PROP_SELECTED_OUTPUT: |
785 |
|
✗ |
g_value_set_object (value, self->selected_output); |
786 |
|
✗ |
break; |
787 |
|
|
|
788 |
|
✗ |
default: |
789 |
|
✗ |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
790 |
|
|
} |
791 |
|
✗ |
} |
792 |
|
|
|
793 |
|
|
static void |
794 |
|
✗ |
cc_display_settings_set_property (GObject *object, |
795 |
|
|
guint prop_id, |
796 |
|
|
const GValue *value, |
797 |
|
|
GParamSpec *pspec) |
798 |
|
|
{ |
799 |
|
✗ |
CcDisplaySettings *self = CC_DISPLAY_SETTINGS (object); |
800 |
|
|
|
801 |
|
✗ |
switch (prop_id) |
802 |
|
|
{ |
803 |
|
✗ |
case PROP_HAS_ACCELEROMETER: |
804 |
|
✗ |
cc_display_settings_set_has_accelerometer (self, g_value_get_boolean (value)); |
805 |
|
✗ |
break; |
806 |
|
|
|
807 |
|
✗ |
case PROP_CONFIG: |
808 |
|
✗ |
cc_display_settings_set_config (self, g_value_get_object (value)); |
809 |
|
✗ |
break; |
810 |
|
|
|
811 |
|
✗ |
case PROP_SELECTED_OUTPUT: |
812 |
|
✗ |
cc_display_settings_set_selected_output (self, g_value_get_object (value)); |
813 |
|
✗ |
break; |
814 |
|
|
|
815 |
|
✗ |
default: |
816 |
|
✗ |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
817 |
|
|
} |
818 |
|
✗ |
} |
819 |
|
|
|
820 |
|
|
static void |
821 |
|
✗ |
cc_display_settings_finalize (GObject *object) |
822 |
|
|
{ |
823 |
|
✗ |
CcDisplaySettings *self = CC_DISPLAY_SETTINGS (object); |
824 |
|
|
|
825 |
|
✗ |
g_clear_object (&self->config); |
826 |
|
|
|
827 |
|
✗ |
g_clear_object (&self->orientation_list); |
828 |
|
✗ |
g_clear_object (&self->refresh_rate_list); |
829 |
|
✗ |
g_clear_object (&self->resolution_list); |
830 |
|
✗ |
g_clear_object (&self->scale_list); |
831 |
|
|
|
832 |
|
✗ |
g_clear_handle_id (&self->idle_udpate_id, g_source_remove); |
833 |
|
|
|
834 |
|
✗ |
G_OBJECT_CLASS (cc_display_settings_parent_class)->finalize (object); |
835 |
|
✗ |
} |
836 |
|
|
|
837 |
|
|
static void |
838 |
|
✗ |
cc_display_settings_class_init (CcDisplaySettingsClass *klass) |
839 |
|
|
{ |
840 |
|
✗ |
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
841 |
|
✗ |
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); |
842 |
|
|
|
843 |
|
✗ |
gobject_class->finalize = cc_display_settings_finalize; |
844 |
|
✗ |
gobject_class->get_property = cc_display_settings_get_property; |
845 |
|
✗ |
gobject_class->set_property = cc_display_settings_set_property; |
846 |
|
|
|
847 |
|
✗ |
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/display/cc-display-settings.ui"); |
848 |
|
|
|
849 |
|
✗ |
props[PROP_HAS_ACCELEROMETER] = |
850 |
|
✗ |
g_param_spec_boolean ("has-accelerometer", "Has Accelerometer", |
851 |
|
|
"If an accelerometre is available for the builtin display", |
852 |
|
|
FALSE, |
853 |
|
|
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); |
854 |
|
|
|
855 |
|
✗ |
props[PROP_CONFIG] = |
856 |
|
✗ |
g_param_spec_object ("config", "Display Config", |
857 |
|
|
"The display configuration to work with", |
858 |
|
|
CC_TYPE_DISPLAY_CONFIG, |
859 |
|
|
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); |
860 |
|
|
|
861 |
|
✗ |
props[PROP_SELECTED_OUTPUT] = |
862 |
|
✗ |
g_param_spec_object ("selected-output", "Selected Output", |
863 |
|
|
"The output that is currently selected on the configuration", |
864 |
|
|
CC_TYPE_DISPLAY_MONITOR, |
865 |
|
|
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); |
866 |
|
|
|
867 |
|
✗ |
g_object_class_install_properties (gobject_class, |
868 |
|
|
PROP_LAST, |
869 |
|
|
props); |
870 |
|
|
|
871 |
|
✗ |
g_signal_new ("updated", |
872 |
|
|
CC_TYPE_DISPLAY_SETTINGS, |
873 |
|
|
G_SIGNAL_RUN_LAST, |
874 |
|
|
0, NULL, NULL, NULL, |
875 |
|
|
G_TYPE_NONE, 1, CC_TYPE_DISPLAY_MONITOR); |
876 |
|
|
|
877 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcDisplaySettings, enabled_listbox); |
878 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcDisplaySettings, enabled_row); |
879 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcDisplaySettings, orientation_row); |
880 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcDisplaySettings, refresh_rate_row); |
881 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcDisplaySettings, refresh_rate_expander_row); |
882 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcDisplaySettings, refresh_rate_expander_suffix_label); |
883 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcDisplaySettings, variable_refresh_rate_row); |
884 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcDisplaySettings, preferred_refresh_rate_row); |
885 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcDisplaySettings, resolution_row); |
886 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcDisplaySettings, scale_bbox); |
887 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcDisplaySettings, scale_buttons_row); |
888 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcDisplaySettings, scale_combo_row); |
889 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcDisplaySettings, underscanning_row); |
890 |
|
|
|
891 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, on_enabled_row_active_changed_cb); |
892 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, on_orientation_selection_changed_cb); |
893 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, on_refresh_rate_selection_changed_cb); |
894 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, on_variable_refresh_rate_active_changed_cb); |
895 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, on_resolution_selection_changed_cb); |
896 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, on_scale_selection_changed_cb); |
897 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, on_underscanning_row_active_changed_cb); |
898 |
|
✗ |
} |
899 |
|
|
|
900 |
|
|
static void |
901 |
|
✗ |
cc_display_settings_init (CcDisplaySettings *self) |
902 |
|
|
{ |
903 |
|
|
GtkExpression *expression; |
904 |
|
|
|
905 |
|
✗ |
gtk_widget_init_template (GTK_WIDGET (self)); |
906 |
|
|
|
907 |
|
✗ |
self->orientation_list = G_LIST_MODEL (gtk_string_list_new (NULL)); |
908 |
|
✗ |
self->refresh_rate_list = g_list_store_new (CC_TYPE_DISPLAY_MODE); |
909 |
|
✗ |
self->resolution_list = g_list_store_new (CC_TYPE_DISPLAY_MODE); |
910 |
|
✗ |
self->scale_list = G_LIST_MODEL (gtk_string_list_new (NULL)); |
911 |
|
|
|
912 |
|
✗ |
self->updating = TRUE; |
913 |
|
|
|
914 |
|
✗ |
adw_combo_row_set_model (ADW_COMBO_ROW (self->orientation_row), |
915 |
|
✗ |
G_LIST_MODEL (self->orientation_list)); |
916 |
|
✗ |
adw_combo_row_set_model (ADW_COMBO_ROW (self->scale_combo_row), |
917 |
|
✗ |
G_LIST_MODEL (self->scale_list)); |
918 |
|
|
|
919 |
|
✗ |
expression = gtk_cclosure_expression_new (G_TYPE_STRING, |
920 |
|
|
NULL, 0, NULL, |
921 |
|
|
G_CALLBACK (make_refresh_rate_string), |
922 |
|
|
self, NULL); |
923 |
|
✗ |
adw_combo_row_set_expression (ADW_COMBO_ROW (self->refresh_rate_row), expression); |
924 |
|
✗ |
adw_combo_row_set_model (ADW_COMBO_ROW (self->refresh_rate_row), |
925 |
|
✗ |
G_LIST_MODEL (self->refresh_rate_list)); |
926 |
|
|
|
927 |
|
✗ |
adw_combo_row_set_expression (self->preferred_refresh_rate_row, expression); |
928 |
|
✗ |
adw_combo_row_set_model (self->preferred_refresh_rate_row, |
929 |
|
✗ |
G_LIST_MODEL (self->refresh_rate_list)); |
930 |
|
|
|
931 |
|
✗ |
g_object_bind_property_full (self->preferred_refresh_rate_row, |
932 |
|
|
"selected-item", |
933 |
|
✗ |
self->refresh_rate_expander_suffix_label, |
934 |
|
|
"label", |
935 |
|
|
G_BINDING_DEFAULT, |
936 |
|
|
(GBindingTransformFunc) mode_to_refresh_rate_transform_func, |
937 |
|
|
NULL, self, NULL); |
938 |
|
|
|
939 |
|
✗ |
expression = gtk_cclosure_expression_new (G_TYPE_STRING, |
940 |
|
|
NULL, 0, NULL, |
941 |
|
|
G_CALLBACK (make_resolution_string), |
942 |
|
|
self, NULL); |
943 |
|
✗ |
adw_combo_row_set_expression (ADW_COMBO_ROW (self->resolution_row), expression); |
944 |
|
✗ |
adw_combo_row_set_model (ADW_COMBO_ROW (self->resolution_row), |
945 |
|
✗ |
G_LIST_MODEL (self->resolution_list)); |
946 |
|
|
|
947 |
|
✗ |
self->updating = FALSE; |
948 |
|
✗ |
} |
949 |
|
|
|
950 |
|
|
CcDisplaySettings* |
951 |
|
✗ |
cc_display_settings_new (void) |
952 |
|
|
{ |
953 |
|
✗ |
return g_object_new (CC_TYPE_DISPLAY_SETTINGS, |
954 |
|
|
NULL); |
955 |
|
|
} |
956 |
|
|
|
957 |
|
|
gboolean |
958 |
|
✗ |
cc_display_settings_get_has_accelerometer (CcDisplaySettings *settings) |
959 |
|
|
{ |
960 |
|
✗ |
return settings->has_accelerometer; |
961 |
|
|
} |
962 |
|
|
|
963 |
|
|
void |
964 |
|
✗ |
cc_display_settings_set_has_accelerometer (CcDisplaySettings *self, |
965 |
|
|
gboolean has_accelerometer) |
966 |
|
|
{ |
967 |
|
✗ |
self->has_accelerometer = has_accelerometer; |
968 |
|
|
|
969 |
|
✗ |
cc_display_settings_rebuild_ui (self); |
970 |
|
✗ |
g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CONFIG]); |
971 |
|
✗ |
} |
972 |
|
|
|
973 |
|
|
CcDisplayConfig* |
974 |
|
✗ |
cc_display_settings_get_config (CcDisplaySettings *self) |
975 |
|
|
{ |
976 |
|
✗ |
return self->config; |
977 |
|
|
} |
978 |
|
|
|
979 |
|
|
void |
980 |
|
✗ |
cc_display_settings_set_config (CcDisplaySettings *self, |
981 |
|
|
CcDisplayConfig *config) |
982 |
|
|
{ |
983 |
|
✗ |
const gchar *signals[] = { "rotation", "mode", "scale", "is-usable", "active" }; |
984 |
|
|
GList *outputs, *l; |
985 |
|
|
guint i; |
986 |
|
|
|
987 |
|
✗ |
if (self->config) |
988 |
|
|
{ |
989 |
|
✗ |
outputs = cc_display_config_get_monitors (self->config); |
990 |
|
✗ |
for (l = outputs; l; l = l->next) |
991 |
|
|
{ |
992 |
|
✗ |
CcDisplayMonitor *output = l->data; |
993 |
|
|
|
994 |
|
✗ |
g_signal_handlers_disconnect_by_data (output, self); |
995 |
|
|
} |
996 |
|
|
} |
997 |
|
✗ |
g_clear_object (&self->config); |
998 |
|
|
|
999 |
|
✗ |
self->config = g_object_ref (config); |
1000 |
|
|
|
1001 |
|
|
/* Listen to all the signals */ |
1002 |
|
✗ |
if (self->config) |
1003 |
|
|
{ |
1004 |
|
✗ |
outputs = cc_display_config_get_monitors (self->config); |
1005 |
|
✗ |
for (l = outputs; l; l = l->next) |
1006 |
|
|
{ |
1007 |
|
✗ |
CcDisplayMonitor *output = l->data; |
1008 |
|
|
|
1009 |
|
✗ |
for (i = 0; i < G_N_ELEMENTS (signals); ++i) |
1010 |
|
✗ |
g_signal_connect_object (output, signals[i], G_CALLBACK (on_output_changed_cb), self, G_CONNECT_SWAPPED); |
1011 |
|
|
} |
1012 |
|
|
} |
1013 |
|
|
|
1014 |
|
✗ |
cc_display_settings_set_selected_output (self, NULL); |
1015 |
|
|
|
1016 |
|
✗ |
g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CONFIG]); |
1017 |
|
✗ |
} |
1018 |
|
|
|
1019 |
|
|
CcDisplayMonitor* |
1020 |
|
✗ |
cc_display_settings_get_selected_output (CcDisplaySettings *self) |
1021 |
|
|
{ |
1022 |
|
✗ |
return self->selected_output; |
1023 |
|
|
} |
1024 |
|
|
|
1025 |
|
|
void |
1026 |
|
✗ |
cc_display_settings_set_selected_output (CcDisplaySettings *self, |
1027 |
|
|
CcDisplayMonitor *output) |
1028 |
|
|
{ |
1029 |
|
✗ |
self->selected_output = output; |
1030 |
|
|
|
1031 |
|
✗ |
adw_expander_row_set_expanded (self->refresh_rate_expander_row, FALSE); |
1032 |
|
|
|
1033 |
|
✗ |
cc_display_settings_rebuild_ui (self); |
1034 |
|
|
|
1035 |
|
✗ |
g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SELECTED_OUTPUT]); |
1036 |
|
✗ |
} |
1037 |
|
|
|
1038 |
|
|
void |
1039 |
|
✗ |
cc_display_settings_refresh_layout (CcDisplaySettings *self, |
1040 |
|
|
gboolean collapsed) |
1041 |
|
|
{ |
1042 |
|
|
gboolean use_combo; |
1043 |
|
|
|
1044 |
|
✗ |
self->collapsed = collapsed; |
1045 |
|
✗ |
use_combo = self->num_scales > MAX_SCALE_BUTTONS || (self->num_scales > 2 && collapsed); |
1046 |
|
|
|
1047 |
|
✗ |
gtk_widget_set_visible (self->scale_combo_row, use_combo); |
1048 |
|
✗ |
gtk_widget_set_visible (self->scale_buttons_row, self->num_scales > 1 && !use_combo); |
1049 |
|
✗ |
} |
1050 |
|
|
|
1051 |
|
|
void |
1052 |
|
✗ |
cc_display_settings_set_multimonitor (CcDisplaySettings *self, |
1053 |
|
|
gboolean multimonitor) |
1054 |
|
|
{ |
1055 |
|
✗ |
gtk_widget_set_visible (self->enabled_listbox, multimonitor); |
1056 |
|
|
|
1057 |
|
✗ |
if (!multimonitor) |
1058 |
|
✗ |
adw_switch_row_set_active (self->enabled_row, TRUE); |
1059 |
|
✗ |
} |
1060 |
|
|
|