Merge lp:~tombeckmann/switchboard-plug-display/mutter-dbus into lp:~elementary-apps/switchboard-plug-display/trunk
- mutter-dbus
- Merge into trunk
Proposed by
Tom Beckmann
Status: | Work in progress |
---|---|
Proposed branch: | lp:~tombeckmann/switchboard-plug-display/mutter-dbus |
Merge into: | lp:~elementary-apps/switchboard-plug-display/trunk |
Diff against target: |
969 lines (+886/-7) 6 files modified
src/CMakeLists.txt (+7/-2) src/Configuration.vala (+14/-5) src/MutterDisplayConfig.vala (+103/-0) src/crtc-assignment.c (+677/-0) src/crtc-assignment.h (+45/-0) vapi/crtc-assignment.vapi (+40/-0) |
To merge this branch: | bzr merge lp:~tombeckmann/switchboard-plug-display/mutter-dbus |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
elementary Apps team | Pending | ||
Review via email: mp+245371@code.launchpad.net |
Commit message
Description of the change
This branch aims to fix the issue with multimonitors resetting after a gala restart by calling mutter's dbus directly instead of using xrandr via gnome-desktop. This fix won't be necessary once we get a more recent version of libgnome-desktop, however backports aren't planned for this lib for Freya, so this branch would be a requirement for Freya.
To post a comment you must log in.
Unmerged revisions
- 79. By Tom Beckmann
-
various fixes, may work now
- 78. By Tom Beckmann
-
clean up gnome-desktop file to prevent conflicts, add actual integration
- 77. By Tom Beckmann
-
prepare call to mutter dbus for applying
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'src/CMakeLists.txt' |
2 | --- src/CMakeLists.txt 2014-07-30 00:58:06 +0000 |
3 | +++ src/CMakeLists.txt 2014-12-25 21:32:50 +0000 |
4 | @@ -18,6 +18,7 @@ |
5 | DisplayPlug.vala |
6 | DisplayPopover.vala |
7 | Monitor.vala |
8 | + MutterDisplayConfig.vala |
9 | OutputList.vala |
10 | SettingsDaemon.vala |
11 | Utils.vala |
12 | @@ -29,13 +30,17 @@ |
13 | clutter-1.0 |
14 | gnome-desktop-3.0 |
15 | gdk-x11-3.0 |
16 | + crtc-assignment |
17 | OPTIONS |
18 | --thread |
19 | --vapidir=${CMAKE_SOURCE_DIR}/vapi |
20 | ) |
21 | |
22 | -add_library (${CMAKE_PROJECT_NAME} MODULE ${VALA_C}) |
23 | +include_directories (${CMAKE_SOURCE_DIR}/src) |
24 | +add_definitions (-w -g) |
25 | + |
26 | +add_library (${CMAKE_PROJECT_NAME} MODULE ${VALA_C} crtc-assignment.c) |
27 | target_link_libraries (${CMAKE_PROJECT_NAME} ${DEPS_LIBRARIES}) |
28 | |
29 | # Installation |
30 | -install (TARGETS ${CMAKE_PROJECT_NAME} DESTINATION ${PKGDATADIR}) |
31 | \ No newline at end of file |
32 | +install (TARGETS ${CMAKE_PROJECT_NAME} DESTINATION ${PKGDATADIR}) |
33 | |
34 | === modified file 'src/Configuration.vala' |
35 | --- src/Configuration.vala 2014-07-29 17:45:48 +0000 |
36 | +++ src/Configuration.vala 2014-12-25 21:32:50 +0000 |
37 | @@ -15,6 +15,8 @@ |
38 | public Gnome.RRScreen screen { get; private set; } |
39 | public Gnome.RRConfig current_config { get; private set; } |
40 | |
41 | + MutterWMHelper mutter_wm_helper; |
42 | + |
43 | SettingsDaemon? settings_daemon = null; |
44 | private Configuration () { |
45 | try { |
46 | @@ -24,6 +26,8 @@ |
47 | report_error (e.message); |
48 | } |
49 | |
50 | + mutter_wm_helper = new MutterWMHelper (); |
51 | + |
52 | try { |
53 | settings_daemon = get_settings_daemon (); |
54 | } catch (Error e) { |
55 | @@ -68,13 +72,18 @@ |
56 | apply_state_changed (false); |
57 | current_config.sanitize (); |
58 | current_config.ensure_primary (); |
59 | + print ("BLAH BLAH\n"); |
60 | |
61 | #if !HAS_GNOME312 |
62 | try { |
63 | - var other_screen = new Gnome.RRScreen (Gdk.Screen.get_default ()); |
64 | - var other_config = new Gnome.RRConfig.current (other_screen); |
65 | - other_config.ensure_primary (); |
66 | - other_config.save (); |
67 | + if (mutter_wm_helper.supported) { |
68 | + mutter_wm_helper.apply_config (current_config, screen); |
69 | + } else { |
70 | + var other_screen = new Gnome.RRScreen (Gdk.Screen.get_default ()); |
71 | + var other_config = new Gnome.RRConfig.current (other_screen); |
72 | + other_config.ensure_primary (); |
73 | + other_config.save (); |
74 | + } |
75 | } catch (Error e) {} |
76 | #endif |
77 | |
78 | @@ -183,4 +192,4 @@ |
79 | |
80 | update_outputs (current_config); |
81 | } |
82 | -} |
83 | \ No newline at end of file |
84 | +} |
85 | |
86 | === added file 'src/MutterDisplayConfig.vala' |
87 | --- src/MutterDisplayConfig.vala 1970-01-01 00:00:00 +0000 |
88 | +++ src/MutterDisplayConfig.vala 2014-12-25 21:32:50 +0000 |
89 | @@ -0,0 +1,103 @@ |
90 | + |
91 | +public struct CrtcConfig |
92 | +{ |
93 | + uint id; |
94 | + int new_mode; |
95 | + int x; |
96 | + int y; |
97 | + uint transform; |
98 | + uint[] outputs; |
99 | + HashTable<string, Variant> properties; |
100 | +} |
101 | + |
102 | +public struct OutputConfig |
103 | +{ |
104 | + uint id; |
105 | + HashTable<string, Variant> properties; |
106 | +} |
107 | + |
108 | +[DBus (name = "org.gnome.Mutter.DisplayConfig")] |
109 | +public interface MutterDisplayConfig : Object |
110 | +{ |
111 | + [DBus (signature = "ua(uxiiiiiuaua{sv})a(uxiausauaua{sv})a(uxuud)ii")] |
112 | + public abstract Variant get_resources () throws Error; |
113 | + public abstract void apply_configuration (uint serial, bool persistent, CrtcConfig[] crtcs, OutputConfig[] outputs) throws Error; |
114 | +} |
115 | + |
116 | +public class MutterWMHelper : Object |
117 | +{ |
118 | + public bool supported { get; private set; default = false; } |
119 | + |
120 | + MutterDisplayConfig mutter_proxy; |
121 | + |
122 | + public MutterWMHelper () |
123 | + { |
124 | + try { |
125 | + mutter_proxy = Bus.get_proxy_sync (BusType.SESSION, |
126 | + "org.pantheon.gala", "/org/gnome/Mutter/DisplayConfig"); |
127 | + } catch (Error e) { |
128 | + return; |
129 | + } |
130 | + |
131 | + supported = mutter_proxy != null; |
132 | + } |
133 | + |
134 | + public void apply_config (Gnome.RRConfig config, Gnome.RRScreen screen) |
135 | + { |
136 | + CrtcAssignment assignment; |
137 | + Gnome.RRCrtc crtc; |
138 | + CrtcInfo info; |
139 | + CrtcConfig[] crtcs = {}; |
140 | + OutputConfig[] outputs = {}; |
141 | + |
142 | + var mutter_info = mutter_proxy.get_resources (); |
143 | + var serial = mutter_info.get_uint32 (); |
144 | + |
145 | + try { |
146 | + get_crtc_assignment (config, screen, out assignment); |
147 | + } catch (Error e) { |
148 | + warning (e.message); |
149 | + return; |
150 | + } |
151 | + |
152 | + if (assignment == null) { |
153 | + return; |
154 | + } |
155 | + |
156 | + var iter = HashTableIter<Gnome.RRCrtc,CrtcInfo?> (assignment.info); |
157 | + while (iter.next (out crtc, out info)) { |
158 | + uint[] output_list = {}; |
159 | + |
160 | + for (var i = 0; i < info.outputs.len; i++) { |
161 | + output_list += ((Gnome.RROutput) info.outputs.index (i)).get_id (); |
162 | + } |
163 | + |
164 | + crtcs += CrtcConfig () { |
165 | + id = crtc.get_id (), |
166 | + new_mode = info.mode != null ? (int) info.mode.get_id () : -1, |
167 | + x = info.x, |
168 | + y = info.y, |
169 | + transform = rotation_to_transform (info.rotation), |
170 | + outputs = output_list, |
171 | + properties = null |
172 | + }; |
173 | + } |
174 | + |
175 | + for (var i = 0; assignment.outputs[i] != null; i++) { |
176 | + var output = assignment.outputs[i]; |
177 | + var rr_output = screen.get_output_by_name (output.get_name ()); |
178 | + var properties = new HashTable<string,Variant> (direct_hash, direct_equal); |
179 | + |
180 | + properties.@set ("primary", output.get_primary ()); |
181 | + properties.@set ("presentation", false); |
182 | + |
183 | + outputs += OutputConfig () { |
184 | + id = rr_output.get_id (), |
185 | + properties = properties |
186 | + }; |
187 | + } |
188 | + |
189 | + mutter_proxy.apply_configuration (serial, true, crtcs, outputs); |
190 | + } |
191 | +} |
192 | + |
193 | |
194 | === added file 'src/crtc-assignment.c' |
195 | --- src/crtc-assignment.c 1970-01-01 00:00:00 +0000 |
196 | +++ src/crtc-assignment.c 2014-12-25 21:32:50 +0000 |
197 | @@ -0,0 +1,677 @@ |
198 | +/* gnome-rr-config.c |
199 | + * -*- c-basic-offset: 4 -*- |
200 | + * |
201 | + * Copyright 2007, 2008, 2013 Red Hat, Inc. |
202 | + * Copyright 2010 Giovanni Campagna <scampa.giovanni@gmail.com> |
203 | + * |
204 | + * This file is part of the Gnome Library. |
205 | + * |
206 | + * The Gnome Library is free software; you can redistribute it and/or |
207 | + * modify it under the terms of the GNU Library General Public License as |
208 | + * published by the Free Software Foundation; either version 2 of the |
209 | + * License, or (at your option) any later version. |
210 | + * |
211 | + * The Gnome Library is distributed in the hope that it will be useful, |
212 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
213 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
214 | + * Library General Public License for more details. |
215 | + * |
216 | + * You should have received a copy of the GNU Library General Public |
217 | + * License along with the Gnome Library; see the file COPYING.LIB. If not, |
218 | + * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
219 | + * Boston, MA 02110-1301, USA. |
220 | + * |
221 | + * Author: Soren Sandmann <sandmann@redhat.com> |
222 | + */ |
223 | + |
224 | +#define GNOME_DESKTOP_USE_UNSTABLE_API |
225 | + |
226 | +#include <glib/gi18n-lib.h> |
227 | +#include <stdlib.h> |
228 | +#include <string.h> |
229 | +#include <glib.h> |
230 | +#include <glib/gstdio.h> |
231 | + |
232 | +#include <X11/Xlib.h> |
233 | +#include <gdk/gdkx.h> |
234 | + |
235 | +#include "crtc-assignment.h" |
236 | + |
237 | +//#include "edid.h" |
238 | + |
239 | +#define CONFIG_INTENDED_BASENAME "monitors.xml" |
240 | +#define CONFIG_BACKUP_BASENAME "monitors.xml.backup" |
241 | + |
242 | +/* Look for DPI_FALLBACK in: |
243 | + * http://git.gnome.org/browse/gnome-settings-daemon/tree/plugins/xsettings/gsd-xsettings-manager.c |
244 | + * for the reasoning */ |
245 | +#define DPI_FALLBACK 96.0 |
246 | + |
247 | +/* In version 0 of the config file format, we had several <configuration> |
248 | + * toplevel elements and no explicit version number. So, the filed looked |
249 | + * like |
250 | + * |
251 | + * <configuration> |
252 | + * ... |
253 | + * </configuration> |
254 | + * <configuration> |
255 | + * ... |
256 | + * </configuration> |
257 | + * |
258 | + * Since version 1 of the config file, the file has a toplevel <monitors> |
259 | + * element to group all the configurations. That element has a "version" |
260 | + * attribute which is an integer. So, the file looks like this: |
261 | + * |
262 | + * <monitors version="1"> |
263 | + * <configuration> |
264 | + * ... |
265 | + * </configuration> |
266 | + * <configuration> |
267 | + * ... |
268 | + * </configuration> |
269 | + * </monitors> |
270 | + */ |
271 | + |
272 | +/** |
273 | + * some things copied from gnome-rr-private.h |
274 | + * |
275 | + * copying the entire file didn't seem very useful as it included |
276 | + * a bunch of things that we don't need |
277 | + */ |
278 | +struct _GnomeRRConfigPrivate |
279 | +{ |
280 | + gboolean clone; |
281 | + GnomeRRScreen *screen; |
282 | + GnomeRROutputInfo **outputs; |
283 | +}; |
284 | +struct _GnomeRROutputInfoPrivate |
285 | +{ |
286 | + char * name; |
287 | + |
288 | + gboolean on; |
289 | + int width; |
290 | + int height; |
291 | + int rate; |
292 | + int x; |
293 | + int y; |
294 | + GnomeRRRotation rotation; |
295 | + GnomeRRRotation available_rotations; |
296 | + |
297 | + gboolean connected; |
298 | + char * vendor; |
299 | + char * product; |
300 | + char * serial; |
301 | + double aspect; |
302 | + int pref_width; |
303 | + int pref_height; |
304 | + char * display_name; |
305 | + gboolean primary; |
306 | +}; |
307 | + |
308 | +static gboolean crtc_assignment_apply (CrtcAssignment *assign, |
309 | + gboolean persistent, |
310 | + GError **error); |
311 | +static CrtcAssignment *crtc_assignment_new (GnomeRRScreen *screen, |
312 | + GnomeRROutputInfo **outputs, |
313 | + GError **error); |
314 | + |
315 | +static GnomeRROutputInfo ** |
316 | +make_outputs (GnomeRRConfig *config) |
317 | +{ |
318 | + GPtrArray *outputs; |
319 | + GnomeRROutputInfo *first_on; |
320 | + int i; |
321 | + |
322 | + outputs = g_ptr_array_new (); |
323 | + |
324 | + first_on = NULL; |
325 | + |
326 | + for (i = 0; config->priv->outputs[i] != NULL; ++i) |
327 | + { |
328 | + GnomeRROutputInfo *old = config->priv->outputs[i]; |
329 | + GnomeRROutputInfo *new = g_object_new (GNOME_TYPE_RR_OUTPUT_INFO, NULL); |
330 | + *(new->priv) = *(old->priv); |
331 | + if (old->priv->name) |
332 | + new->priv->name = g_strdup (old->priv->name); |
333 | + if (old->priv->display_name) |
334 | + new->priv->display_name = g_strdup (old->priv->display_name); |
335 | + |
336 | + if (old->priv->on && !first_on) |
337 | + first_on = old; |
338 | + |
339 | + if (config->priv->clone && new->priv->on) |
340 | + { |
341 | + g_assert (first_on); |
342 | + |
343 | + new->priv->width = first_on->priv->width; |
344 | + new->priv->height = first_on->priv->height; |
345 | + new->priv->rotation = first_on->priv->rotation; |
346 | + new->priv->x = 0; |
347 | + new->priv->y = 0; |
348 | + } |
349 | + |
350 | + g_ptr_array_add (outputs, new); |
351 | + } |
352 | + |
353 | + g_ptr_array_add (outputs, NULL); |
354 | + |
355 | + return (GnomeRROutputInfo **)g_ptr_array_free (outputs, FALSE); |
356 | +} |
357 | + |
358 | +gboolean |
359 | +get_crtc_assignment (GnomeRRConfig *config, |
360 | + GnomeRRScreen *screen, |
361 | + CrtcAssignment *assignment, |
362 | + GError **error) |
363 | +{ |
364 | + GnomeRROutputInfo **outputs; |
365 | + gboolean result = FALSE; |
366 | + int i; |
367 | + |
368 | + g_return_val_if_fail (GNOME_IS_RR_CONFIG (config), FALSE); |
369 | + g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), FALSE); |
370 | + |
371 | + outputs = make_outputs (config); |
372 | + |
373 | + assignment = crtc_assignment_new (screen, outputs, error); |
374 | + |
375 | + if (assignment) |
376 | + { |
377 | + return TRUE; |
378 | + } |
379 | + |
380 | + for (i = 0; outputs[i] != NULL; i++) |
381 | + g_object_unref (outputs[i]); |
382 | + g_free (outputs); |
383 | + |
384 | + return FALSE; |
385 | +} |
386 | + |
387 | + |
388 | +/* |
389 | + * CRTC assignment |
390 | + */ |
391 | + |
392 | +static gboolean |
393 | +can_clone (CrtcInfo *info, |
394 | + GnomeRROutput *output) |
395 | +{ |
396 | + int i; |
397 | + |
398 | + for (i = 0; i < info->outputs->len; ++i) |
399 | + { |
400 | + GnomeRROutput *clone = info->outputs->pdata[i]; |
401 | + |
402 | + if (!gnome_rr_output_can_clone (clone, output)) |
403 | + return FALSE; |
404 | + } |
405 | + |
406 | + return TRUE; |
407 | +} |
408 | + |
409 | +static gboolean |
410 | +crtc_assignment_assign (CrtcAssignment *assign, |
411 | + GnomeRRCrtc *crtc, |
412 | + GnomeRRMode *mode, |
413 | + int x, |
414 | + int y, |
415 | + GnomeRRRotation rotation, |
416 | + gboolean primary, |
417 | + GnomeRROutput *output, |
418 | + GError **error) |
419 | +{ |
420 | + CrtcInfo *info = g_hash_table_lookup (assign->info, crtc); |
421 | + guint32 crtc_id; |
422 | + const char *output_name; |
423 | + |
424 | + crtc_id = gnome_rr_crtc_get_id (crtc); |
425 | + output_name = gnome_rr_output_get_name (output); |
426 | + |
427 | + if (!gnome_rr_crtc_can_drive_output (crtc, output)) |
428 | + { |
429 | + g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_CRTC_ASSIGNMENT, |
430 | + _("CRTC %d cannot drive output %s"), crtc_id, output_name); |
431 | + return FALSE; |
432 | + } |
433 | + |
434 | + if (!gnome_rr_output_supports_mode (output, mode)) |
435 | + { |
436 | + g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_CRTC_ASSIGNMENT, |
437 | + _("output %s does not support mode %dx%d@%dHz"), |
438 | + output_name, |
439 | + gnome_rr_mode_get_width (mode), |
440 | + gnome_rr_mode_get_height (mode), |
441 | + gnome_rr_mode_get_freq (mode)); |
442 | + return FALSE; |
443 | + } |
444 | + |
445 | + if (!gnome_rr_crtc_supports_rotation (crtc, rotation)) |
446 | + { |
447 | + g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_CRTC_ASSIGNMENT, |
448 | + _("CRTC %d does not support rotation=%d"), |
449 | + crtc_id, rotation); |
450 | + return FALSE; |
451 | + } |
452 | + |
453 | + if (info) |
454 | + { |
455 | + if (!(info->mode == mode && |
456 | + info->x == x && |
457 | + info->y == y && |
458 | + info->rotation == rotation)) |
459 | + { |
460 | + g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_CRTC_ASSIGNMENT, |
461 | + _("output %s does not have the same parameters as another cloned output:\n" |
462 | + "existing mode = %d, new mode = %d\n" |
463 | + "existing coordinates = (%d, %d), new coordinates = (%d, %d)\n" |
464 | + "existing rotation = %d, new rotation = %d"), |
465 | + output_name, |
466 | + gnome_rr_mode_get_id (info->mode), gnome_rr_mode_get_id (mode), |
467 | + info->x, info->y, |
468 | + x, y, |
469 | + info->rotation, rotation); |
470 | + return FALSE; |
471 | + } |
472 | + |
473 | + if (!can_clone (info, output)) |
474 | + { |
475 | + g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_CRTC_ASSIGNMENT, |
476 | + _("cannot clone to output %s"), |
477 | + output_name); |
478 | + return FALSE; |
479 | + } |
480 | + |
481 | + g_ptr_array_add (info->outputs, output); |
482 | + |
483 | + if (primary && !assign->primary) |
484 | + { |
485 | + assign->primary = output; |
486 | + } |
487 | + |
488 | + return TRUE; |
489 | + } |
490 | + else |
491 | + { |
492 | + CrtcInfo *info = g_new0 (CrtcInfo, 1); |
493 | + |
494 | + info->mode = mode; |
495 | + info->x = x; |
496 | + info->y = y; |
497 | + info->rotation = rotation; |
498 | + info->outputs = g_ptr_array_new (); |
499 | + |
500 | + g_ptr_array_add (info->outputs, output); |
501 | + |
502 | + g_hash_table_insert (assign->info, crtc, info); |
503 | + |
504 | + if (primary && !assign->primary) |
505 | + { |
506 | + assign->primary = output; |
507 | + } |
508 | + |
509 | + return TRUE; |
510 | + } |
511 | +} |
512 | + |
513 | +static void |
514 | +crtc_assignment_unassign (CrtcAssignment *assign, |
515 | + GnomeRRCrtc *crtc, |
516 | + GnomeRROutput *output) |
517 | +{ |
518 | + CrtcInfo *info = g_hash_table_lookup (assign->info, crtc); |
519 | + |
520 | + if (info) |
521 | + { |
522 | + g_ptr_array_remove (info->outputs, output); |
523 | + |
524 | + if (assign->primary == output) |
525 | + { |
526 | + assign->primary = NULL; |
527 | + } |
528 | + |
529 | + if (info->outputs->len == 0) |
530 | + g_hash_table_remove (assign->info, crtc); |
531 | + } |
532 | +} |
533 | + |
534 | +void |
535 | +crtc_assignment_free (CrtcAssignment *assign) |
536 | +{ |
537 | + if (!assign) |
538 | + return; |
539 | + |
540 | + if (assign->info) |
541 | + g_hash_table_destroy (assign->info); |
542 | + |
543 | + g_free (assign); |
544 | +} |
545 | + |
546 | +static gboolean |
547 | +mode_is_rotated (CrtcInfo *info) |
548 | +{ |
549 | + if ((info->rotation & GNOME_RR_ROTATION_270) || |
550 | + (info->rotation & GNOME_RR_ROTATION_90)) |
551 | + { |
552 | + return TRUE; |
553 | + } |
554 | + return FALSE; |
555 | +} |
556 | + |
557 | +static void |
558 | +accumulate_error (GString *accumulated_error, GError *error) |
559 | +{ |
560 | + g_string_append_printf (accumulated_error, " %s\n", error->message); |
561 | + g_error_free (error); |
562 | +} |
563 | + |
564 | +/* Check whether the given set of settings can be used |
565 | + * at the same time -- ie. whether there is an assignment |
566 | + * of CRTC's to outputs. |
567 | + * |
568 | + * Brute force - the number of objects involved is small |
569 | + * enough that it doesn't matter. |
570 | + */ |
571 | +static gboolean |
572 | +real_assign_crtcs (GnomeRRScreen *screen, |
573 | + GnomeRROutputInfo **outputs, |
574 | + CrtcAssignment *assignment, |
575 | + GError **error) |
576 | +{ |
577 | + GnomeRRCrtc **crtcs = gnome_rr_screen_list_crtcs (screen); |
578 | + GnomeRROutputInfo *output; |
579 | + int i; |
580 | + gboolean tried_mode; |
581 | + GError *my_error; |
582 | + GString *accumulated_error; |
583 | + gboolean success; |
584 | + |
585 | + output = *outputs; |
586 | + if (!output) |
587 | + return TRUE; |
588 | + |
589 | + /* It is always allowed for an output to be turned off */ |
590 | + if (!output->priv->on) |
591 | + { |
592 | + return real_assign_crtcs (screen, outputs + 1, assignment, error); |
593 | + } |
594 | + |
595 | + success = FALSE; |
596 | + tried_mode = FALSE; |
597 | + accumulated_error = g_string_new (NULL); |
598 | + |
599 | + for (i = 0; crtcs[i] != NULL; ++i) |
600 | + { |
601 | + GnomeRRCrtc *crtc = crtcs[i]; |
602 | + int crtc_id = gnome_rr_crtc_get_id (crtc); |
603 | + int pass; |
604 | + |
605 | + g_string_append_printf (accumulated_error, |
606 | + _("Trying modes for CRTC %d\n"), |
607 | + crtc_id); |
608 | + |
609 | + /* Make two passes, one where frequencies must match, then |
610 | + * one where they don't have to |
611 | + */ |
612 | + for (pass = 0; pass < 2; ++pass) |
613 | + { |
614 | + GnomeRROutput *gnome_rr_output = gnome_rr_screen_get_output_by_name (screen, output->priv->name); |
615 | + GnomeRRMode **modes = gnome_rr_output_list_modes (gnome_rr_output); |
616 | + int j; |
617 | + |
618 | + for (j = 0; modes[j] != NULL; ++j) |
619 | + { |
620 | + GnomeRRMode *mode = modes[j]; |
621 | + int mode_width; |
622 | + int mode_height; |
623 | + int mode_freq; |
624 | + |
625 | + mode_width = gnome_rr_mode_get_width (mode); |
626 | + mode_height = gnome_rr_mode_get_height (mode); |
627 | + mode_freq = gnome_rr_mode_get_freq (mode); |
628 | + |
629 | + g_string_append_printf (accumulated_error, |
630 | + _("CRTC %d: trying mode %dx%d@%dHz with output at %dx%d@%dHz (pass %d)\n"), |
631 | + crtc_id, |
632 | + mode_width, mode_height, mode_freq, |
633 | + output->priv->width, output->priv->height, output->priv->rate, |
634 | + pass); |
635 | + |
636 | + if (mode_width == output->priv->width && |
637 | + mode_height == output->priv->height && |
638 | + (pass == 1 || mode_freq == output->priv->rate)) |
639 | + { |
640 | + tried_mode = TRUE; |
641 | + |
642 | + my_error = NULL; |
643 | + if (crtc_assignment_assign ( |
644 | + assignment, crtc, modes[j], |
645 | + output->priv->x, output->priv->y, |
646 | + output->priv->rotation, |
647 | + output->priv->primary, |
648 | + gnome_rr_output, |
649 | + &my_error)) |
650 | + { |
651 | + my_error = NULL; |
652 | + if (real_assign_crtcs (screen, outputs + 1, assignment, &my_error)) { |
653 | + success = TRUE; |
654 | + goto out; |
655 | + } else |
656 | + accumulate_error (accumulated_error, my_error); |
657 | + |
658 | + crtc_assignment_unassign (assignment, crtc, gnome_rr_output); |
659 | + } else |
660 | + accumulate_error (accumulated_error, my_error); |
661 | + } |
662 | + } |
663 | + } |
664 | + } |
665 | + |
666 | +out: |
667 | + |
668 | + if (success) |
669 | + g_string_free (accumulated_error, TRUE); |
670 | + else { |
671 | + char *str; |
672 | + |
673 | + str = g_string_free (accumulated_error, FALSE); |
674 | + |
675 | + if (tried_mode) |
676 | + g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_CRTC_ASSIGNMENT, |
677 | + _("could not assign CRTCs to outputs:\n%s"), |
678 | + str); |
679 | + else |
680 | + g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_CRTC_ASSIGNMENT, |
681 | + _("none of the selected modes were compatible with the possible modes:\n%s"), |
682 | + str); |
683 | + |
684 | + g_free (str); |
685 | + } |
686 | + |
687 | + return success; |
688 | +} |
689 | + |
690 | +void |
691 | +crtc_info_free (CrtcInfo *info) |
692 | +{ |
693 | + g_ptr_array_free (info->outputs, TRUE); |
694 | + g_free (info); |
695 | +} |
696 | + |
697 | +static void |
698 | +get_required_virtual_size (CrtcAssignment *assign, int *width, int *height) |
699 | +{ |
700 | + GList *active_crtcs = g_hash_table_get_keys (assign->info); |
701 | + GList *list; |
702 | + int d; |
703 | + |
704 | + if (!width) |
705 | + width = &d; |
706 | + if (!height) |
707 | + height = &d; |
708 | + |
709 | + /* Compute size of the screen */ |
710 | + *width = *height = 1; |
711 | + for (list = active_crtcs; list != NULL; list = list->next) |
712 | + { |
713 | + GnomeRRCrtc *crtc = list->data; |
714 | + CrtcInfo *info = g_hash_table_lookup (assign->info, crtc); |
715 | + int w, h; |
716 | + |
717 | + w = gnome_rr_mode_get_width (info->mode); |
718 | + h = gnome_rr_mode_get_height (info->mode); |
719 | + |
720 | + if (mode_is_rotated (info)) |
721 | + { |
722 | + int tmp = h; |
723 | + h = w; |
724 | + w = tmp; |
725 | + } |
726 | + |
727 | + *width = MAX (*width, info->x + w); |
728 | + *height = MAX (*height, info->y + h); |
729 | + } |
730 | + |
731 | + g_list_free (active_crtcs); |
732 | +} |
733 | + |
734 | +static CrtcAssignment * |
735 | +crtc_assignment_new (GnomeRRScreen *screen, |
736 | + GnomeRROutputInfo **outputs, |
737 | + GError **error) |
738 | +{ |
739 | + CrtcAssignment *assignment = g_new0 (CrtcAssignment, 1); |
740 | + |
741 | + assignment->outputs = outputs; |
742 | + assignment->info = g_hash_table_new_full ( |
743 | + g_direct_hash, g_direct_equal, NULL, (GFreeFunc)crtc_info_free); |
744 | + |
745 | + if (real_assign_crtcs (screen, outputs, assignment, error)) |
746 | + { |
747 | + int width, height; |
748 | + int min_width, max_width, min_height, max_height; |
749 | + |
750 | + get_required_virtual_size (assignment, &width, &height); |
751 | + |
752 | + gnome_rr_screen_get_ranges ( |
753 | + screen, &min_width, &max_width, &min_height, &max_height); |
754 | + |
755 | + if (width < min_width || width > max_width || |
756 | + height < min_height || height > max_height) |
757 | + { |
758 | + g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_BOUNDS_ERROR, |
759 | + /* Translators: the "requested", "minimum", and |
760 | + * "maximum" words here are not keywords; please |
761 | + * translate them as usual. */ |
762 | + _("required virtual size does not fit available size: " |
763 | + "requested=(%d, %d), minimum=(%d, %d), maximum=(%d, %d)"), |
764 | + width, height, |
765 | + min_width, min_height, |
766 | + max_width, max_height); |
767 | + goto fail; |
768 | + } |
769 | + |
770 | + assignment->screen = screen; |
771 | + |
772 | + return assignment; |
773 | + } |
774 | + |
775 | +fail: |
776 | + crtc_assignment_free (assignment); |
777 | + |
778 | + return NULL; |
779 | +} |
780 | + |
781 | +#define ROTATION_MASK 0x7F |
782 | + |
783 | +wl_output_transform |
784 | +rotation_to_transform (GnomeRRRotation rotation) |
785 | +{ |
786 | + static const wl_output_transform y_reflected_map[] = { |
787 | + WL_OUTPUT_TRANSFORM_FLIPPED_180, |
788 | + WL_OUTPUT_TRANSFORM_FLIPPED_90, |
789 | + WL_OUTPUT_TRANSFORM_FLIPPED, |
790 | + WL_OUTPUT_TRANSFORM_FLIPPED_270 |
791 | + }; |
792 | + wl_output_transform ret; |
793 | + |
794 | + switch (rotation & ROTATION_MASK) |
795 | + { |
796 | + default: |
797 | + case GNOME_RR_ROTATION_0: |
798 | + ret = WL_OUTPUT_TRANSFORM_NORMAL; |
799 | + break; |
800 | + case GNOME_RR_ROTATION_90: |
801 | + ret = WL_OUTPUT_TRANSFORM_90; |
802 | + break; |
803 | + case GNOME_RR_ROTATION_180: |
804 | + ret = WL_OUTPUT_TRANSFORM_180; |
805 | + break; |
806 | + case GNOME_RR_ROTATION_270: |
807 | + ret = WL_OUTPUT_TRANSFORM_270; |
808 | + break; |
809 | + } |
810 | + |
811 | + if (rotation & GNOME_RR_REFLECT_X) |
812 | + return ret + 4; |
813 | + else if (rotation & GNOME_RR_REFLECT_Y) |
814 | + return y_reflected_map[ret]; |
815 | + else |
816 | + return ret; |
817 | +} |
818 | + |
819 | +/* |
820 | +static gboolean |
821 | +crtc_assignment_apply (CrtcAssignment *assign, gboolean persistent, GError **error) |
822 | +{ |
823 | + GVariantBuilder crtc_builder, output_builder, nested_outputs; |
824 | + GHashTableIter iter; |
825 | + GnomeRRCrtc *crtc; |
826 | + CrtcInfo *info; |
827 | + unsigned i; |
828 | + |
829 | + g_variant_builder_init (&crtc_builder, G_VARIANT_TYPE ("a(uiiiuaua{sv})")); |
830 | + g_variant_builder_init (&output_builder, G_VARIANT_TYPE ("a(ua{sv})")); |
831 | + |
832 | + g_hash_table_iter_init (&iter, assign->info); |
833 | + while (g_hash_table_iter_next (&iter, (void*) &crtc, (void*) &info)) |
834 | + { |
835 | + g_variant_builder_init (&nested_outputs, G_VARIANT_TYPE ("au")); |
836 | + for (i = 0; i < info->outputs->len; i++) |
837 | + { |
838 | + GnomeRROutput *output = g_ptr_array_index (info->outputs, i); |
839 | + |
840 | + g_variant_builder_add (&nested_outputs, "u", |
841 | + gnome_rr_output_get_id (output)); |
842 | + } |
843 | + |
844 | + g_variant_builder_add (&crtc_builder, "(uiiiuaua{sv})", |
845 | + gnome_rr_crtc_get_id (crtc), |
846 | + info->mode ? |
847 | + gnome_rr_mode_get_id (info->mode) : -1, |
848 | + info->x, |
849 | + info->y, |
850 | + rotation_to_transform (info->rotation), |
851 | + &nested_outputs, |
852 | + NULL); |
853 | + } |
854 | + |
855 | + for (i = 0; assign->outputs[i]; i++) |
856 | + { |
857 | + GnomeRROutputInfo *output = assign->outputs[i]; |
858 | + GnomeRROutput *gnome_rr_output = gnome_rr_screen_get_output_by_name (assign->screen, |
859 | + output->priv->name); |
860 | + |
861 | + g_variant_builder_add (&output_builder, "(u@a{sv})", |
862 | + gnome_rr_output_get_id (gnome_rr_output), |
863 | + g_variant_new_parsed ("{ 'primary': <%b>," |
864 | + " 'presentation': <%b> }", |
865 | + output->priv->primary, |
866 | + FALSE)); |
867 | + } |
868 | + |
869 | + return _gnome_rr_screen_apply_configuration (assign->screen, |
870 | + persistent, |
871 | + g_variant_builder_end (&crtc_builder), |
872 | + g_variant_builder_end (&output_builder), |
873 | + error); |
874 | +}*/ |
875 | |
876 | === added file 'src/crtc-assignment.h' |
877 | --- src/crtc-assignment.h 1970-01-01 00:00:00 +0000 |
878 | +++ src/crtc-assignment.h 2014-12-25 21:32:50 +0000 |
879 | @@ -0,0 +1,45 @@ |
880 | +#include <gnome-desktop-3.0/libgnome-desktop/gnome-rr.h> |
881 | +#include <gnome-desktop-3.0/libgnome-desktop/gnome-rr-config.h> |
882 | + |
883 | +typedef struct CrtcAssignment CrtcAssignment; |
884 | + |
885 | +struct CrtcAssignment |
886 | +{ |
887 | + GnomeRROutputInfo **outputs; |
888 | + GnomeRRScreen *screen; |
889 | + GHashTable *info; |
890 | + GnomeRROutput *primary; |
891 | +}; |
892 | + |
893 | +typedef struct CrtcInfo CrtcInfo; |
894 | + |
895 | +struct CrtcInfo |
896 | +{ |
897 | + GnomeRRMode *mode; |
898 | + int x; |
899 | + int y; |
900 | + GnomeRRRotation rotation; |
901 | + GPtrArray *outputs; |
902 | +}; |
903 | + |
904 | +#ifdef GDK_WINDOWING_WAYLAND |
905 | +#include <gdk/gdkwayland.h> |
906 | +#else |
907 | +enum wl_output_transform { |
908 | + WL_OUTPUT_TRANSFORM_NORMAL, |
909 | + WL_OUTPUT_TRANSFORM_90, |
910 | + WL_OUTPUT_TRANSFORM_180, |
911 | + WL_OUTPUT_TRANSFORM_270, |
912 | + WL_OUTPUT_TRANSFORM_FLIPPED, |
913 | + WL_OUTPUT_TRANSFORM_FLIPPED_90, |
914 | + WL_OUTPUT_TRANSFORM_FLIPPED_180, |
915 | + WL_OUTPUT_TRANSFORM_FLIPPED_270 |
916 | +}; |
917 | +#endif |
918 | + |
919 | +typedef enum wl_output_transform wl_output_transform; |
920 | + |
921 | +void crtc_assignment_free (CrtcAssignment *assign); |
922 | +void crtc_info_free (CrtcInfo *info); |
923 | + |
924 | +gboolean get_crtc_assignment (GnomeRRConfig *config, GnomeRRScreen *screen, CrtcAssignment *assignment, GError **error); |
925 | |
926 | === added file 'vapi/crtc-assignment.vapi' |
927 | --- vapi/crtc-assignment.vapi 1970-01-01 00:00:00 +0000 |
928 | +++ vapi/crtc-assignment.vapi 2014-12-25 21:32:50 +0000 |
929 | @@ -0,0 +1,40 @@ |
930 | + |
931 | +[CCode (cheader_filename = "crtc-assignment.h")] |
932 | +public class CrtcAssignment |
933 | +{ |
934 | + [CCode (array_null_terminated = true)] |
935 | + public Gnome.RROutputInfo[] outputs; |
936 | + public Gnome.RRScreen screen; |
937 | + public GLib.HashTable<Gnome.RRCrtc,CrtcInfo?> info; |
938 | + public Gnome.RROutput primary; |
939 | +} |
940 | + |
941 | +[CCode (cheader_filename = "crtc-assignment.h", has_destroy_function = "false")] |
942 | +public struct CrtcInfo |
943 | +{ |
944 | + Gnome.RRMode mode; |
945 | + int x; |
946 | + int y; |
947 | + Gnome.RRRotation rotation; |
948 | + GLib.PtrArray outputs; |
949 | +} |
950 | + |
951 | +[CCode (cheader_filename = "crtc-assignment.h")] |
952 | +public enum wl_output_transform { |
953 | + WL_OUTPUT_TRANSFORM_NORMAL, |
954 | + WL_OUTPUT_TRANSFORM_90, |
955 | + WL_OUTPUT_TRANSFORM_180, |
956 | + WL_OUTPUT_TRANSFORM_270, |
957 | + WL_OUTPUT_TRANSFORM_FLIPPED, |
958 | + WL_OUTPUT_TRANSFORM_FLIPPED_90, |
959 | + WL_OUTPUT_TRANSFORM_FLIPPED_180, |
960 | + WL_OUTPUT_TRANSFORM_FLIPPED_270 |
961 | +} |
962 | + |
963 | +[CCode (cheader_filename = "crtc-assignment.h")] |
964 | +public bool get_crtc_assignment (Gnome.RRConfig config, |
965 | + Gnome.RRScreen screen, out CrtcAssignment assignment) throws GLib.Error; |
966 | + |
967 | +[CCode (cheader_filename = "crtc-assignment.h")] |
968 | +public wl_output_transform rotation_to_transform (Gnome.RRRotation rotation); |
969 | + |