Merge lp:~unity-team/unity/multiple-monitor-support into lp:unity

Proposed by Neil J. Patel
Status: Merged
Merged at revision: 539
Proposed branch: lp:~unity-team/unity/multiple-monitor-support
Merge into: lp:unity
Diff against target: 378 lines (+130/-55)
6 files modified
targets/mutter/Makefile.am (+1/-0)
targets/mutter/expose-manager.vala (+22/-15)
targets/mutter/main.c (+5/-5)
targets/mutter/plugin.vala (+101/-31)
targets/mutter/spaces-manager.vala (+1/-1)
unity-private/testing/background.vala (+0/-3)
To merge this branch: bzr merge lp:~unity-team/unity/multiple-monitor-support
Reviewer Review Type Date Requested Status
Mirco Müller (community) Approve
Review via email: mp+35937@code.launchpad.net

Description of the change

This adds some support for multi monitor setups. It basically makes Unity stick to screen 0, which is because it's currently not possible to have a left-edge panel on a monitor that isn't monitor 0.

We can fix that during the natty cycle, but at least this let's you use your other monitors somewhat normally :)

To post a comment you must log in.
Revision history for this message
Mirco Müller (macslow) :
review: Needs Resubmitting
Revision history for this message
Mirco Müller (macslow) wrote :

Code is ok. But I'm missing a way to test it on a real multi-monitor setup (using xrandr).

review: Approve
Revision history for this message
Jason Smith (jassmith) wrote :

+1 looks good

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'targets/mutter/Makefile.am'
2--- targets/mutter/Makefile.am 2010-08-18 13:53:39 +0000
3+++ targets/mutter/Makefile.am 2010-09-19 17:17:45 +0000
4@@ -43,6 +43,7 @@
5 --pkg Dbusmenu-Glib-0.2 \
6 --pkg dee-1.0 \
7 --pkg gtk+-2.0 \
8+ --pkg gdk-x11-2.0 \
9 --pkg gee-1.0 \
10 --pkg indicator \
11 --pkg mutter-2.28 \
12
13=== modified file 'targets/mutter/expose-manager.vala'
14--- targets/mutter/expose-manager.vala 2010-08-24 12:02:16 +0000
15+++ targets/mutter/expose-manager.vala 2010-09-19 17:17:45 +0000
16@@ -260,12 +260,12 @@
17 private ExposeClone? last_selected_clone = null;
18
19
20- public ExposeManager (Plugin plugin, Launcher.Launcher launcher)
21+ public ExposeManager (Plugin owner, Launcher.Launcher launcher)
22 {
23 this.launcher = launcher;
24- this.owner = plugin;
25+ this.owner = owner;
26 this.exposed_windows = new List<ExposeClone> ();
27- this.stage = (Clutter.Stage)plugin.get_stage ();
28+ this.stage = (Clutter.Stage)owner.get_stage ();
29
30 hovered_opacity = 255;
31 unhovered_opacity = 255;
32@@ -394,23 +394,23 @@
33 {
34 Clutter.Actor last = null;
35
36- int middle_size = (int) (stage.width * 0.8f);
37- int width = (int) stage.width - left_buffer - right_buffer;
38+ int middle_size = (int) (owner.primary_monitor.width * 0.8f);
39+ int width = (int) owner.primary_monitor.width - left_buffer - right_buffer;
40 int slice_width = width / 10;
41
42- int middle_y = (int) stage.height / 2;
43+ int middle_y = (int) owner.primary_monitor.height / 2;
44 int middle_x = left_buffer + width / 2;
45
46 int middle_index = windows.index (active);
47
48- float scale = float.min (1f, (stage.height / 2) / float.max (active.height, active.width));
49+ float scale = float.min (1f, (owner.primary_monitor.height / 2) / float.max (active.height, active.width));
50 scale = 1f;
51
52 active.set_anchor_point_from_gravity (Clutter.Gravity.CENTER);
53 active.animate (Clutter.AnimationMode.EASE_IN_OUT_SINE, 250,
54 "x", (float) middle_x,
55 "y", (float) middle_y,
56- "depth", stage.width * -0.7,
57+ "depth", owner.primary_monitor.width * -0.7,
58 "scale-x", scale,
59 "scale-y", scale,
60 "rotation-angle-y", 0f);
61@@ -425,13 +425,13 @@
62 actor.set_anchor_point_from_gravity (Clutter.Gravity.CENTER);
63 actor.lower (last);
64
65- scale = float.min (1f, (stage.height / 2) / float.max (actor.height, actor.width));
66+ scale = float.min (1f, (owner.primary_monitor.height / 2) / float.max (actor.height, actor.width));
67 scale = 1f;
68
69 actor.animate (Clutter.AnimationMode.EASE_IN_OUT_SINE, 250,
70 "x", (float) current_x,
71 "y", (float) middle_y,
72- "depth", stage.width * -0.7,
73+ "depth", owner.primary_monitor.width * -0.7,
74 "scale-x", scale,
75 "scale-y", scale,
76 "rotation-angle-y", 60f);
77@@ -448,13 +448,13 @@
78 actor.set_anchor_point_from_gravity (Clutter.Gravity.CENTER);
79 actor.lower (last);
80
81- scale = float.min (1f, (stage.height / 2) / float.max (actor.height, actor.width));
82+ scale = float.min (1f, (owner.primary_monitor.height / 2) / float.max (actor.height, actor.width));
83 scale = 1f;
84
85 actor.animate (Clutter.AnimationMode.EASE_IN_OUT_SINE, 250,
86 "x", (float) current_x,
87 "y", (float) middle_y,
88- "depth", stage.width * -0.7,
89+ "depth", owner.primary_monitor.width * -0.7,
90 "scale-x", scale,
91 "scale-y", scale,
92 "rotation-angle-y", -60f);
93@@ -474,25 +474,32 @@
94
95 public void position_windows_on_grid (List<Clutter.Actor> _windows, int top_buffer, int left_buffer, int right_buffer, int bottom_buffer)
96 {
97+ if (_windows.length () < 1)
98+ {
99+ warning ("There are no windows to position on grid");
100+ return;
101+ }
102+
103 List<Clutter.Actor> windows = _windows.copy ();
104 windows.sort ((CompareFunc) direct_comparison);
105
106 int count = (int) windows.length ();
107 int cols = (int) Math.ceil (Math.sqrt (count));
108+ if (cols < 1) cols = 1;
109 int rows = 1;
110
111 while (cols * rows < count)
112 rows++;
113
114- int boxWidth = (int) ((stage.width - left_buffer - right_buffer) / cols);
115- int boxHeight = (int) ((stage.height - top_buffer - bottom_buffer) / rows);
116+ int boxWidth = (int) ((owner.primary_monitor.width - left_buffer - right_buffer) / cols);
117+ int boxHeight = (int) ((owner.primary_monitor.height - top_buffer - bottom_buffer) / rows);
118
119 for (int row = 0; row < rows; row++)
120 {
121 if (row == rows - 1)
122 {
123 /* Last row, time to perform centering as needed */
124- boxWidth = (int) ((stage.width - left_buffer - right_buffer) / windows.length ());
125+ boxWidth = (int) ((owner.primary_monitor.width - left_buffer - right_buffer) / windows.length ());
126 }
127
128 for (int col = 0; col < cols; col++)
129
130=== modified file 'targets/mutter/main.c'
131--- targets/mutter/main.c 2010-07-20 13:07:00 +0000
132+++ targets/mutter/main.c 2010-09-19 17:17:45 +0000
133@@ -174,16 +174,16 @@
134 rects = g_new (XRectangle, 2);
135
136 /* Panel first */
137- rects[0].x = 0;
138- rects[0].y = 0;
139- rects[0].width = width;
140+ rects[0].x = plugin->primary_monitor.x;
141+ rects[0].y = plugin->primary_monitor.y;
142+ rects[0].width = plugin->primary_monitor.width;
143 rects[0].height = unity_plugin_get_panel_height (plugin);
144
145 /* Launcher */
146- rects[1].x = 0;
147+ rects[1].x = plugin->primary_monitor.y;
148 rects[1].y = rects[0].height;
149 rects[1].width = unity_plugin_get_launcher_width (plugin) + 1;
150- rects[1].height = height - rects[0].height;
151+ rects[1].height = plugin->primary_monitor.height - rects[0].height;
152
153 /* Update region */
154 region = XFixesCreateRegion (xdisplay, rects, 2);
155
156=== modified file 'targets/mutter/plugin.vala'
157--- targets/mutter/plugin.vala 2010-09-16 17:37:19 +0000
158+++ targets/mutter/plugin.vala 2010-09-19 17:17:45 +0000
159@@ -108,8 +108,7 @@
160 }
161
162 public ExposeManager expose_manager { get; private set; }
163- public Background background { get; private set; }
164-
165+
166 public bool menus_swallow_events { get { return false; } }
167
168 private bool _super_key_active = false;
169@@ -125,6 +124,9 @@
170 private static const int QUICKLAUNCHER_WIDTH = 58;
171 private static const string UNDECORATED_HINT = "UNDECORATED_HINT";
172
173+ public Gee.ArrayList<Background> backgrounds;
174+ public Gdk.Rectangle primary_monitor;
175+
176 private Clutter.Stage stage;
177 private Application app;
178 private WindowManagement wm;
179@@ -231,6 +233,8 @@
180 this.wm = new WindowManagement (this);
181 this.maximus = new Maximus ();
182
183+ (Clutter.Stage.get_default () as Clutter.Stage).color = { 0, 0, 0, 255 };
184+
185 END_FUNCTION ();
186 }
187
188@@ -286,10 +290,13 @@
189 super_key_modifier_press (keysym);
190 });
191
192- this.background = new Background ();
193- this.stage.add_actor (background);
194- this.background.lower_bottom ();
195- this.background.show ();
196+ /* Setup the backgrounds */
197+ unowned Gdk.Screen screen = Gdk.Screen.get_default ();
198+ backgrounds = new Gee.ArrayList<Background> ();
199+
200+ /* Connect to interestng signals */
201+ screen.monitors_changed.connect (relayout);
202+ screen.size_changed.connect (relayout);
203
204 this.launcher = new Launcher.Launcher (this);
205 this.launcher.get_view ().opacity = 0;
206@@ -453,41 +460,97 @@
207 }
208 }
209
210+ private void refresh_n_backgrounds (int n_monitors)
211+ {
212+ int size = backgrounds.size;
213+
214+ if (size == n_monitors)
215+ return;
216+ else if (size < n_monitors)
217+ {
218+ for (int i = 0; i < n_monitors - size; i++)
219+ {
220+ var bg = new Background ();
221+ backgrounds.add (bg);
222+ stage.add_actor (bg);
223+ bg.lower_bottom ();
224+ bg.opacity = 0;
225+ bg.show ();
226+ bg.animate (Clutter.AnimationMode.EASE_IN_QUAD, 2000,
227+ "opacity", 255);
228+ }
229+ }
230+ else
231+ {
232+ for (int i = 0; i < size - n_monitors; i++)
233+ {
234+ var bg = backgrounds.get (0);
235+ if (bg is Clutter.Actor)
236+ {
237+ backgrounds.remove (bg);
238+ stage.remove_actor (bg);
239+ }
240+ }
241+ }
242+ }
243 private void relayout ()
244 {
245 START_FUNCTION ();
246- float width, height;
247-
248- this.stage.get_size (out width, out height);
249-
250- this.drag_dest.resize (this.QUICKLAUNCHER_WIDTH,
251- (int)height - this.PANEL_HEIGHT);
252- this.drag_dest.move (0, this.PANEL_HEIGHT);
253-
254- this.background.set_size (width, height);
255- this.background.set_position (0, 0);
256+
257+ unowned Gdk.Screen screen = Gdk.Screen.get_default ();
258+ int x, y, width, height;
259+
260+ /* Figure out what should be the right size and location of Unity */
261+ /* FIXME: This needs to always be monitor 0 right now as it doesn't
262+ * seem possible to have panels on a vertical edge of a monitor unless
263+ * it's the first or last monitor :(
264+ */
265+ screen.get_monitor_geometry (0, // Should be screen.get_primary_monitor()
266+ out primary_monitor);
267+ x = primary_monitor.x;
268+ y = primary_monitor.y;
269+ width = primary_monitor.width;
270+ height = primary_monitor.height;
271+
272+ /* The drag-n-drop region */
273+ drag_dest.resize (QUICKLAUNCHER_WIDTH,
274+ height - PANEL_HEIGHT);
275+ drag_dest.move (x, y + PANEL_HEIGHT);
276+
277+ /* We're responsible for painting the backgrounds on all the monitors */
278+ refresh_n_backgrounds (screen.get_n_monitors ());
279+ for (int i = 0; i < screen.get_n_monitors (); i++)
280+ {
281+ var bg = backgrounds.get (i);
282+ if (bg is Background)
283+ {
284+ Gdk.Rectangle rect;
285+ screen.get_monitor_geometry (i, out rect);
286+
287+ bg.set_position (rect.x, rect.y);
288+ bg.set_size (rect.width, rect.height);
289+ }
290+ }
291
292 this.launcher.get_container ().set_size (this.QUICKLAUNCHER_WIDTH,
293 (height-this.PANEL_HEIGHT));
294- this.launcher.get_container ().set_position (0, this.PANEL_HEIGHT);
295+ this.launcher.get_container ().set_position (x, y + this.PANEL_HEIGHT);
296 this.launcher.get_container ().set_clip (0, 0,
297 this.QUICKLAUNCHER_WIDTH,
298 height-this.PANEL_HEIGHT);
299+
300 Utils.set_strut ((Gtk.Window)this.drag_dest,
301- this.QUICKLAUNCHER_WIDTH, 0, (uint32)height,
302- PANEL_HEIGHT, 0, (uint32)width);
303+ this.QUICKLAUNCHER_WIDTH, y, (uint32)height,
304+ PANEL_HEIGHT, x, (uint32)width);
305
306 this.places.set_size (width - this.QUICKLAUNCHER_WIDTH, height);
307- this.places.set_position (this.QUICKLAUNCHER_WIDTH, 0);
308-
309- this.panel.set_size (width, 24);
310- this.panel.set_position (0, 0);
311-
312- /* Leaving this here to remind me that we need to use these when
313- * there are fullscreen windows etc
314- * this.plugin.set_stage_input_region (uint region);
315- * this.plugin.set_stage_reactive (true);
316- */
317+ this.places.set_position (x + this.QUICKLAUNCHER_WIDTH, y);
318+
319+ this.panel.set_size (width, PANEL_HEIGHT);
320+ this.panel.set_position (x, y);
321+
322+ ensure_input_region ();
323+
324 END_FUNCTION ();
325 }
326
327@@ -686,8 +749,8 @@
328 (this.plugin.get_window_group () as Clutter.Container).add_actor (this.dark_box);
329 this.dark_box.raise (plugin.get_normal_window_group ());
330
331- this.dark_box.set_position (0, 0);
332- this.dark_box.set_size (this.stage.width, this.stage.height);
333+ this.dark_box.set_position (primary_monitor.x, primary_monitor.y);
334+ this.dark_box.set_size (primary_monitor.width, primary_monitor.height);
335
336 this.dark_box.show ();
337
338@@ -1426,6 +1489,13 @@
339 return false;
340 });
341 }
342+ else if (window.get_window_type () == Mutter.MetaCompWindowType.DOCK)
343+ {
344+ if (win.get_xwindow (win) == Gdk.x11_drawable_get_xid (drag_dest.window))
345+ {
346+ window.opacity = 0;
347+ }
348+ }
349
350 this.maximus.process_window (window);
351 this.window_mapped (this, window);
352
353=== modified file 'targets/mutter/spaces-manager.vala'
354--- targets/mutter/spaces-manager.vala 2010-08-26 17:08:21 +0000
355+++ targets/mutter/spaces-manager.vala 2010-09-19 17:17:45 +0000
356@@ -370,7 +370,7 @@
357 }
358 }
359
360- ExposeClone background_clone = new ExposeClone (plugin.background);
361+ ExposeClone background_clone = new ExposeClone (plugin.backgrounds.get (0));
362 background_clone.fade_on_close = false;
363
364 wsp.add_actor (background_clone);
365
366=== modified file 'unity-private/testing/background.vala'
367--- unity-private/testing/background.vala 2010-08-26 15:14:33 +0000
368+++ unity-private/testing/background.vala 2010-09-19 17:17:45 +0000
369@@ -156,9 +156,6 @@
370 this.bg_texture.show ();
371 }
372
373- this.x = 0.0f;
374- this.y = 0.0f;
375-
376 this.gbg.get_color (out type, out primary, out secondary);
377
378 this.bg_texture.set_surface_size ((uint) this.width,