Merge lp:~ricotz/plank/zoom into lp:plank

Proposed by Rico Tzschichholz on 2015-06-24
Status: Merged
Merged at revision: 1343
Proposed branch: lp:~ricotz/plank/zoom
Merge into: lp:plank
Diff against target: 2458 lines (+1232/-386)
13 files modified
data/ui/preferences.ui (+45/-0)
docs/Makefile.am (+1/-0)
lib/DockController.vala (+0/-2)
lib/DockPreferences.vala (+21/-0)
lib/DockRenderer.vala (+271/-185)
lib/DragManager.vala (+2/-1)
lib/Drawing/DockSurface.vala (+21/-0)
lib/Drawing/SurfaceCache.vala (+322/-0)
lib/Items/DockItem.vala (+59/-40)
lib/Makefile.am (+1/-0)
lib/PositionManager.vala (+451/-154)
lib/Widgets/DockWindow.vala (+5/-4)
lib/Widgets/PreferencesWindow.vala (+33/-0)
To merge this branch: bzr merge lp:~ricotz/plank/zoom
Reviewer Review Type Date Requested Status
Docky Core 2015-06-24 Pending
Review via email: mp+262897@code.launchpad.net

Description of the change

Add support to enable a zoom-animation while hovering the dock.

Still needs some cleaning and a more intelligent caching.
Caching icons significantly increases the memory consumption which is suppose to only take effect with enabled zoom.

Might still perform badly on your machine!

(drawing this bloody "libreoffice-writer.svg" (> 500kb) takes about 200ms)

To post a comment you must log in.
lp:~ricotz/plank/zoom updated on 2015-07-16
1328. By Rico Tzschichholz on 2015-06-27

animatedrenderer: Always initialize frame if a redraw is scheduled

1329. By Rico Tzschichholz on 2015-06-27

po: Update translations

1330. By Rico Tzschichholz on 2015-07-03

dockrenderer: Guard duration-calculations which are used for animations

1331. By Rico Tzschichholz on 2015-07-06

Update symbols

1332. By Rico Tzschichholz on 2015-07-09

color: Avoid double setting of out-vars in hsv_to_rgb

1333. By Rico Tzschichholz on 2015-07-09

color: Clarify documention of set_min/max_* methods

1334. By Rico Tzschichholz on 2015-07-09

hidemanager: Add dodge-active hide-mode

1335. By Rico Tzschichholz on 2015-07-12

prefswindow: Use Gtk.Stack if available

1337. By Rico Tzschichholz on 2015-07-12

prefswindow: Allow closing the window using "Escape"

1338. By Rico Tzschichholz on 2015-07-12

po: Update translations

1339. By Rico Tzschichholz on 2015-07-12

ui: Tweak minimum gtk+ version for conditional 3.4 support

1340. By Rico Tzschichholz on 2015-07-15

build: Make sure to enable maintainer-mode by default

1341. By Rico Tzschichholz on 2015-06-27

Add icon-zoom preferences and expose gui-settings

1342. By Rico Tzschichholz on 2015-07-02

Add optional zoom animation when hovering dock-items

1343. By Rico Tzschichholz on 2015-07-16

Add ability to cache multiple sizes of drawn items

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'data/ui/preferences.ui'
2--- data/ui/preferences.ui 2015-07-12 17:08:16 +0000
3+++ data/ui/preferences.ui 2015-07-16 08:37:41 +0000
4@@ -42,6 +42,13 @@
5 <property name="upper">2500</property>
6 <property name="step_increment">50</property>
7 </object>
8+ <object class="GtkAdjustment" id="adj_zoom_percent">
9+ <property name="lower">100</property>
10+ <property name="upper">200</property>
11+ <property name="value">150</property>
12+ <property name="step_increment">5</property>
13+ <property name="page_increment">10</property>
14+ </object>
15 <object class="GtkStack" id="dock_preferences">
16 <property name="visible">True</property>
17 <property name="can_focus">False</property>
18@@ -266,6 +273,44 @@
19 <property name="width">2</property>
20 </packing>
21 </child>
22+ <child>
23+ <object class="GtkScale" id="s_zoom_percent">
24+ <property name="visible">True</property>
25+ <property name="can_focus">True</property>
26+ <property name="adjustment">adj_zoom_percent</property>
27+ <property name="digits">0</property>
28+ <property name="value_pos">right</property>
29+ </object>
30+ <packing>
31+ <property name="left_attach">3</property>
32+ <property name="top_attach">6</property>
33+ </packing>
34+ </child>
35+ <child>
36+ <object class="GtkSwitch" id="sw_zoom_enabled">
37+ <property name="visible">True</property>
38+ <property name="can_focus">True</property>
39+ <property name="halign">start</property>
40+ <property name="valign">center</property>
41+ </object>
42+ <packing>
43+ <property name="left_attach">2</property>
44+ <property name="top_attach">6</property>
45+ </packing>
46+ </child>
47+ <child>
48+ <object class="GtkLabel" id="l_iconzoom">
49+ <property name="visible">True</property>
50+ <property name="can_focus">False</property>
51+ <property name="halign">end</property>
52+ <property name="label" translatable="yes">Icon Zoom:</property>
53+ <property name="justify">right</property>
54+ </object>
55+ <packing>
56+ <property name="left_attach">1</property>
57+ <property name="top_attach">6</property>
58+ </packing>
59+ </child>
60 </object>
61 <packing>
62 <property name="name">grid_appearance</property>
63
64=== modified file 'docs/Makefile.am'
65--- docs/Makefile.am 2015-06-04 20:24:37 +0000
66+++ docs/Makefile.am 2015-07-16 08:37:41 +0000
67@@ -33,6 +33,7 @@
68 $(top_srcdir)/lib/Drawing/DockSurface.vala \
69 $(top_srcdir)/lib/Drawing/DockTheme.vala \
70 $(top_srcdir)/lib/Drawing/Easing.vala \
71+ $(top_srcdir)/lib/Drawing/SurfaceCache.vala \
72 $(top_srcdir)/lib/Drawing/Theme.vala \
73 $(top_srcdir)/lib/Factories/AbstractMain.vala \
74 $(top_srcdir)/lib/Factories/Factory.vala \
75
76=== modified file 'lib/DockController.vala'
77--- lib/DockController.vala 2015-06-11 05:36:16 +0000
78+++ lib/DockController.vala 2015-07-16 08:37:41 +0000
79@@ -348,7 +348,6 @@
80 && added.size != removed.size) {
81 position_manager.update (renderer.theme);
82 } else {
83- position_manager.reset_item_caches ();
84 position_manager.update_regions ();
85 }
86 window.update_icon_regions ();
87@@ -362,7 +361,6 @@
88 update_visible_elements ();
89
90 foreach (unowned DockElement item in moved_items) {
91- position_manager.reset_item_cache (item);
92 unowned ApplicationDockItem? app_item = (item as ApplicationDockItem);
93 if (app_item != null)
94 window.update_icon_region (app_item);
95
96=== modified file 'lib/DockPreferences.vala'
97--- lib/DockPreferences.vala 2015-05-07 12:46:58 +0000
98+++ lib/DockPreferences.vala 2015-07-16 08:37:41 +0000
99@@ -29,6 +29,9 @@
100 public const int MIN_ICON_SIZE = 24;
101 public const int MAX_ICON_SIZE = 128;
102
103+ public const int MIN_ICON_ZOOM = 100;
104+ public const int MAX_ICON_ZOOM = 200;
105+
106 [Description(nick = "current-workspace-only", blurb = "Whether to show only windows of the current workspace.")]
107 public bool CurrentWorkspaceOnly { get; set; }
108
109@@ -80,6 +83,12 @@
110 [Description(nick = "show-dock-item", blurb = "Whether to show the item for the dock itself.")]
111 public bool ShowDockItem { get; set; }
112
113+ [Description(nick = "zoom-enabled", blurb = "Whether the dock will zoom when hovered.")]
114+ public bool ZoomEnabled { get; set; }
115+
116+ [Description(nick = "zoom-percent", blurb = "The dock's icon-zoom (in percent).")]
117+ public uint ZoomPercent { get; set; }
118+
119 /**
120 * {@inheritDoc}
121 */
122@@ -132,6 +141,8 @@
123 PinnedOnly = false;
124 AutoPinning = true;
125 ShowDockItem = true;
126+ ZoomEnabled = false;
127+ ZoomPercent = 150;
128 }
129
130 /**
131@@ -235,6 +246,16 @@
132
133 case "ShowDockItem":
134 break;
135+
136+ case "ZoomEnabled":
137+ break;
138+
139+ case "ZoomPercent":
140+ if (ZoomPercent < MIN_ICON_ZOOM)
141+ ZoomPercent = MIN_ICON_ZOOM;
142+ else if (ZoomPercent > MAX_ICON_ZOOM)
143+ ZoomPercent = MAX_ICON_ZOOM;
144+ break;
145 }
146 }
147 }
148
149=== modified file 'lib/DockRenderer.vala'
150--- lib/DockRenderer.vala 2015-07-03 20:25:11 +0000
151+++ lib/DockRenderer.vala 2015-07-16 08:37:41 +0000
152@@ -44,6 +44,18 @@
153 */
154 [CCode (notify = false)]
155 double opacity { get; private set; }
156+
157+ /**
158+ * The current progress [0.0..1.0] of the zoom-in-animation of the dock.
159+ */
160+ [CCode (notify = false)]
161+ public double zoom_in_progress { get; private set; }
162+
163+ /**
164+ * The current local cursor-position on the dock if hovered.
165+ */
166+ [CCode (notify = false)]
167+ public Gdk.Point local_cursor { get; private set; }
168
169 DockSurface? main_buffer = null;
170 DockSurface? fade_buffer = null;
171@@ -57,16 +69,19 @@
172 DockSurface? urgent_glow_buffer = null;
173
174 int64 last_hide = 0;
175+ int64 last_hovered_changed = 0;
176
177 bool screen_is_composited = false;
178 uint reset_position_manager_timer = 0;
179 int window_scale_factor = 1;
180 bool is_first_frame = true;
181+ bool zoom_changed = false;
182
183 ulong gtk_theme_name_changed_id = 0;
184
185 double dynamic_animation_offset = 0.0;
186
187+ Gee.ArrayList<unowned DockItem> current_items;
188 Gee.HashSet<DockItem> transient_items;
189 #if BENCHMARK
190 Gee.ArrayList<string> benchmark;
191@@ -86,6 +101,7 @@
192 construct
193 {
194 transient_items = new Gee.HashSet<DockItem> ();
195+ current_items = new Gee.ArrayList<unowned DockItem> ();
196 #if BENCHMARK
197 benchmark = new Gee.ArrayList<string> ();
198 #endif
199@@ -104,6 +120,7 @@
200
201 controller.window.notify["HoveredItem"].connect (animated_draw);
202 controller.hide_manager.notify["Hidden"].connect (hidden_changed);
203+ controller.hide_manager.notify["Hovered"].connect (hovered_changed);
204 }
205
206 ~DockRenderer ()
207@@ -112,6 +129,7 @@
208 theme.notify.disconnect (theme_changed);
209
210 controller.hide_manager.notify["Hidden"].disconnect (hidden_changed);
211+ controller.hide_manager.notify["Hovered"].disconnect (hovered_changed);
212 controller.window.notify["HoveredItem"].disconnect (animated_draw);
213 }
214
215@@ -221,7 +239,9 @@
216 {
217 return_if_fail (theme != null);
218
219- screen_is_composited = controller.position_manager.screen_is_composited;
220+ unowned PositionManager position_manager = controller.position_manager;
221+
222+ screen_is_composited = position_manager.screen_is_composited;
223 dynamic_animation_offset = 0.0;
224
225 var fade_opacity = theme.FadeOpacity;
226@@ -237,14 +257,78 @@
227 } else {
228 hide_progress = (controller.hide_manager.Hidden ? 1.0 : 0.0);
229 }
230+
231+ var zoom_duration = 150 * 1000;
232+ var zoom_time = int64.max (0LL, frame_time - last_hovered_changed);
233+ double zoom_progress;
234+ if (zoom_time < zoom_duration)
235+ zoom_progress = Drawing.easing_for_mode (AnimationMode.LINEAR, zoom_time, zoom_duration);
236+ else
237+ zoom_progress = 1.0;
238+ if (!controller.hide_manager.Hovered)
239+ zoom_progress = 1.0 - zoom_progress;
240+ zoom_progress *= 1.0 - hide_progress;
241+ zoom_in_progress = zoom_progress;
242 } else {
243 hide_progress = 0.0;
244+ zoom_in_progress = 0.0;
245 }
246
247 if (fade_opacity < 1.0)
248 opacity = 1.0 - (1.0 - fade_opacity) * hide_progress;
249 else
250 opacity = 1.0;
251+
252+ // Update *ordered* list of items
253+ current_items.clear ();
254+ current_items.add_all (controller.VisibleItems);
255+
256+ if (screen_is_composited) {
257+ var add_time = 0LL;
258+ var remove_time = 0LL;
259+ var move_time = 0LL;
260+ var move_duration = theme.ItemMoveTime * 1000;
261+
262+ var transient_items_it = transient_items.iterator ();
263+ while (transient_items_it.next ()) {
264+ var item = transient_items_it.get ();
265+ add_time = item.AddTime;
266+ remove_time = item.RemoveTime;
267+
268+ if (add_time > remove_time) {
269+ move_time = frame_time - add_time;
270+ if (move_time < move_duration) {
271+ if (!current_items.contains (item))
272+ current_items.add (item);
273+ } else {
274+ transient_items_it.remove ();
275+ }
276+ } else if (remove_time > 0) {
277+ move_time = frame_time - remove_time;
278+ if (move_time < move_duration) {
279+ if (!current_items.contains (item))
280+ current_items.add (item);
281+ } else {
282+ transient_items_it.remove ();
283+ }
284+ }
285+ }
286+ } else {
287+ transient_items.clear ();
288+ }
289+
290+#if HAVE_GEE_0_8
291+ current_items.sort ((CompareDataFunc) compare_dock_item_position);
292+#else
293+ current_items.sort ((CompareFunc) compare_dock_item_position);
294+#endif
295+
296+ // Calculate positions for given ordered list of items
297+ position_manager.update_draw_values (current_items,
298+ (PositionManager.DockItemDrawValueFunc) animate_draw_value_for_item,
299+ (PositionManager.DrawValuesFunc) post_process_draw_values);
300+
301+ background_rect = position_manager.get_background_region ();
302 }
303
304 /**
305@@ -262,7 +346,6 @@
306 unowned PositionManager position_manager = controller.position_manager;
307 unowned DockItem dragged_item = controller.drag_manager.DragItem;
308 var win_rect = position_manager.get_dock_window_region ();
309- var items = controller.VisibleItems;
310
311 if (main_buffer == null) {
312 main_buffer = new DockSurface.with_surface (win_rect.width, win_rect.height, cr.get_target ());
313@@ -295,7 +378,7 @@
314 cr.paint ();
315 cr.restore ();
316
317- foreach (var item in items)
318+ foreach (unowned DockItem item in current_items)
319 draw_urgent_glow (item, cr, frame_time);
320
321 return;
322@@ -320,118 +403,11 @@
323 unowned Cairo.Context item_cr = item_buffer.Context;
324 unowned Cairo.Context shadow_cr = shadow_buffer.Context;
325
326- // draw transient items onto the dock buffer and calculate the resulting
327- // dynamic-animation-offset used to animate the background-resize
328- if (screen_is_composited) {
329- var add_time = 0LL;
330- var remove_time = 0LL;
331- var move_time = 0LL;
332- var move_duration = theme.ItemMoveTime * 1000;
333-
334- var transient_items_it = transient_items.iterator ();
335- while (transient_items_it.next ()) {
336- var item = transient_items_it.get ();
337- add_time = item.AddTime;
338- remove_time = item.RemoveTime;
339-
340- if (add_time > remove_time) {
341- move_time = int64.max (0LL, frame_time - add_time);
342- if (move_time < move_duration) {
343- var move_animation_progress = 1.0 - Drawing.easing_for_mode (AnimationMode.EASE_OUT_QUINT, move_time, move_duration);
344- dynamic_animation_offset -= move_animation_progress * (position_manager.IconSize + position_manager.ItemPadding);
345- } else {
346- transient_items_it.remove ();
347- }
348- } else if (remove_time > 0) {
349- move_time = int64.max (0LL, frame_time - remove_time);
350- if (move_time < move_duration) {
351- var move_animation_progress = 1.0 - Drawing.easing_for_mode (AnimationMode.EASE_IN_QUINT, move_time, move_duration);
352- dynamic_animation_offset += move_animation_progress * (position_manager.IconSize + position_manager.ItemPadding);
353- } else {
354- transient_items_it.remove ();
355- }
356- } else {
357- continue;
358- }
359-#if BENCHMARK
360- start2 = new DateTime.now_local ();
361-#endif
362- // Do not draw the currently dragged item or items which are suppose to be drawn later
363- if (move_time < move_duration && item.IsVisible && dragged_item != item && !items.contains (item)) {
364- var draw_value = get_animated_draw_value_for_item (item, frame_time);
365- draw_item (item_cr, item, ref draw_value, frame_time);
366- draw_item_shadow (shadow_cr, item, ref draw_value);
367- }
368-#if BENCHMARK
369- end2 = new DateTime.now_local ();
370- benchmark.add ("item render time - %f ms".printf (end2.difference (start2) / 1000.0));
371-#endif
372- }
373- } else {
374- transient_items.clear ();
375- }
376-
377- background_rect = position_manager.get_background_region ();
378-
379 // calculate drawing offset
380 var x_offset = 0, y_offset = 0;
381 if (opacity == 1.0)
382 position_manager.get_dock_draw_position (out x_offset, out y_offset);
383
384- // calculate drawing animation-offset
385- var x_animation_offset = 0, y_animation_offset = 0;
386- switch (controller.prefs.Alignment) {
387- default:
388- case Gtk.Align.CENTER:
389- if (position_manager.is_horizontal_dock ())
390- x_animation_offset -= (int) Math.round (dynamic_animation_offset / 2.0);
391- else
392- y_animation_offset -= (int) Math.round (dynamic_animation_offset / 2.0);
393- background_rect = { background_rect.x + x_offset + x_animation_offset, background_rect.y + y_offset + y_animation_offset,
394- background_rect.width -2 * x_animation_offset, background_rect.height -2 * y_animation_offset };
395- break;
396- case Gtk.Align.START:
397- if (position_manager.is_horizontal_dock ())
398- background_rect = { background_rect.x + x_offset, background_rect.y + y_offset,
399- background_rect.width + (int) Math.round (dynamic_animation_offset), background_rect.height };
400- else
401- background_rect = { background_rect.x + x_offset, background_rect.y + y_offset,
402- background_rect.width, background_rect.height + (int) Math.round (dynamic_animation_offset) };
403- break;
404- case Gtk.Align.END:
405- if (position_manager.is_horizontal_dock ())
406- x_animation_offset -= (int) Math.round (dynamic_animation_offset);
407- else
408- y_animation_offset -= (int) Math.round (dynamic_animation_offset);
409- background_rect = { background_rect.x + x_offset + x_animation_offset, background_rect.y + y_offset + y_animation_offset,
410- background_rect.width - x_animation_offset, background_rect.height - y_animation_offset };
411- break;
412- case Gtk.Align.FILL:
413- switch (controller.prefs.ItemsAlignment) {
414- default:
415- case Gtk.Align.FILL:
416- case Gtk.Align.CENTER:
417- if (position_manager.is_horizontal_dock ())
418- x_animation_offset -= (int) Math.round (dynamic_animation_offset / 2.0);
419- else
420- y_animation_offset -= (int) Math.round (dynamic_animation_offset / 2.0);
421- break;
422- case Gtk.Align.START:
423- break;
424- case Gtk.Align.END:
425- if (position_manager.is_horizontal_dock ())
426- x_animation_offset -= (int) Math.round (dynamic_animation_offset);
427- else
428- y_animation_offset -= (int) Math.round (dynamic_animation_offset);
429- break;
430- }
431- background_rect = { background_rect.x + x_offset, background_rect.y + y_offset, background_rect.width, background_rect.height };
432- break;
433- }
434-
435- x_offset += x_animation_offset;
436- y_offset += y_animation_offset;
437-
438 // composite dock layers and make sure to draw onto the window's context with one operation
439 main_buffer.clear ();
440 unowned Cairo.Context main_cr = main_buffer.Context;
441@@ -441,22 +417,22 @@
442 start2 = new DateTime.now_local ();
443 #endif
444 // draw background-layer
445- draw_dock_background (main_cr, background_rect);
446+ draw_dock_background (main_cr, background_rect, x_offset, y_offset);
447 #if BENCHMARK
448 end2 = new DateTime.now_local ();
449 benchmark.add ("background render time - %f ms".printf (end2.difference (start2) / 1000.0));
450 #endif
451
452 // draw each item onto the dock buffer
453- foreach (var item in items) {
454+ foreach (unowned DockItem item in current_items) {
455 #if BENCHMARK
456 start2 = new DateTime.now_local ();
457 #endif
458 // Do not draw the currently dragged item
459 if (item.IsVisible && dragged_item != item) {
460- var draw_value = get_animated_draw_value_for_item (item, frame_time);
461- draw_item (item_cr, item, ref draw_value, frame_time);
462- draw_item_shadow (shadow_cr, item, ref draw_value);
463+ var draw_value = position_manager.get_draw_value_for_item (item);
464+ draw_item (item_cr, item, draw_value, frame_time);
465+ draw_item_shadow (shadow_cr, item, draw_value);
466 }
467 #if BENCHMARK
468 end2 = new DateTime.now_local ();
469@@ -489,7 +465,7 @@
470
471 // draw urgent-glow if dock is completely hidden
472 if (hide_progress == 1.0) {
473- foreach (var item in items)
474+ foreach (unowned DockItem item in current_items)
475 draw_urgent_glow (item, cr, frame_time);
476 }
477
478@@ -520,7 +496,7 @@
479 }
480 }
481
482- void draw_dock_background (Cairo.Context cr, Gdk.Rectangle background_rect)
483+ void draw_dock_background (Cairo.Context cr, Gdk.Rectangle background_rect, int x_offset, int y_offset)
484 {
485 unowned PositionManager position_manager = controller.position_manager;
486
487@@ -534,21 +510,20 @@
488 background_buffer = theme.create_background (background_rect.width, background_rect.height,
489 position_manager.Position, main_buffer);
490
491- cr.set_source_surface (background_buffer.Internal, background_rect.x, background_rect.y);
492+ cr.set_source_surface (background_buffer.Internal, background_rect.x + x_offset, background_rect.y + y_offset);
493 cr.paint ();
494 }
495
496- PositionManager.DockItemDrawValue get_animated_draw_value_for_item (DockItem item, int64 frame_time)
497+ [CCode (instance_pos = -1)]
498+ void animate_draw_value_for_item (DockItem item, PositionManager.DockItemDrawValue draw_value)
499 {
500 unowned PositionManager position_manager = controller.position_manager;
501 unowned DockItem hovered_item = controller.window.HoveredItem;
502 unowned DragManager drag_manager = controller.drag_manager;
503
504- var icon_size = position_manager.IconSize;
505+ var icon_size = (int) draw_value.icon_size;
506 var position = position_manager.Position;
507-
508- // get item's draw-value
509- var draw_value = position_manager.get_draw_value_for_item (item);
510+ var x_offset = 0.0, y_offset = 0.0;
511
512 // check for and calculate click-animation
513 var max_click_time = item.ClickedAnimation == Animation.BOUNCE ? theme.LaunchBounceTime : theme.ClickTime;
514@@ -564,8 +539,7 @@
515 case Animation.BOUNCE:
516 if (!screen_is_composited)
517 break;
518- var change = Math.fabs (Math.sin (2 * Math.PI * click_animation_progress) * position_manager.LaunchBounceHeight * double.min (1.0, 1.3333 * (1.0 - click_animation_progress)));
519- draw_value.move_in (position, change);
520+ y_offset += Math.fabs (Math.sin (2 * Math.PI * click_animation_progress) * position_manager.LaunchBounceHeight * double.min (1.0, 1.3333 * (1.0 - click_animation_progress)));
521 break;
522 case Animation.DARKEN:
523 draw_value.darken = double.max (0, Math.sin (Math.PI * click_animation_progress)) * 0.5;
524@@ -630,8 +604,40 @@
525 var urgent_time = int64.max (0LL, frame_time - item.LastUrgent);
526 var bounce_animation_progress = urgent_time / (double) (theme.UrgentBounceTime * 1000);
527 if (bounce_animation_progress < 1.0) {
528- var change = Math.fabs (Math.sin (Math.PI * bounce_animation_progress) * position_manager.UrgentBounceHeight * double.min (1.0, 2.0 * (1.0 - bounce_animation_progress)));
529- draw_value.move_in (position, change);
530+ y_offset += Math.fabs (Math.sin (Math.PI * bounce_animation_progress) * position_manager.UrgentBounceHeight * double.min (1.0, 2.0 * (1.0 - bounce_animation_progress)));
531+ }
532+ }
533+
534+ // animate addition/removal
535+ unowned DockContainer? container = item.Container;
536+ var allow_animation = (screen_is_composited && (container == null || container.AddTime < item.AddTime));
537+ if (allow_animation && item.AddTime > item.RemoveTime) {
538+ var move_duration = theme.ItemMoveTime * 1000;
539+ var move_time = int64.max (0LL, frame_time - item.AddTime);
540+ if (move_time < move_duration) {
541+ var move_animation_progress = 1.0 - Drawing.easing_for_mode (AnimationMode.LINEAR, move_time, move_duration);
542+ draw_value.opacity = Drawing.easing_for_mode (AnimationMode.EASE_IN_EXPO, move_time, move_duration);
543+ y_offset -= move_animation_progress * (icon_size + position_manager.BottomPadding);
544+ draw_value.show_indicator = false;
545+
546+ // calculate the resulting incremental dynamic-animation-offset used to animate the background-resize and icon-offset
547+ move_animation_progress = 1.0 - Drawing.easing_for_mode (AnimationMode.EASE_OUT_QUINT, move_time, move_duration);
548+ dynamic_animation_offset -= move_animation_progress * (icon_size + position_manager.ItemPadding);
549+ x_offset += dynamic_animation_offset;
550+ }
551+ } else if (allow_animation && item.RemoveTime > 0) {
552+ var move_duration = theme.ItemMoveTime * 1000;
553+ var move_time = int64.max (0LL, frame_time - item.RemoveTime);
554+ if (move_time < move_duration) {
555+ var move_animation_progress = Drawing.easing_for_mode (AnimationMode.LINEAR, move_time, move_duration);
556+ draw_value.opacity = 1.0 - Drawing.easing_for_mode (AnimationMode.EASE_OUT_EXPO, move_time, move_duration);
557+ y_offset -= move_animation_progress * (icon_size + position_manager.BottomPadding);
558+ draw_value.show_indicator = false;
559+
560+ // calculate the resulting incremental dynamic-animation-offset used to animate the background-resize and icon-offset
561+ move_animation_progress = 1.0 - Drawing.easing_for_mode (AnimationMode.EASE_IN_QUINT, move_time, move_duration);
562+ dynamic_animation_offset += move_animation_progress * (icon_size + position_manager.ItemPadding);
563+ x_offset += dynamic_animation_offset - (icon_size + position_manager.ItemPadding);
564 }
565 }
566
567@@ -650,37 +656,12 @@
568 move_animation_progress = 1.0 - Drawing.easing_for_mode (AnimationMode.EASE_OUT_CIRC, move_time, move_duration);
569 }
570 var change = move_animation_progress * (icon_size + position_manager.ItemPadding);
571- draw_value.move_right (position, (item.Position < item.LastPosition ? change : -change));
572+ x_offset += (item.Position < item.LastPosition ? change : -change);
573 } else {
574 item.unset_move_state ();
575 }
576 }
577
578- // animate addition/removal
579- unowned DockContainer? container = item.Container;
580- var allow_animation = (screen_is_composited && (container == null || container.AddTime < item.AddTime));
581- if (allow_animation && item.AddTime > item.RemoveTime) {
582- var move_duration = theme.ItemMoveTime * 1000;
583- var move_time = int64.max (0LL, frame_time - item.AddTime);
584- if (move_time < move_duration) {
585- var move_animation_progress = 1.0 - Drawing.easing_for_mode (AnimationMode.LINEAR, move_time, move_duration);
586- draw_value.opacity = Drawing.easing_for_mode (AnimationMode.EASE_IN_EXPO, move_time, move_duration);
587- var change = move_animation_progress * (icon_size + position_manager.BottomPadding);
588- draw_value.move_in (position, -change);
589- draw_value.show_indicator = false;
590- }
591- } else if (allow_animation && item.RemoveTime > 0) {
592- var move_duration = theme.ItemMoveTime * 1000;
593- var move_time = int64.max (0LL, frame_time - item.RemoveTime);
594- if (move_time < move_duration) {
595- var move_animation_progress = Drawing.easing_for_mode (AnimationMode.LINEAR, move_time, move_duration);
596- draw_value.opacity = 1.0 - Drawing.easing_for_mode (AnimationMode.EASE_OUT_EXPO, move_time, move_duration);
597- var change = move_animation_progress * (icon_size + position_manager.BottomPadding);
598- draw_value.move_in (position, -change);
599- draw_value.show_indicator = false;
600- }
601- }
602-
603 // animate icon on invalid state
604 if ((item.State & ItemState.INVALID) != 0) {
605 var invalid_duration = 3000 * 1000;
606@@ -692,13 +673,71 @@
607 }
608 }
609
610- return draw_value;
611- }
612-
613- void draw_item (Cairo.Context cr, DockItem item, ref PositionManager.DockItemDrawValue draw_value, int64 frame_time)
614- {
615- unowned PositionManager position_manager = controller.position_manager;
616- var icon_size = position_manager.IconSize;
617+ if (x_offset != 0.0)
618+ draw_value.move_right (position, x_offset);
619+
620+ if (y_offset != 0.0)
621+ draw_value.move_in (position, y_offset);
622+ }
623+
624+ [CCode (instance_pos = -1)]
625+ void post_process_draw_values (Gee.HashMap<DockElement, PositionManager.DockItemDrawValue?> draw_values)
626+ {
627+ if (dynamic_animation_offset == 0.0)
628+ return;
629+
630+ unowned PositionManager position_manager = controller.position_manager;
631+ var position = position_manager.Position;
632+
633+ var x_offset = 0.0;
634+
635+ switch (position_manager.Alignment) {
636+ default:
637+ case Gtk.Align.CENTER:
638+ x_offset -= Math.round (dynamic_animation_offset / 2.0);
639+ break;
640+ case Gtk.Align.START:
641+ break;
642+ case Gtk.Align.END:
643+ x_offset -= Math.round (dynamic_animation_offset);
644+ break;
645+ case Gtk.Align.FILL:
646+ switch (position_manager.ItemsAlignment) {
647+ default:
648+ case Gtk.Align.FILL:
649+ case Gtk.Align.CENTER:
650+ x_offset -= Math.round (dynamic_animation_offset / 2.0);
651+ break;
652+ case Gtk.Align.START:
653+ break;
654+ case Gtk.Align.END:
655+ x_offset -= Math.round (dynamic_animation_offset);
656+ break;
657+ }
658+ break;
659+ }
660+
661+ if (x_offset == 0.0)
662+ return;
663+
664+#if HAVE_GEE_0_8
665+ draw_values.map_iterator ().foreach ((i, val) => {
666+ val.move_right (position, x_offset);
667+ return true;
668+ });
669+#else
670+ var draw_values_it = draw_values.map_iterator ();
671+ while (draw_values_it.next ()) {
672+ var val = draw_values_it.get_value ();
673+ val.move_right (position, x_offset);
674+ }
675+#endif
676+ }
677+
678+ void draw_item (Cairo.Context cr, DockItem item, PositionManager.DockItemDrawValue draw_value, int64 frame_time)
679+ {
680+ unowned PositionManager position_manager = controller.position_manager;
681+ var icon_size = (int) draw_value.icon_size;
682 var position = position_manager.Position;
683
684 // load the icon
685@@ -710,7 +749,7 @@
686
687 DockSurface? icon_overlay_surface = null;
688 if (item.CountVisible || item.ProgressVisible)
689- icon_overlay_surface = item.get_foreground_surface (draw_item_foreground);
690+ icon_overlay_surface = item.get_foreground_surface (icon_size * window_scale_factor, icon_size * window_scale_factor, item_buffer, (DrawDataFunc<DockItem>) draw_item_foreground);
691
692 if (icon_overlay_surface != null) {
693 icon_cr.set_source_surface (icon_overlay_surface.Internal, 0, 0);
694@@ -766,15 +805,17 @@
695 draw_indicator_state (cr, draw_value.hover_region, item.Indicator, item.State);
696 }
697
698- void draw_item_shadow (Cairo.Context cr, DockItem item, ref PositionManager.DockItemDrawValue draw_value)
699+ void draw_item_shadow (Cairo.Context cr, DockItem item, PositionManager.DockItemDrawValue draw_value)
700 {
701 unowned PositionManager position_manager = controller.position_manager;
702 var shadow_size = position_manager.IconShadowSize;
703-
704+ // Inflate size to fit shadow
705+ var icon_size = (int) draw_value.icon_size + 2 * shadow_size;
706+
707 // load and draw the icon shadow
708 DockSurface? icon_shadow_surface = null;
709 if (shadow_size > 0)
710- icon_shadow_surface = item.get_background_surface (draw_item_background);
711+ icon_shadow_surface = item.get_background_surface (icon_size * window_scale_factor, icon_size * window_scale_factor, item_buffer, (DrawDataFunc<DockItem>) draw_item_background);
712
713 if (icon_shadow_surface != null) {
714 if (window_scale_factor > 1) {
715@@ -793,20 +834,13 @@
716 }
717 }
718
719- DockSurface draw_item_foreground (DockItem item, DockSurface icon_surface, DockSurface? current_surface)
720+ [CCode (instance_pos = -1)]
721+ DockSurface draw_item_foreground (int width, int height, DockSurface model, DockItem item)
722 {
723- unowned PositionManager position_manager = controller.position_manager;
724- var width = icon_surface.Width;
725- var height = icon_surface.Height;
726-
727- if (current_surface != null
728- && width == current_surface.Width && height == current_surface.Height)
729- return current_surface;
730-
731 Logger.verbose ("DockItem.draw_item_overlay (width = %i, height = %i)", width, height);
732- var surface = new DockSurface.with_dock_surface (width, height, icon_surface);
733+ var surface = new DockSurface.with_dock_surface (width, height, model);
734
735- var icon_size = position_manager.IconSize * window_scale_factor;
736+ var icon_size = int.min (width, height) * window_scale_factor;
737 var urgent_color = get_styled_color ();
738 urgent_color.add_hue (theme.UrgentHueShift);
739
740@@ -821,21 +855,18 @@
741 return surface;
742 }
743
744- DockSurface draw_item_background (DockItem item, DockSurface icon_surface, DockSurface? current_surface)
745+ [CCode (instance_pos = -1)]
746+ DockSurface draw_item_background (int width, int height, DockSurface model, DockItem item)
747 {
748 unowned PositionManager position_manager = controller.position_manager;
749 var shadow_size = position_manager.IconShadowSize * window_scale_factor;
750
751- // Inflate size to fit shadow
752- var width = icon_surface.Width + 2 * shadow_size;
753- var height = icon_surface.Height + 2 * shadow_size;
754-
755- if (current_surface != null
756- && width == current_surface.Width && height == current_surface.Height)
757- return current_surface;
758+ var draw_value = position_manager.get_draw_value_for_item (item);
759+ var icon_size = (int) draw_value.icon_size;
760+ var icon_surface = item.get_surface (icon_size, icon_size, model);
761
762 Logger.verbose ("DockItem.draw_icon_with_shadow (width = %i, height = %i, shadow_size = %i)", width, height, shadow_size);
763- var surface = new DockSurface.with_dock_surface (width, height, icon_surface);
764+ var surface = new DockSurface.with_dock_surface (width, height, model);
765 unowned Cairo.Context cr = surface.Context;
766 var shadow_surface = icon_surface.create_mask (0.4, null);
767
768@@ -976,6 +1007,35 @@
769 animated_draw ();
770 }
771
772+ void hovered_changed ()
773+ {
774+ force_frame_time_update ();
775+ var now = frame_time;
776+ var diff = now - last_hovered_changed;
777+ var time = 150 * 1000;
778+
779+ if (diff < time)
780+ last_hovered_changed = now + (diff - time);
781+ else
782+ last_hovered_changed = now;
783+
784+ animated_draw ();
785+ }
786+
787+ public void update_local_cursor (int x, int y)
788+ {
789+ Gdk.Point new_cursor = { x, y };
790+ if (local_cursor == new_cursor)
791+ return;
792+
793+ local_cursor = new_cursor;
794+
795+ if (controller.prefs.ZoomEnabled) {
796+ zoom_changed = true;
797+ animated_draw ();
798+ }
799+ }
800+
801 public void animate_items (Gee.List<DockElement> elements)
802 {
803 if (!screen_is_composited)
804@@ -995,6 +1055,15 @@
805 */
806 protected override bool animation_needed (int64 frame_time)
807 {
808+ if (zoom_changed) {
809+ //FIXME reset at a better place
810+ zoom_changed = false;
811+ return true;
812+ }
813+
814+ if (frame_time - last_hovered_changed <= 150 * 1000)
815+ return true;
816+
817 if (theme.FadeOpacity == 1.0) {
818 if (frame_time - last_hide <= theme.HideTime * 1000)
819 return true;
820@@ -1006,7 +1075,7 @@
821 if (transient_items.size > 0)
822 return true;
823
824- foreach (var item in controller.VisibleItems)
825+ foreach (var item in current_items)
826 if (item_animation_needed (item, frame_time))
827 return true;
828
829@@ -1039,5 +1108,22 @@
830
831 return false;
832 }
833+
834+ static int compare_dock_item_position (DockItem i1, DockItem i2)
835+ {
836+ var p_i1 = i1.Position;
837+ var p_i2 = i2.Position;
838+
839+ if (p_i1 > p_i2)
840+ return 1;
841+
842+ if (p_i1 < p_i2)
843+ return -1;
844+
845+ if (i1.RemoveTime > i2.RemoveTime)
846+ return -1;
847+
848+ return 1;
849+ }
850 }
851 }
852
853=== modified file 'lib/DragManager.vala'
854--- lib/DragManager.vala 2015-06-08 09:36:14 +0000
855+++ lib/DragManager.vala 2015-07-16 08:37:41 +0000
856@@ -178,7 +178,7 @@
857 #if HAVE_HIDPI
858 window_scale_factor = controller.window.get_window ().get_scale_factor ();
859 #endif
860- var drag_icon_size = (int) (1.2 * controller.position_manager.IconSize);
861+ var drag_icon_size = (int) (1.2 * controller.position_manager.ZoomIconSize);
862 if (drag_icon_size % 2 == 1)
863 drag_icon_size++;
864 #if HAVE_HIDPI
865@@ -441,6 +441,7 @@
866 Gdk.drag_status (context, Gdk.DragAction.COPY, time_);
867 }
868
869+ controller.renderer.update_local_cursor (x, y);
870 hide_manager.update_hovered ();
871 window.update_hovered (x, y);
872
873
874=== modified file 'lib/Drawing/DockSurface.vala'
875--- lib/Drawing/DockSurface.vala 2015-05-16 18:48:15 +0000
876+++ lib/Drawing/DockSurface.vala 2015-07-16 08:37:41 +0000
877@@ -125,6 +125,27 @@
878 }
879
880 /**
881+ * Create a scaled copy of the surface
882+ *
883+ * @param width the resulting width
884+ * @param height the resulting height
885+ * @return scaled copy of this surface
886+ */
887+ public DockSurface scaled_copy (int width, int height)
888+ {
889+ var result = new DockSurface.with_dock_surface (width, height, this);
890+ unowned Cairo.Context cr = result.Context;
891+
892+ cr.save ();
893+ cr.scale ((double) width / Width, (double) height / Height);
894+ cr.set_source_surface (Internal, 0, 0);
895+ cr.paint ();
896+ cr.restore ();
897+
898+ return result;
899+ }
900+
901+ /**
902 * Saves the current dock surface to a {@link Gdk.Pixbuf}.
903 *
904 * @return the {@link Gdk.Pixbuf}
905
906=== added file 'lib/Drawing/SurfaceCache.vala'
907--- lib/Drawing/SurfaceCache.vala 1970-01-01 00:00:00 +0000
908+++ lib/Drawing/SurfaceCache.vala 2015-07-16 08:37:41 +0000
909@@ -0,0 +1,322 @@
910+//
911+// Copyright (C) 2015 Rico Tzschichholz
912+//
913+// This file is part of Plank.
914+//
915+// Plank is free software: you can redistribute it and/or modify
916+// it under the terms of the GNU General Public License as published by
917+// the Free Software Foundation, either version 3 of the License, or
918+// (at your option) any later version.
919+//
920+// Plank is distributed in the hope that it will be useful,
921+// but WITHOUT ANY WARRANTY; without even the implied warranty of
922+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
923+// GNU General Public License for more details.
924+//
925+// You should have received a copy of the GNU General Public License
926+// along with this program. If not, see <http://www.gnu.org/licenses/>.
927+//
928+
929+using Plank.Services;
930+
931+namespace Plank.Drawing
932+{
933+ /**
934+ * Creates a new surface based on the given information
935+ *
936+ * @param width the width
937+ * @param height the height
938+ * @param model existing surface to use as basis of new surface
939+ * @param draw_data_func function which changes the surface
940+ * @return the newly created surface or NULL
941+ */
942+ public delegate DockSurface? DrawFunc<G> (int width, int height, DockSurface model, DrawDataFunc<G>? draw_data_func);
943+
944+ /**
945+ * Creates a new surface using the given element and information
946+ *
947+ * @param width the width
948+ * @param height the height
949+ * @param model existing surface to use as basis of new surface
950+ * @param data the data object used for drawing
951+ * @return the newly created surface or NULL
952+ */
953+ public delegate DockSurface? DrawDataFunc<G> (int width, int height, DockSurface model, G? data);
954+
955+ /**
956+ * Controls some internal behaviors of a {@link Plank.Drawing.SurfaceCache}
957+ */
958+ [Flags]
959+ public enum SurfaceCacheFlags
960+ {
961+ NONE = 0,
962+ /**
963+ * Allow down-scaling of an existing cached surface for better performance
964+ */
965+ ALLOW_DOWNSCALE = 1 << 0,
966+ /**
967+ * Allow up-scaling of an existing cached surface for better performance
968+ */
969+ ALLOW_UPSCALE = 1 << 1,
970+ /**
971+ * Allow scaling of an existing cached surface for better performance
972+ * (This basically means the cache will only contain one entry which will be scaled accordingly on request)
973+ */
974+ ALLOW_SCALE = ALLOW_UPSCALE | ALLOW_DOWNSCALE,
975+ /**
976+ * Allow scaling if the drawing-time is significatly high
977+ */
978+ ADAPTIVE_SCALE = 1 << 2,
979+ }
980+
981+ /**
982+ * Cache multiple sizes of the assumed same image
983+ */
984+ public class SurfaceCache<G> : GLib.Object
985+ {
986+ const int64 MAX_CACHE_AGE = 5 * 60 * 1000 * 1000;
987+ const int64 MIN_DRAWING_TIME = 10 * 1000;
988+ const int64 ACCESS_REWARD = 500 * 1000;
989+
990+ class SurfaceInfo
991+ {
992+ public uint16 width;
993+ public uint16 height;
994+ public uint access_count;
995+ public int64 last_access_time;
996+ public int64 drawing_time;
997+ public double scale;
998+
999+ public SurfaceInfo (uint16 width, uint16 height, int64 last_access_time, int64 drawing_time)
1000+ {
1001+ this.width = width;
1002+ this.height = height;
1003+ this.last_access_time = last_access_time;
1004+ this.drawing_time = drawing_time;
1005+ this.access_count = 0;
1006+ this.scale = 1.0;
1007+ }
1008+
1009+ public static uint hash (SurfaceInfo s)
1010+ {
1011+ uint n1 = s.width, n2 = s.height;
1012+ return (n1 >= n2 ? n1 * n1 + n1 + n2 : n1 + n2 * n2);
1013+ }
1014+
1015+ public static int compare (SurfaceInfo s1, SurfaceInfo s2)
1016+ {
1017+ if (s1 == s2)
1018+ return 0;
1019+
1020+ return (2 * (s1.width - s2.width) + s2.height - s2.height);
1021+ }
1022+
1023+ public int compare_with (uint16 width, uint16 height)
1024+ {
1025+ return (2 * (this.width - width) + this.height - height);
1026+ }
1027+ }
1028+
1029+ public SurfaceCacheFlags flags { get; construct; }
1030+
1031+ Gee.TreeSet<unowned SurfaceInfo> infos;
1032+ Gee.HashMap<SurfaceInfo, DockSurface> cache_map;
1033+ unowned SurfaceInfo? last_info;
1034+ Mutex cache_mutex;
1035+
1036+ uint clean_up_timer = 0U;
1037+
1038+ public SurfaceCache (SurfaceCacheFlags flags = SurfaceCacheFlags.NONE)
1039+ {
1040+ Object (flags: flags);
1041+ }
1042+
1043+ construct
1044+ {
1045+ infos = new Gee.TreeSet<unowned SurfaceInfo> ((CompareDataFunc) SurfaceInfo.compare);
1046+ cache_map = new Gee.HashMap<SurfaceInfo, DockSurface> ((Gee.HashDataFunc<SurfaceInfo>) SurfaceInfo.hash);
1047+ last_info = null;
1048+
1049+ //TODO Adaptive delay depending on the access rate
1050+ clean_up_timer = Gdk.threads_add_timeout (5 * 60 * 1000, () => {
1051+ clean_up ();
1052+ return true;
1053+ });
1054+ }
1055+
1056+ ~SurfaceCache ()
1057+ {
1058+ if (clean_up_timer > 0U) {
1059+ GLib.Source.remove (clean_up_timer);
1060+ clean_up_timer = 0U;
1061+ }
1062+
1063+ cache_map.clear ();
1064+ infos.clear ();
1065+ last_info = null;
1066+ }
1067+
1068+ public DockSurface? get_surface<G> (int width, int height, DockSurface model, DrawFunc<G> draw_func, DrawDataFunc<G>? draw_data_func)
1069+ requires (width >= 0 && height >= 0)
1070+ {
1071+ cache_mutex.lock ();
1072+
1073+ unowned SurfaceInfo? info;
1074+ SurfaceInfo? current_info = null;
1075+ DockSurface? surface = null;
1076+ bool needs_scaling = false;
1077+
1078+ info = find_match ((uint16) width, (uint16) height, out needs_scaling);
1079+ last_info = info;
1080+ current_info = info;
1081+
1082+ var access_time = GLib.get_monotonic_time ();
1083+
1084+ if (current_info != null) {
1085+ current_info.last_access_time = access_time;
1086+ current_info.access_count++;
1087+ surface = cache_map.get (current_info);
1088+
1089+ cache_mutex.unlock ();
1090+
1091+ if (needs_scaling)
1092+ return surface.scaled_copy (width, height);
1093+ else
1094+ return surface;
1095+ }
1096+
1097+ surface = draw_func (width, height, model, draw_data_func);
1098+
1099+ var finish_time = GLib.get_monotonic_time ();
1100+ var time_elapsed = finish_time - access_time;
1101+
1102+ current_info = new SurfaceInfo ((uint16) width, (uint16) height, finish_time, time_elapsed);
1103+ current_info.access_count++;
1104+
1105+ cache_map.set (current_info, surface);
1106+ infos.add (current_info);
1107+
1108+ cache_mutex.unlock ();
1109+
1110+ return surface;
1111+ }
1112+
1113+ unowned SurfaceInfo? find_match (uint16 width, uint16 height, out bool needs_scaling)
1114+ {
1115+ needs_scaling = false;
1116+
1117+ if (infos.is_empty)
1118+ return null;
1119+
1120+ unowned SurfaceInfo? info;
1121+ // Check if the last requested entry matches already
1122+ if (last_info != null) {
1123+ info = last_info;
1124+ if (info.width == width && info.height == height)
1125+ return info;
1126+
1127+ if ((flags & SurfaceCacheFlags.ALLOW_DOWNSCALE) != 0
1128+ && info.width > width && info.height > height) {
1129+ needs_scaling = true;
1130+ return info;
1131+ }
1132+
1133+ if ((flags & SurfaceCacheFlags.ALLOW_UPSCALE) != 0
1134+ && info.width < width && info.height < height) {
1135+ needs_scaling = true;
1136+ return info;
1137+ }
1138+ }
1139+
1140+ Gee.BidirIterator<unowned SurfaceInfo> infos_it;
1141+ if (last_info != null)
1142+ infos_it = (Gee.BidirIterator<unowned SurfaceInfo>) infos.iterator_at (last_info);
1143+ else
1144+ infos_it = infos.bidir_iterator ();
1145+
1146+ if (last_info != null && last_info.compare_with (width, height) > 0) {
1147+ while (infos_it.previous ()) {
1148+ info = infos_it.get ();
1149+
1150+ if (info.width == width && info.height == height)
1151+ return info;
1152+
1153+ if ((flags & SurfaceCacheFlags.ALLOW_DOWNSCALE) != 0
1154+ && info.width > width && info.height > height) {
1155+ needs_scaling = true;
1156+ return info;
1157+ }
1158+
1159+ if ((flags & SurfaceCacheFlags.ALLOW_UPSCALE) != 0
1160+ && info.width < width && info.height < height) {
1161+ needs_scaling = true;
1162+ return info;
1163+ }
1164+ }
1165+ } else {
1166+ while (infos_it.next ()) {
1167+ info = infos_it.get ();
1168+
1169+ if (info.width == width && info.height == height)
1170+ return info;
1171+
1172+ if ((flags & SurfaceCacheFlags.ALLOW_DOWNSCALE) != 0
1173+ && info.width > width && info.height > height) {
1174+ needs_scaling = true;
1175+ return info;
1176+ }
1177+
1178+ if ((flags & SurfaceCacheFlags.ALLOW_UPSCALE) != 0
1179+ && info.width < width && info.height < height) {
1180+ needs_scaling = true;
1181+ return info;
1182+ }
1183+ }
1184+ }
1185+
1186+ return null;
1187+ }
1188+
1189+ public void clear ()
1190+ {
1191+ cache_mutex.lock ();
1192+
1193+ infos.clear ();
1194+ cache_map.clear ();
1195+ last_info = null;
1196+
1197+ cache_mutex.unlock ();
1198+ }
1199+
1200+ void clean_up ()
1201+ {
1202+ cache_mutex.lock ();
1203+
1204+ if (cache_map.size <= 1)
1205+ return;
1206+
1207+ var now = GLib.get_monotonic_time ();
1208+ var size_before = cache_map.size;
1209+
1210+ var cache_it = cache_map.map_iterator ();
1211+ while (cache_it.next ()) {
1212+ var info = cache_it.get_key ();
1213+
1214+ if (now - info.last_access_time < ACCESS_REWARD * info.access_count)
1215+ continue;
1216+
1217+ if (info.drawing_time > MIN_DRAWING_TIME)
1218+ continue;
1219+
1220+ infos.remove (info);
1221+ cache_it.unset ();
1222+ }
1223+
1224+ last_info = null;
1225+
1226+ Logger.verbose ("SurfaceCache.clean_up (%i -> %i) ", size_before, cache_map.size);
1227+
1228+ cache_mutex.unlock ();
1229+ }
1230+ }
1231+}
1232
1233=== modified file 'lib/Items/DockItem.vala'
1234--- lib/Items/DockItem.vala 2015-06-10 20:26:28 +0000
1235+++ lib/Items/DockItem.vala 2015-07-16 08:37:41 +0000
1236@@ -24,16 +24,6 @@
1237 namespace Plank.Items
1238 {
1239 /**
1240- * Draws a modified surface onto another newly created or given surface
1241- *
1242- * @param item the dock-item
1243- * @param source original surface which may not be changed
1244- * @param target the previously modified surface
1245- * @return the modified surface or passed through target
1246- */
1247- public delegate DockSurface DrawItemFunc (DockItem item, DockSurface source, DockSurface? target);
1248-
1249- /**
1250 * The base class for all dock items.
1251 */
1252 public abstract class DockItem : DockElement
1253@@ -134,8 +124,8 @@
1254 */
1255 public DockItemPreferences Prefs { get; construct; }
1256
1257- DockSurface? surface = null;
1258- DockSurface? background_surface = null;
1259+ SurfaceCache<DockItem> buffer;
1260+ SurfaceCache<DockItem> background_buffer;
1261 DockSurface? foreground_surface = null;
1262
1263 FileMonitor? launcher_file_monitor = null;
1264@@ -154,6 +144,9 @@
1265
1266 construct
1267 {
1268+ buffer = new SurfaceCache<DockItem> (SurfaceCacheFlags.NONE);
1269+ background_buffer = new SurfaceCache<DockItem> (SurfaceCacheFlags.ALLOW_SCALE);
1270+
1271 Prefs.deleted.connect (handle_deleted);
1272 Prefs.notify["Launcher"].connect (handle_launcher_changed);
1273
1274@@ -173,6 +166,9 @@
1275
1276 ~DockItem ()
1277 {
1278+ buffer.clear ();
1279+ background_buffer.clear ();
1280+
1281 Prefs.deleted.disconnect (handle_deleted);
1282 Prefs.notify["Launcher"].disconnect (handle_launcher_changed);
1283
1284@@ -232,8 +228,8 @@
1285 */
1286 protected void reset_icon_buffer ()
1287 {
1288- surface = null;
1289- background_surface = null;
1290+ buffer.clear ();
1291+ background_buffer.clear ();
1292 foreground_surface = null;
1293
1294 needs_redraw ();
1295@@ -244,7 +240,7 @@
1296 */
1297 public override void reset_buffers ()
1298 {
1299- background_surface = null;
1300+ background_buffer.clear ();
1301 foreground_surface = null;
1302 }
1303
1304@@ -420,16 +416,31 @@
1305 return true;
1306 }
1307
1308- unowned DockSurface get_surface (int width, int height, DockSurface model)
1309- {
1310- if (surface == null || width != surface.Width || height != surface.Height) {
1311- surface = new DockSurface.with_dock_surface (width, height, model);
1312-
1313- Logger.verbose ("DockItem.draw_icon (width = %i, height = %i)", width, height);
1314- draw_icon (surface);
1315-
1316- AverageIconColor = surface.average_color ();
1317- }
1318+ /**
1319+ * Returns the dock surface for this item.
1320+ *
1321+ * It might trigger an internal redraw if the requested size
1322+ * isn't cached yet.
1323+ *
1324+ * @param width width of the icon surface
1325+ * @param height height of the icon surface
1326+ * @param model existing surface to use as basis of new surface
1327+ * @return the dock surface for this item which may not be changed
1328+ */
1329+ public DockSurface get_surface (int width, int height, DockSurface model)
1330+ {
1331+ return buffer.get_surface<DockItem> (width, height, model, (DrawFunc<DockItem>) internal_get_surface, null);
1332+ }
1333+
1334+ [CCode (instance_pos = -1)]
1335+ DockSurface internal_get_surface (int width, int height, DockSurface model, DrawDataFunc<DockItem>? draw_data_func)
1336+ {
1337+ var surface = new DockSurface.with_dock_surface (width, height, model);
1338+
1339+ Logger.verbose ("DockItem.draw_icon (width = %i, height = %i)", width, height);
1340+ draw_icon (surface);
1341+
1342+ AverageIconColor = surface.average_color ();
1343
1344 return surface;
1345 }
1346@@ -442,18 +453,21 @@
1347 *
1348 * Passing null as draw_func will destroy the internal background buffer.
1349 *
1350- * @param draw_func function which creates/changes the background surface
1351+ * @param draw_data_func function which creates/changes the background surface
1352 * @return the background surface of this item which may not be changed
1353 */
1354- public unowned DockSurface? get_background_surface (DrawItemFunc? draw_func = null)
1355- requires (surface != null)
1356- {
1357- if (draw_func != null)
1358- background_surface = draw_func (this, surface, background_surface);
1359- else
1360- background_surface = null;
1361+ public DockSurface? get_background_surface (int width, int height, DockSurface model, DrawDataFunc<DockItem>? draw_data_func)
1362+ {
1363+ return background_buffer.get_surface<DockItem> (width, height, model, (DrawFunc<DockItem>) internal_get_background_surface, (DrawDataFunc<DockItem>) draw_data_func);
1364+ }
1365+
1366+ [CCode (instance_pos = -1)]
1367+ DockSurface? internal_get_background_surface (int width, int height, DockSurface model, DrawDataFunc<DockItem>? draw_data_func)
1368+ {
1369+ if (draw_data_func == null)
1370+ return null;
1371
1372- return background_surface;
1373+ return draw_data_func (width, height, model, this);
1374 }
1375
1376 /**
1377@@ -464,16 +478,21 @@
1378 *
1379 * Passing null as draw_func will destroy the internal foreground buffer.
1380 *
1381- * @param draw_func function which creates/changes the foreground surface
1382+ * @param draw_data_func function which creates/changes the foreground surface
1383 * @return the background surface of this item which may not be changed
1384 */
1385- public unowned DockSurface? get_foreground_surface (DrawItemFunc? draw_func = null)
1386- requires (surface != null)
1387+ public DockSurface? get_foreground_surface (int width, int height, DockSurface model, DrawDataFunc<DockItem>? draw_data_func)
1388 {
1389- if (draw_func != null)
1390- foreground_surface = draw_func (this, surface, foreground_surface);
1391- else
1392+ if (draw_data_func == null) {
1393 foreground_surface = null;
1394+ return null;
1395+ }
1396+
1397+ if (foreground_surface != null
1398+ && foreground_surface.Width == width && foreground_surface.Height == height)
1399+ return foreground_surface;
1400+
1401+ foreground_surface = draw_data_func (width, height, model, this);
1402
1403 return foreground_surface;
1404 }
1405
1406=== modified file 'lib/Makefile.am'
1407--- lib/Makefile.am 2015-06-08 21:48:12 +0000
1408+++ lib/Makefile.am 2015-07-16 08:37:41 +0000
1409@@ -79,6 +79,7 @@
1410 Drawing/DockSurface.vala \
1411 Drawing/DockTheme.vala \
1412 Drawing/Easing.vala \
1413+ Drawing/SurfaceCache.vala \
1414 Drawing/Theme.vala \
1415 Factories/AbstractMain.vala \
1416 Factories/Factory.vala \
1417
1418=== modified file 'lib/PositionManager.vala'
1419--- lib/PositionManager.vala 2015-06-11 05:36:16 +0000
1420+++ lib/PositionManager.vala 2015-07-16 08:37:41 +0000
1421@@ -29,12 +29,41 @@
1422 */
1423 public class PositionManager : GLib.Object
1424 {
1425- public struct DockItemDrawValue
1426- {
1427+ public struct PointD
1428+ {
1429+ public double x;
1430+ public double y;
1431+ }
1432+
1433+ /**
1434+ * Modify the given DrawItemValue
1435+ *
1436+ * @param item the dock-item
1437+ * @param draw_value the dock-item-drawvalue
1438+ */
1439+ public delegate void DockItemDrawValueFunc (DockItem item, DockItemDrawValue draw_value);
1440+
1441+ /**
1442+ * Modify the all DrawItemValue of all dock-items
1443+ *
1444+ * @param draw_values the map of all current dock-items and their draw-values
1445+ */
1446+ public delegate void DrawValuesFunc (Gee.HashMap<DockElement, DockItemDrawValue> draw_values);
1447+
1448+ /**
1449+ * Contains all positions and modifications to draw a dock-item on the dock
1450+ */
1451+ public class DockItemDrawValue
1452+ {
1453+ public PointD center;
1454+ public PointD static_center;
1455+ public double icon_size;
1456+
1457 public Gdk.Rectangle hover_region;
1458 public Gdk.Rectangle draw_region;
1459 public Gdk.Rectangle background_region;
1460
1461+ public double zoom;
1462 public double opacity;
1463
1464 public double darken;
1465@@ -49,18 +78,26 @@
1466 switch (position) {
1467 default:
1468 case Gtk.PositionType.BOTTOM:
1469+ center.y -= damount;
1470+ static_center.y -= damount;
1471 hover_region.y -= amount;
1472 draw_region.y -= amount;
1473 break;
1474 case Gtk.PositionType.TOP:
1475+ center.y += damount;
1476+ static_center.y += damount;
1477 hover_region.y += amount;
1478 draw_region.y += amount;
1479 break;
1480 case Gtk.PositionType.LEFT:
1481+ center.x += damount;
1482+ static_center.x += damount;
1483 hover_region.x += amount;
1484 draw_region.x += amount;
1485 break;
1486 case Gtk.PositionType.RIGHT:
1487+ center.x -= damount;
1488+ static_center.x -= damount;
1489 hover_region.x -= amount;
1490 draw_region.x -= amount;
1491 break;
1492@@ -74,21 +111,29 @@
1493 switch (position) {
1494 default:
1495 case Gtk.PositionType.BOTTOM:
1496+ center.x += damount;
1497+ static_center.x += damount;
1498 hover_region.x += amount;
1499 draw_region.x += amount;
1500 background_region.x += amount;
1501 break;
1502 case Gtk.PositionType.TOP:
1503+ center.x += damount;
1504+ static_center.x += damount;
1505 hover_region.x += amount;
1506 draw_region.x += amount;
1507 background_region.x += amount;
1508 break;
1509 case Gtk.PositionType.LEFT:
1510+ center.y += damount;
1511+ static_center.y += damount;
1512 hover_region.y += amount;
1513 draw_region.y += amount;
1514 background_region.y += amount;
1515 break;
1516 case Gtk.PositionType.RIGHT:
1517+ center.y += damount;
1518+ static_center.y += damount;
1519 hover_region.y += amount;
1520 draw_region.y += amount;
1521 background_region.y += amount;
1522@@ -102,7 +147,7 @@
1523 public bool screen_is_composited { get; private set; }
1524
1525 Gdk.Rectangle static_dock_region;
1526- Gee.HashMap<DockElement, DockItemDrawValue?> draw_values;
1527+ Gee.HashMap<DockElement, DockItemDrawValue> draw_values;
1528
1529 Gdk.Rectangle monitor_geo;
1530
1531@@ -121,9 +166,9 @@
1532 construct
1533 {
1534 static_dock_region = {};
1535- draw_values = new Gee.HashMap<DockElement, DockItemDrawValue?> ();
1536+ draw_values = new Gee.HashMap<DockElement, DockItemDrawValue> ();
1537
1538- controller.prefs.notify["Monitor"].connect (prefs_monitor_changed);
1539+ controller.prefs.notify.connect (prefs_changed);
1540 }
1541
1542 /**
1543@@ -151,11 +196,27 @@
1544 screen.monitors_changed.disconnect (screen_changed);
1545 screen.size_changed.disconnect (screen_changed);
1546 screen.composited_changed.disconnect (screen_composited_changed);
1547- controller.prefs.notify["Monitor"].disconnect (prefs_monitor_changed);
1548+ controller.prefs.notify.disconnect (prefs_changed);
1549
1550 draw_values.clear ();
1551 }
1552
1553+ void prefs_changed (Object prefs, ParamSpec prop)
1554+ {
1555+ switch (prop.name) {
1556+ case "Monitor":
1557+ prefs_monitor_changed ();
1558+ break;
1559+ case "ZoomPercent":
1560+ case "ZoomEnabled":
1561+ prefs_zoom_changed ();
1562+ break;
1563+ default:
1564+ // Nothing important for us changed
1565+ break;
1566+ }
1567+ }
1568+
1569 public static string[] get_monitor_plug_names (Gdk.Screen screen)
1570 {
1571 int n_monitors = screen.get_n_monitors ();
1572@@ -231,7 +292,12 @@
1573 * Cached current icon size for the dock.
1574 */
1575 public int IconSize { get; private set; }
1576-
1577+
1578+ /**
1579+ * Cached current icon size for the dock.
1580+ */
1581+ public int ZoomIconSize { get; private set; }
1582+
1583 /**
1584 * Cached position of the dock.
1585 */
1586@@ -330,6 +396,10 @@
1587 */
1588 int DockBackgroundWidth;
1589
1590+ double ZoomPercent;
1591+
1592+ Gdk.Rectangle background_rect;
1593+
1594 /**
1595 * The maximum item count which fit the dock in its maximum
1596 * size with the current theme and icon-size.
1597@@ -363,24 +433,6 @@
1598 thaw_notify ();
1599 }
1600
1601- /**
1602- * Resets all internal caches for the given item.
1603- *
1604- * @param item the dock item
1605- */
1606- public void reset_item_cache (DockElement item)
1607- {
1608- draw_values.unset (item);
1609- }
1610-
1611- /**
1612- * Resets all internal item caches.
1613- */
1614- public void reset_item_caches ()
1615- {
1616- draw_values.clear ();
1617- }
1618-
1619 void update_caches (DockTheme theme)
1620 {
1621 unowned DockPreferences prefs = controller.prefs;
1622@@ -413,6 +465,8 @@
1623 }
1624
1625 IconSize = int.min (MaxIconSize, prefs.IconSize);
1626+ ZoomPercent = (screen_is_composited ? prefs.ZoomPercent / 100.0 : 1.0);
1627+ ZoomIconSize = (screen_is_composited && prefs.ZoomEnabled ? (int) Math.round (IconSize * ZoomPercent) : IconSize);
1628
1629 var scaled_icon_size = IconSize / 10.0;
1630
1631@@ -445,8 +499,14 @@
1632 extra_hide_offset = (IconShadowSize - top_offset);
1633 else
1634 extra_hide_offset = 0;
1635+ }
1636+
1637+ void prefs_zoom_changed ()
1638+ {
1639+ unowned DockPreferences prefs = controller.prefs;
1640
1641- draw_values.clear ();
1642+ ZoomPercent = (screen_is_composited ? prefs.ZoomPercent / 100.0 : 1.0);
1643+ ZoomIconSize = (screen_is_composited && prefs.ZoomEnabled ? (int) Math.round (IconSize * ZoomPercent) : IconSize);
1644 }
1645
1646 /**
1647@@ -563,6 +623,15 @@
1648 window_scale_factor = controller.window.get_window ().get_scale_factor ();
1649 #endif
1650
1651+ // If zoom is enabled extend cursor-region based on current hovered-item
1652+ if (controller.prefs.ZoomEnabled) {
1653+ unowned DockItem? hovered_item = controller.window.HoveredItem;
1654+ if (hovered_item != null) {
1655+ var hover_region = get_hover_region_for_element (hovered_item);
1656+ cursor_region.union (hover_region, out cursor_region);
1657+ }
1658+ }
1659+
1660 switch (Position) {
1661 default:
1662 case Gtk.PositionType.BOTTOM:
1663@@ -691,9 +760,6 @@
1664
1665 update_dock_position ();
1666
1667- // FIXME Maybe no need to purge all cached values?
1668- draw_values.clear ();
1669-
1670 if (!screen_is_composited
1671 || old_region.x != static_dock_region.x
1672 || old_region.y != static_dock_region.y
1673@@ -721,91 +787,337 @@
1674 */
1675 public DockItemDrawValue get_draw_value_for_item (DockItem item)
1676 {
1677- DockItemDrawValue? draw_value;
1678-
1679- if ((draw_value = draw_values.get (item)) == null) {
1680- var hover_rect = internal_get_item_hover_region (item);
1681- var draw_rect = get_item_draw_region (hover_rect);
1682- var background_rect = get_item_background_region (hover_rect);
1683-
1684- draw_value = { hover_rect, draw_rect, background_rect, 1.0, 0.0, 0.0, true };
1685- draw_values.set (item, draw_value);
1686+ if (draw_values.size == 0) {
1687+ critical ("Without draw_values there is trouble ahead");
1688+ update_draw_values (controller.VisibleItems);
1689+ }
1690+
1691+ var draw_value = draw_values[item];
1692+ if (draw_value == null) {
1693+ critical ("Without a draw_value there is trouble ahead for '%s'", item.Text);
1694+ draw_value = new DockItemDrawValue ();
1695 }
1696
1697 return draw_value;
1698 }
1699
1700 /**
1701+ * Update and recalculated all internal draw-values using the given methodes for custom manipulations.
1702+ *
1703+ * @param items the ordered list of all current item which are suppose to be shown on the dock
1704+ * @param func a function which adjusts the draw-value per item
1705+ * @param post_func a function which post-processes all draw-values
1706+ */
1707+ public void update_draw_values (Gee.ArrayList<unowned DockItem> items, DockItemDrawValueFunc? func = null,
1708+ DrawValuesFunc? post_func = null)
1709+ {
1710+ unowned DockPreferences prefs = controller.prefs;
1711+
1712+ draw_values.clear ();
1713+
1714+ bool external_drag_active = controller.drag_manager.ExternalDragActive;
1715+
1716+ // first we do the math as if this is a top dock, to do this we need to set
1717+ // up some "pretend" variables. we pretend we are a top dock because 0,0 is
1718+ // at the top.
1719+ int width = DockWidth;
1720+ int height = DockHeight;
1721+ int icon_size = IconSize;
1722+
1723+ double zoom_in_progress = controller.renderer.zoom_in_progress;
1724+ Gdk.Point cursor = controller.renderer.local_cursor;
1725+
1726+ // "relocate" our cursor to be on the top
1727+ switch (Position) {
1728+ case Gtk.PositionType.RIGHT:
1729+ cursor.x = width - cursor.x;
1730+ break;
1731+ case Gtk.PositionType.BOTTOM:
1732+ cursor.y = height - cursor.y;
1733+ break;
1734+ default:
1735+ break;
1736+ }
1737+
1738+ // our width and height switch around if we have a vertical dock
1739+ if (!is_horizontal_dock ()) {
1740+ int tmp = cursor.y;
1741+ cursor.y = cursor.x;
1742+ cursor.x = tmp;
1743+
1744+ tmp = width;
1745+ width = height;
1746+ height = tmp;
1747+ }
1748+
1749+ //FIXME
1750+ // the line along the dock width about which the center of unzoomed icons sit
1751+ double center_y = (is_horizontal_dock () ? static_dock_region.height / 2.0 : static_dock_region.width / 2.0);
1752+
1753+ double center_x = (icon_size + ItemPadding) / 2.0 + items_offset;
1754+ if (Alignment == Gtk.Align.FILL) {
1755+ switch (ItemsAlignment) {
1756+ default:
1757+ case Gtk.Align.FILL:
1758+ case Gtk.Align.CENTER:
1759+ if (is_horizontal_dock ())
1760+ center_x += static_dock_region.x + (static_dock_region.width - 2 * items_offset - items_width) / 2;
1761+ else
1762+ center_x += static_dock_region.y + (static_dock_region.height - 2 * items_offset - items_width) / 2;
1763+ break;
1764+ case Gtk.Align.START:
1765+ break;
1766+ case Gtk.Align.END:
1767+ if (is_horizontal_dock ())
1768+ center_x += static_dock_region.x + (static_dock_region.width - 2 * items_offset - items_width);
1769+ else
1770+ center_x += static_dock_region.y + (static_dock_region.height - 2 * items_offset - items_width);
1771+ break;
1772+ }
1773+ } else {
1774+ if (is_horizontal_dock ())
1775+ center_x += static_dock_region.x;
1776+ else
1777+ center_x += static_dock_region.y;
1778+ }
1779+
1780+ PointD center = { Math.floor (center_x), Math.floor (center_y) };
1781+
1782+ // ZoomPercent is a number greater than 1. It should never be less than one.
1783+
1784+ // zoom_in_percent is a range of 1 to ZoomPercent.
1785+ // We need a number that is 1 when ZoomIn is 0, and ZoomPercent when ZoomIn is 1.
1786+ // Then we treat this as if it were the ZoomPercent for the rest of the calculation.
1787+ double zoom_in_percent = (prefs.ZoomEnabled ? 1.0 + (ZoomPercent - 1.0) * zoom_in_progress : 1.0);
1788+ double zoom_icon_size = (prefs.ZoomEnabled ? ZoomIconSize : 2.0 * icon_size);
1789+
1790+ foreach (unowned DockItem item in items) {
1791+ DockItemDrawValue val = new DockItemDrawValue ();
1792+ val.opacity = 1.0;
1793+ val.darken = 0.0;
1794+ val.lighten = 0.0;
1795+ val.show_indicator = true;
1796+ val.zoom = 1.0;
1797+
1798+ val.static_center = center;
1799+
1800+ // get us some handy doubles with fancy names
1801+ double cursor_position = cursor.x;
1802+ double center_position = center.x;
1803+
1804+ // offset from the center of the true position, ranged between 0 and the zoom size
1805+ double offset = double.min (Math.fabs (cursor_position - center_position), zoom_icon_size);
1806+
1807+ double offset_percent;
1808+ if (external_drag_active) {
1809+ // Provide space for dropping between items
1810+ offset += offset * zoom_icon_size / icon_size;
1811+ offset_percent = double.min (1.0, offset / (zoom_icon_size + ZoomIconSize));
1812+ } else {
1813+ offset_percent = offset / zoom_icon_size;
1814+ }
1815+
1816+ if (offset_percent > 0.99)
1817+ offset_percent = 1.0;
1818+
1819+ // pull in our offset to make things less spaced out
1820+ // explaination since this is a bit tricky...
1821+ // we have three terms, basically offset = f(x) * h(x) * g(x)
1822+ // f(x) == offset identity
1823+ // h(x) == a number from 0 to DockPreference.ZoomPercent - 1. This is used to get the smooth "zoom in" effect.
1824+ // additionally serves to "curve" the offset based on the max zoom
1825+ // g(x) == a term used to move the ends of the zoom inward. Precalculated that the edges should be 66% of the current
1826+ // value. The center is 100%. (1 - offset_percent) == 0,1 distance from center
1827+ // The .66 value comes from the area under the curve. Dont ask me to explain it too much because it's too clever for me.
1828+
1829+ // for external drags with no zoom, we pretend there is actually a zoom of 200%
1830+ if (external_drag_active && ZoomPercent == 1.0)
1831+ offset *= zoom_in_progress / 2.0;
1832+ else
1833+ offset *= zoom_in_percent - 1.0;
1834+ offset *= 1.0 - offset_percent / 3.0;
1835+
1836+ if (cursor_position > center_position)
1837+ center_position -= offset;
1838+ else
1839+ center_position += offset;
1840+
1841+ // zoom is calculated as 1 through target_zoom (default 2).
1842+ // The larger your offset, the smaller your zoom
1843+
1844+ // First we get the point on our curve that defines our current zoom
1845+ // offset is always going to fall on a point on the curve >= 0
1846+ var zoom = 1.0 - Math.pow (offset_percent, 2);
1847+
1848+ // scale this to match our zoom_in_percent
1849+ zoom = 1.0 + zoom * (zoom_in_percent - 1.0);
1850+
1851+ double zoomed_center_height = (icon_size * zoom / 2.0);
1852+
1853+ if (zoom == 1.0)
1854+ center_position = Math.round (center_position);
1855+
1856+ val.center = { center_position, zoomed_center_height };
1857+ val.zoom = zoom;
1858+ val.icon_size = Math.round (zoom * icon_size);
1859+
1860+ // now we undo our transforms to the point
1861+ if (!is_horizontal_dock ()) {
1862+ double tmp = val.center.y;
1863+ val.center.y = val.center.x;
1864+ val.center.x = tmp;
1865+
1866+ tmp = val.static_center.y;
1867+ val.static_center.y = val.static_center.x;
1868+ val.static_center.x = tmp;
1869+ }
1870+
1871+ switch (Position) {
1872+ case Gtk.PositionType.RIGHT:
1873+ val.center.x = height - val.center.x;
1874+ val.static_center.x = height - val.static_center.x;
1875+ break;
1876+ case Gtk.PositionType.BOTTOM:
1877+ val.center.y = height - val.center.y;
1878+ val.static_center.y = height - val.static_center.y;
1879+ break;
1880+ default:
1881+ break;
1882+ }
1883+
1884+ //FIXME
1885+ val.move_in (Position, bottom_offset);
1886+
1887+ // let the draw-value be modified by the given function
1888+ if (func != null)
1889+ func (item, val);
1890+
1891+ draw_values[item] = val;
1892+
1893+ //FIXME
1894+ // Don't reserve space for removed items
1895+ if (item.RemoveTime == 0)
1896+ center.x += icon_size + ItemPadding;
1897+ }
1898+
1899+ if (post_func != null)
1900+ post_func (draw_values);
1901+
1902+ update_background_region (draw_values[items.first ()], draw_values[items.last ()]);
1903+
1904+ // precalculate and cache regions (for the current frame)
1905+#if HAVE_GEE_0_8
1906+ draw_values.map_iterator ().foreach ((i, val) => {
1907+ val.draw_region = get_item_draw_region (val);
1908+ val.hover_region = get_item_hover_region (val);
1909+ val.background_region = get_item_background_region (val);
1910+ return true;
1911+ });
1912+#else
1913+ var draw_values_it = draw_values.map_iterator ();
1914+ while (draw_values_it.next ()) {
1915+ var val = draw_values_it.get_value ();
1916+ val.draw_region = get_item_draw_region (val);
1917+ val.hover_region = get_item_hover_region (val);
1918+ val.background_region = get_item_background_region (val);
1919+ }
1920+#endif
1921+ }
1922+ /**
1923 * The region for drawing a dock item.
1924 *
1925- * @param hover_rect the item's hover region
1926- * @return the region for the dock item
1927- */
1928- Gdk.Rectangle get_item_draw_region (Gdk.Rectangle hover_rect)
1929- {
1930+ * @param val the item's DockItemDrawValue
1931+ * @return the region for the dock item
1932+ */
1933+ Gdk.Rectangle get_item_draw_region (DockItemDrawValue val)
1934+ {
1935+ var width = val.icon_size, height = val.icon_size;
1936+
1937+ return { (int) Math.round (val.center.x - width / 2.0),
1938+ (int) Math.round (val.center.y - height / 2.0),
1939+ (int) width,
1940+ (int) height };
1941+ }
1942+
1943+ /**
1944+ * The intersecting region of a dock item's hover region and the background.
1945+ *
1946+ * @param val the item's DockItemDrawValue
1947+ * @return the region for the dock item
1948+ */
1949+ Gdk.Rectangle get_item_background_region (DockItemDrawValue val)
1950+ {
1951+ Gdk.Rectangle rect;
1952+
1953+ if (!val.hover_region.intersect (get_background_region (), out rect))
1954+ return {};
1955+
1956+ return rect;
1957+ }
1958+
1959+ /**
1960+ * The cursor region for interacting with a dock element.
1961+ *
1962+ * @param val the item's DockItemDrawValue
1963+ * @return the region for the dock item
1964+ */
1965+ Gdk.Rectangle get_item_hover_region (DockItemDrawValue val)
1966+ {
1967+ Gdk.Rectangle rect;
1968+
1969 var item_padding = ItemPadding;
1970 var top_padding = (top_offset < 0 ? 0 : top_offset);
1971 var bottom_padding = bottom_offset;
1972+ var width = val.icon_size, height = val.icon_size;
1973
1974+ // Apply scalable padding
1975 switch (Position) {
1976 default:
1977 case Gtk.PositionType.BOTTOM:
1978- hover_rect.x += item_padding / 2;
1979- hover_rect.y += top_padding;
1980- hover_rect.width -= item_padding;
1981- hover_rect.height -= bottom_padding + top_padding;
1982+ width += item_padding;
1983 break;
1984 case Gtk.PositionType.TOP:
1985- hover_rect.x += item_padding / 2;
1986- hover_rect.y += bottom_padding;
1987- hover_rect.width -= item_padding;
1988- hover_rect.height -= bottom_padding + top_padding;
1989+ width += item_padding;
1990 break;
1991 case Gtk.PositionType.LEFT:
1992- hover_rect.x += bottom_padding;
1993- hover_rect.y += item_padding / 2;
1994- hover_rect.width -= bottom_padding + top_padding;
1995- hover_rect.height -= item_padding;
1996+ height += item_padding;
1997 break;
1998 case Gtk.PositionType.RIGHT:
1999- hover_rect.x += top_padding;
2000- hover_rect.y += item_padding / 2;
2001- hover_rect.width -= bottom_padding + top_padding;
2002- hover_rect.height -= item_padding;
2003+ height += item_padding;
2004 break;
2005 }
2006
2007- return hover_rect;
2008- }
2009-
2010- /**
2011- * The intersecting region of a dock item's hover region and the background.
2012- *
2013- * @param rect the item's hover region
2014- * @return the region for the dock item
2015- */
2016- Gdk.Rectangle get_item_background_region (Gdk.Rectangle rect)
2017- {
2018- var top_padding = (top_offset > 0 ? 0 : top_offset);
2019+ rect = { (int) Math.round (val.center.x - width / 2.0),
2020+ (int) Math.round (val.center.y - height / 2.0),
2021+ (int) width,
2022+ (int) height };
2023
2024+ // Apply static padding
2025 switch (Position) {
2026 default:
2027 case Gtk.PositionType.BOTTOM:
2028 rect.y -= top_padding;
2029- rect.height += top_padding;
2030+ rect.height += bottom_padding + top_padding;
2031 break;
2032 case Gtk.PositionType.TOP:
2033- rect.height += top_padding;
2034+ rect.y -= bottom_padding;
2035+ rect.height += bottom_padding + top_padding;
2036 break;
2037 case Gtk.PositionType.LEFT:
2038- rect.width += top_padding;
2039+ rect.x -= bottom_padding;
2040+ rect.width += bottom_padding + top_padding;
2041 break;
2042 case Gtk.PositionType.RIGHT:
2043 rect.x -= top_padding;
2044- rect.width += top_padding;
2045+ rect.width += bottom_padding + top_padding;
2046 break;
2047 }
2048
2049+ Gdk.Rectangle background_region;
2050+
2051+ if (rect.intersect (get_background_region (), out background_region))
2052+ background_region.union (get_item_draw_region (val), out rect);
2053+
2054 return rect;
2055 }
2056
2057@@ -815,7 +1127,7 @@
2058 * @param element the dock element to find a region for
2059 * @return the region for the dock item
2060 */
2061- public Gdk.Rectangle get_item_hover_region (DockElement element)
2062+ public Gdk.Rectangle get_hover_region_for_element (DockElement element)
2063 {
2064 unowned DockItem? item = (element as DockItem);
2065 if (item != null)
2066@@ -830,73 +1142,16 @@
2067 if (items.size == 0)
2068 return {};
2069
2070- var first_rect = get_item_hover_region (items.first ());
2071+ var first_rect = get_hover_region_for_element (items.first ());
2072 if (items.size == 1)
2073 return first_rect;
2074
2075- var last_rect = get_item_hover_region (items.last ());
2076+ var last_rect = get_hover_region_for_element (items.last ());
2077
2078 Gdk.Rectangle result;
2079 first_rect.union (last_rect, out result);
2080 return result;
2081 }
2082-
2083- Gdk.Rectangle internal_get_item_hover_region (DockItem item)
2084- {
2085- Gdk.Rectangle rect = {};
2086-
2087- switch (Position) {
2088- default:
2089- case Gtk.PositionType.BOTTOM:
2090- rect.width = IconSize + ItemPadding;
2091- rect.height = VisibleDockHeight;
2092- rect.x = static_dock_region.x + items_offset + item.Position * (ItemPadding + IconSize);
2093- rect.y = DockHeight - rect.height;
2094- break;
2095- case Gtk.PositionType.TOP:
2096- rect.width = IconSize + ItemPadding;
2097- rect.height = VisibleDockHeight;
2098- rect.x = static_dock_region.x + items_offset + item.Position * (ItemPadding + IconSize);
2099- rect.y = 0;
2100- break;
2101- case Gtk.PositionType.LEFT:
2102- rect.height = IconSize + ItemPadding;
2103- rect.width = VisibleDockWidth;
2104- rect.y = static_dock_region.y + items_offset + item.Position * (ItemPadding + IconSize);
2105- rect.x = 0;
2106- break;
2107- case Gtk.PositionType.RIGHT:
2108- rect.height = IconSize + ItemPadding;
2109- rect.width = VisibleDockWidth;
2110- rect.y = static_dock_region.y + items_offset + item.Position * (ItemPadding + IconSize);
2111- rect.x = DockWidth - rect.width;
2112- break;
2113- }
2114-
2115- if (Alignment != Gtk.Align.FILL)
2116- return rect;
2117-
2118- switch (ItemsAlignment) {
2119- default:
2120- case Gtk.Align.FILL:
2121- case Gtk.Align.CENTER:
2122- if (is_horizontal_dock ())
2123- rect.x += (static_dock_region.width - 2 * items_offset - items_width) / 2;
2124- else
2125- rect.y += (static_dock_region.height - 2 * items_offset - items_width) / 2;
2126- break;
2127- case Gtk.Align.START:
2128- break;
2129- case Gtk.Align.END:
2130- if (is_horizontal_dock ())
2131- rect.x += (static_dock_region.width - 2 * items_offset - items_width);
2132- else
2133- rect.y += (static_dock_region.height - 2 * items_offset - items_width);
2134- break;
2135- }
2136-
2137- return rect;
2138- }
2139
2140 /**
2141 * Get's the x and y position to display a menu for a dock item.
2142@@ -908,7 +1163,7 @@
2143 */
2144 public void get_menu_position (DockItem hovered, Gtk.Requisition requisition, out int x, out int y)
2145 {
2146- var rect = get_item_hover_region (hovered);
2147+ var rect = get_hover_region_for_element (hovered);
2148
2149 var offset = 10;
2150 switch (Position) {
2151@@ -941,25 +1196,26 @@
2152 */
2153 public void get_hover_position (DockItem hovered, out int x, out int y)
2154 {
2155- var rect = get_item_hover_region (hovered);
2156+ var center = get_draw_value_for_item (hovered).static_center;
2157+ var offset = (ZoomIconSize - IconSize / 2.0);
2158
2159 switch (Position) {
2160 default:
2161 case Gtk.PositionType.BOTTOM:
2162- x = rect.x + win_x + rect.width / 2;
2163- y = rect.y + win_y;
2164+ x = (int) Math.round (center.x + win_x);
2165+ y = (int) Math.round (center.y + win_y - offset);
2166 break;
2167 case Gtk.PositionType.TOP:
2168- x = rect.x + win_x + rect.width / 2;
2169- y = rect.y + win_y + rect.height;
2170+ x = (int) Math.round (center.x + win_x);
2171+ y = (int) Math.round (center.y + win_y + offset);
2172 break;
2173 case Gtk.PositionType.LEFT:
2174- y = rect.y + win_y + rect.height / 2;
2175- x = rect.x + win_x + rect.width;
2176+ x = (int) Math.round (center.x + win_x + offset);
2177+ y = (int) Math.round (center.y + win_y);
2178 break;
2179 case Gtk.PositionType.RIGHT:
2180- y = rect.y + win_y + rect.height / 2;
2181- x = rect.x + win_x;
2182+ x = (int) Math.round (center.x + win_x - offset);
2183+ y = (int) Math.round (center.y + win_y);
2184 break;
2185 }
2186 }
2187@@ -973,7 +1229,7 @@
2188 */
2189 public void get_urgent_glow_position (DockItem item, out int x, out int y)
2190 {
2191- var rect = get_item_hover_region (item);
2192+ var rect = get_hover_region_for_element (item);
2193 var glow_size = GlowSize;
2194
2195 switch (Position) {
2196@@ -1130,8 +1386,12 @@
2197 */
2198 public Gdk.Rectangle get_background_region ()
2199 {
2200- var x = 0, y = 0;
2201- var width = 0, height = 0;
2202+ return background_rect;
2203+ }
2204+
2205+ void update_background_region (DockItemDrawValue val_first, DockItemDrawValue val_last)
2206+ {
2207+ var x = 0, y = 0, width = 0, height = 0;
2208
2209 if (screen_is_composited) {
2210 x = static_dock_region.x;
2211@@ -1143,27 +1403,64 @@
2212 height = DockHeight;
2213 }
2214
2215+ if (Alignment == Gtk.Align.FILL) {
2216+ switch (Position) {
2217+ default:
2218+ case Gtk.PositionType.BOTTOM:
2219+ x += (width - DockBackgroundWidth) / 2;
2220+ y += height - DockBackgroundHeight;
2221+ break;
2222+ case Gtk.PositionType.TOP:
2223+ x += (width - DockBackgroundWidth) / 2;
2224+ y = 0;
2225+ break;
2226+ case Gtk.PositionType.LEFT:
2227+ x = 0;
2228+ y += (height - DockBackgroundHeight) / 2;
2229+ break;
2230+ case Gtk.PositionType.RIGHT:
2231+ x += width - DockBackgroundWidth;
2232+ y += (height - DockBackgroundHeight) / 2;
2233+ break;
2234+ }
2235+
2236+ background_rect = { x, y, DockBackgroundWidth, DockBackgroundHeight };
2237+ return;
2238+ }
2239+
2240+ var center_first = val_first.center;
2241+ var center_last = val_last.center;
2242+ var padding = IconSize + ItemPadding + 2 * HorizPadding + 4 * LineWidth;
2243+
2244 switch (Position) {
2245 default:
2246 case Gtk.PositionType.BOTTOM:
2247- x += (width - DockBackgroundWidth) / 2;
2248+ x = (int) Math.round (center_first.x - padding / 2.0);
2249 y += height - DockBackgroundHeight;
2250+ width = (int) Math.round (center_last.x - center_first.x + padding);
2251+ height = DockBackgroundHeight;
2252 break;
2253 case Gtk.PositionType.TOP:
2254- x += (width - DockBackgroundWidth) / 2;
2255+ x = (int) Math.round (center_first.x - padding / 2.0);
2256 y = 0;
2257+ width = (int) Math.round (center_last.x - center_first.x + padding);
2258+ height = DockBackgroundHeight;
2259 break;
2260 case Gtk.PositionType.LEFT:
2261 x = 0;
2262- y += (height - DockBackgroundHeight) / 2;
2263+ y = (int) Math.round (center_first.y - padding / 2.0);
2264+ width = DockBackgroundWidth;
2265+ height = (int) Math.round (center_last.y - center_first.y + padding);
2266 break;
2267 case Gtk.PositionType.RIGHT:
2268 x += width - DockBackgroundWidth;
2269- y += (height - DockBackgroundHeight) / 2;
2270+ y = (int) Math.round (center_first.y - padding / 2.0);
2271+ width = DockBackgroundWidth;
2272+ height = (int) Math.round (center_last.y - center_first.y + padding);
2273 break;
2274 }
2275
2276- return { x, y, DockBackgroundWidth, DockBackgroundHeight };
2277+ background_rect = { x, y, width, height };
2278 }
2279
2280 /**
2281@@ -1175,7 +1472,7 @@
2282 */
2283 public Gdk.Rectangle get_icon_geometry (ApplicationDockItem item, bool for_hidden)
2284 {
2285- var region = get_item_hover_region (item);
2286+ var region = get_hover_region_for_element (item);
2287
2288 if (!for_hidden) {
2289 region.x += win_x;
2290
2291=== modified file 'lib/Widgets/DockWindow.vala'
2292--- lib/Widgets/DockWindow.vala 2015-06-10 16:44:08 +0000
2293+++ lib/Widgets/DockWindow.vala 2015-07-16 08:37:41 +0000
2294@@ -234,6 +234,7 @@
2295 if (menu_is_visible ())
2296 return Gdk.EVENT_STOP;
2297
2298+ controller.renderer.update_local_cursor ((int) event.x, (int) event.y);
2299 update_hovered ((int) event.x, (int) event.y);
2300
2301 return Gdk.EVENT_PROPAGATE;
2302@@ -394,7 +395,7 @@
2303
2304 // check if there already was a hovered-item and if it is still hovered to speed up things
2305 if (HoveredItem != null) {
2306- rect = position_manager.get_item_hover_region (HoveredItem);
2307+ rect = position_manager.get_hover_region_for_element (HoveredItem);
2308 if (y >= rect.y && y < rect.y + rect.height && x >= rect.x && x < rect.x + rect.width)
2309 // Do not allow the hovered-item to be the drag-item
2310 if (drag_item == HoveredItem) {
2311@@ -421,7 +422,7 @@
2312 foreach (var element in controller.VisibleElements) {
2313 item = (element as DockItem);
2314 if (item != null) {
2315- rect = position_manager.get_item_hover_region (item);
2316+ rect = position_manager.get_hover_region_for_element (item);
2317 if (y < rect.y || y >= rect.y + rect.height || x < rect.x || x >= rect.x + rect.width)
2318 continue;
2319
2320@@ -438,7 +439,7 @@
2321 if (provider == null)
2322 continue;
2323
2324- rect = position_manager.get_item_hover_region (provider);
2325+ rect = position_manager.get_hover_region_for_element (provider);
2326 if (y < rect.y || y >= rect.y + rect.height || x < rect.x || x >= rect.x + rect.width)
2327 continue;
2328
2329@@ -446,7 +447,7 @@
2330 found_hovered_provider = true;
2331
2332 foreach (var element2 in provider.VisibleElements) {
2333- rect = position_manager.get_item_hover_region (element2);
2334+ rect = position_manager.get_hover_region_for_element (element2);
2335 if (y < rect.y || y >= rect.y + rect.height || x < rect.x || x >= rect.x + rect.width)
2336 continue;
2337
2338
2339=== modified file 'lib/Widgets/PreferencesWindow.vala'
2340--- lib/Widgets/PreferencesWindow.vala 2015-07-12 09:40:05 +0000
2341+++ lib/Widgets/PreferencesWindow.vala 2015-07-16 08:37:41 +0000
2342@@ -40,11 +40,13 @@
2343 Gtk.SpinButton sp_hide_delay;
2344 Gtk.SpinButton sp_unhide_delay;
2345 Gtk.Scale s_offset;
2346+ Gtk.Scale s_zoom_percent;
2347
2348 Gtk.Adjustment adj_hide_delay;
2349 Gtk.Adjustment adj_unhide_delay;
2350 Gtk.Adjustment adj_iconsize;
2351 Gtk.Adjustment adj_offset;
2352+ Gtk.Adjustment adj_zoom_percent;
2353
2354 Gtk.Switch sw_hide;
2355 Gtk.Switch sw_primary_display;
2356@@ -54,6 +56,7 @@
2357 Gtk.Switch sw_auto_pinning;
2358 Gtk.Switch sw_pressure_reveal;
2359 Gtk.Switch sw_show_dock_item;
2360+ Gtk.Switch sw_zoom_enabled;
2361
2362 public PreferencesWindow (DockPreferences prefs)
2363 {
2364@@ -105,7 +108,9 @@
2365 adj_unhide_delay = builder.get_object ("adj_unhide_delay") as Gtk.Adjustment;
2366 adj_iconsize = builder.get_object ("adj_iconsize") as Gtk.Adjustment;
2367 adj_offset = builder.get_object ("adj_offset") as Gtk.Adjustment;
2368+ adj_zoom_percent = builder.get_object ("adj_zoom_percent") as Gtk.Adjustment;
2369 s_offset = builder.get_object ("s_offset") as Gtk.Scale;
2370+ s_zoom_percent = builder.get_object ("s_zoom_percent") as Gtk.Scale;
2371 sw_hide = builder.get_object ("sw_hide") as Gtk.Switch;
2372 sw_primary_display = builder.get_object ("sw_primary_display") as Gtk.Switch;
2373 sw_workspace_only = builder.get_object ("sw_workspace_only") as Gtk.Switch;
2374@@ -114,6 +119,7 @@
2375 sw_auto_pinning = builder.get_object ("sw_auto_pinning") as Gtk.Switch;
2376 sw_pressure_reveal = builder.get_object ("sw_pressure_reveal") as Gtk.Switch;
2377 sw_show_dock_item = builder.get_object ("sw_show_dock_item") as Gtk.Switch;
2378+ sw_zoom_enabled = builder.get_object ("sw_zoom_enabled") as Gtk.Switch;
2379 cb_alignment = builder.get_object ("cb_alignment") as Gtk.ComboBoxText;
2380 cb_items_alignment = builder.get_object ("cb_items_alignment") as Gtk.ComboBoxText;
2381
2382@@ -197,6 +203,12 @@
2383 case "UnhideDelay":
2384 adj_unhide_delay.value = prefs.UnhideDelay;
2385 break;
2386+ case "ZoomEnabled":
2387+ sw_zoom_enabled.set_active (prefs.ZoomEnabled);
2388+ break;
2389+ case "ZoomPercent":
2390+ adj_zoom_percent.value = prefs.ZoomPercent;
2391+ break;
2392 // Ignored settings
2393 case "DockItems":
2394 break;
2395@@ -292,6 +304,17 @@
2396 prefs.ShowDockItem = ((Gtk.Switch) widget).get_active ();
2397 }
2398
2399+ void zoom_enabled_toggled (GLib.Object widget, ParamSpec param)
2400+ {
2401+ if (((Gtk.Switch) widget).get_active ()) {
2402+ prefs.ZoomEnabled = true;
2403+ s_zoom_percent.sensitive = true;
2404+ } else {
2405+ prefs.ZoomEnabled = false;
2406+ s_zoom_percent.sensitive = false;
2407+ }
2408+ }
2409+
2410 void iconsize_changed (Gtk.Adjustment adj)
2411 {
2412 prefs.IconSize = (int) adj.value;
2413@@ -312,6 +335,11 @@
2414 prefs.UnhideDelay = (int) adj.value;
2415 }
2416
2417+ void zoom_percent_changed (Gtk.Adjustment adj)
2418+ {
2419+ prefs.ZoomPercent = (int) adj.value;
2420+ }
2421+
2422 void monitor_changed (Gtk.ComboBox widget)
2423 {
2424 prefs.Monitor = ((Gtk.ComboBoxText) widget).get_active_text ();
2425@@ -329,6 +357,7 @@
2426 cb_display_plug.changed.connect (monitor_changed);
2427 adj_iconsize.value_changed.connect (iconsize_changed);
2428 adj_offset.value_changed.connect (offset_changed);
2429+ adj_zoom_percent.value_changed.connect (zoom_percent_changed);
2430 sw_hide.notify["active"].connect (hide_toggled);
2431 sw_primary_display.notify["active"].connect (primary_display_toggled);
2432 sw_workspace_only.notify["active"].connect (workspace_only_toggled);
2433@@ -337,6 +366,7 @@
2434 sw_auto_pinning.notify["active"].connect (auto_pinning_toggled);
2435 sw_pressure_reveal.notify["active"].connect (pressure_reveal_toggled);
2436 sw_show_dock_item.notify["active"].connect (show_dock_item_toggled);
2437+ sw_zoom_enabled.notify["active"].connect (zoom_enabled_toggled);
2438 cb_alignment.changed.connect (cb_alignment_changed);
2439 cb_items_alignment.changed.connect (cb_items_alignment_changed);
2440 }
2441@@ -373,7 +403,9 @@
2442
2443 adj_iconsize.value = prefs.IconSize;
2444 adj_offset.value = prefs.Offset;
2445+ adj_zoom_percent.value = prefs.ZoomPercent;
2446 s_offset.sensitive = (prefs.Alignment == Gtk.Align.CENTER);
2447+ s_zoom_percent.sensitive = prefs.ZoomEnabled;
2448 sw_hide.set_active (prefs.HideMode != HideType.NONE);
2449 sw_primary_display.set_active (prefs.Monitor == "");
2450 sw_workspace_only.set_active (prefs.CurrentWorkspaceOnly);
2451@@ -382,6 +414,7 @@
2452 sw_auto_pinning.set_active (prefs.AutoPinning);
2453 sw_pressure_reveal.set_active (prefs.PressureReveal);
2454 sw_show_dock_item.set_active (prefs.ShowDockItem);
2455+ sw_zoom_enabled.set_active (prefs.ZoomEnabled);
2456 cb_alignment.active_id = ((int) prefs.Alignment).to_string ();
2457 cb_items_alignment.active_id = ((int) prefs.ItemsAlignment).to_string ();
2458 cb_items_alignment.sensitive = (prefs.Alignment == Gtk.Align.FILL);

Subscribers

People subscribed via source and target branches

to status/vote changes: