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

Proposed by Rico Tzschichholz
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 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
1328. By Rico Tzschichholz

animatedrenderer: Always initialize frame if a redraw is scheduled

1329. By Rico Tzschichholz

po: Update translations

1330. By Rico Tzschichholz

dockrenderer: Guard duration-calculations which are used for animations

1331. By Rico Tzschichholz

Update symbols

1332. By Rico Tzschichholz

color: Avoid double setting of out-vars in hsv_to_rgb

1333. By Rico Tzschichholz

color: Clarify documention of set_min/max_* methods

1334. By Rico Tzschichholz

hidemanager: Add dodge-active hide-mode

1335. By Rico Tzschichholz

prefswindow: Use Gtk.Stack if available

1337. By Rico Tzschichholz

prefswindow: Allow closing the window using "Escape"

1338. By Rico Tzschichholz

po: Update translations

1339. By Rico Tzschichholz

ui: Tweak minimum gtk+ version for conditional 3.4 support

1340. By Rico Tzschichholz

build: Make sure to enable maintainer-mode by default

1341. By Rico Tzschichholz

Add icon-zoom preferences and expose gui-settings

1342. By Rico Tzschichholz

Add optional zoom animation when hovering dock-items

1343. By Rico Tzschichholz

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
=== modified file 'data/ui/preferences.ui'
--- data/ui/preferences.ui 2015-07-12 17:08:16 +0000
+++ data/ui/preferences.ui 2015-07-16 08:37:41 +0000
@@ -42,6 +42,13 @@
42 <property name="upper">2500</property>42 <property name="upper">2500</property>
43 <property name="step_increment">50</property>43 <property name="step_increment">50</property>
44 </object>44 </object>
45 <object class="GtkAdjustment" id="adj_zoom_percent">
46 <property name="lower">100</property>
47 <property name="upper">200</property>
48 <property name="value">150</property>
49 <property name="step_increment">5</property>
50 <property name="page_increment">10</property>
51 </object>
45 <object class="GtkStack" id="dock_preferences">52 <object class="GtkStack" id="dock_preferences">
46 <property name="visible">True</property>53 <property name="visible">True</property>
47 <property name="can_focus">False</property>54 <property name="can_focus">False</property>
@@ -266,6 +273,44 @@
266 <property name="width">2</property>273 <property name="width">2</property>
267 </packing>274 </packing>
268 </child>275 </child>
276 <child>
277 <object class="GtkScale" id="s_zoom_percent">
278 <property name="visible">True</property>
279 <property name="can_focus">True</property>
280 <property name="adjustment">adj_zoom_percent</property>
281 <property name="digits">0</property>
282 <property name="value_pos">right</property>
283 </object>
284 <packing>
285 <property name="left_attach">3</property>
286 <property name="top_attach">6</property>
287 </packing>
288 </child>
289 <child>
290 <object class="GtkSwitch" id="sw_zoom_enabled">
291 <property name="visible">True</property>
292 <property name="can_focus">True</property>
293 <property name="halign">start</property>
294 <property name="valign">center</property>
295 </object>
296 <packing>
297 <property name="left_attach">2</property>
298 <property name="top_attach">6</property>
299 </packing>
300 </child>
301 <child>
302 <object class="GtkLabel" id="l_iconzoom">
303 <property name="visible">True</property>
304 <property name="can_focus">False</property>
305 <property name="halign">end</property>
306 <property name="label" translatable="yes">Icon Zoom:</property>
307 <property name="justify">right</property>
308 </object>
309 <packing>
310 <property name="left_attach">1</property>
311 <property name="top_attach">6</property>
312 </packing>
313 </child>
269 </object>314 </object>
270 <packing>315 <packing>
271 <property name="name">grid_appearance</property>316 <property name="name">grid_appearance</property>
272317
=== modified file 'docs/Makefile.am'
--- docs/Makefile.am 2015-06-04 20:24:37 +0000
+++ docs/Makefile.am 2015-07-16 08:37:41 +0000
@@ -33,6 +33,7 @@
33 $(top_srcdir)/lib/Drawing/DockSurface.vala \33 $(top_srcdir)/lib/Drawing/DockSurface.vala \
34 $(top_srcdir)/lib/Drawing/DockTheme.vala \34 $(top_srcdir)/lib/Drawing/DockTheme.vala \
35 $(top_srcdir)/lib/Drawing/Easing.vala \35 $(top_srcdir)/lib/Drawing/Easing.vala \
36 $(top_srcdir)/lib/Drawing/SurfaceCache.vala \
36 $(top_srcdir)/lib/Drawing/Theme.vala \37 $(top_srcdir)/lib/Drawing/Theme.vala \
37 $(top_srcdir)/lib/Factories/AbstractMain.vala \38 $(top_srcdir)/lib/Factories/AbstractMain.vala \
38 $(top_srcdir)/lib/Factories/Factory.vala \39 $(top_srcdir)/lib/Factories/Factory.vala \
3940
=== modified file 'lib/DockController.vala'
--- lib/DockController.vala 2015-06-11 05:36:16 +0000
+++ lib/DockController.vala 2015-07-16 08:37:41 +0000
@@ -348,7 +348,6 @@
348 && added.size != removed.size) {348 && added.size != removed.size) {
349 position_manager.update (renderer.theme);349 position_manager.update (renderer.theme);
350 } else {350 } else {
351 position_manager.reset_item_caches ();
352 position_manager.update_regions ();351 position_manager.update_regions ();
353 }352 }
354 window.update_icon_regions ();353 window.update_icon_regions ();
@@ -362,7 +361,6 @@
362 update_visible_elements ();361 update_visible_elements ();
363 362
364 foreach (unowned DockElement item in moved_items) {363 foreach (unowned DockElement item in moved_items) {
365 position_manager.reset_item_cache (item);
366 unowned ApplicationDockItem? app_item = (item as ApplicationDockItem);364 unowned ApplicationDockItem? app_item = (item as ApplicationDockItem);
367 if (app_item != null)365 if (app_item != null)
368 window.update_icon_region (app_item);366 window.update_icon_region (app_item);
369367
=== modified file 'lib/DockPreferences.vala'
--- lib/DockPreferences.vala 2015-05-07 12:46:58 +0000
+++ lib/DockPreferences.vala 2015-07-16 08:37:41 +0000
@@ -29,6 +29,9 @@
29 public const int MIN_ICON_SIZE = 24;29 public const int MIN_ICON_SIZE = 24;
30 public const int MAX_ICON_SIZE = 128;30 public const int MAX_ICON_SIZE = 128;
31 31
32 public const int MIN_ICON_ZOOM = 100;
33 public const int MAX_ICON_ZOOM = 200;
34
32 [Description(nick = "current-workspace-only", blurb = "Whether to show only windows of the current workspace.")]35 [Description(nick = "current-workspace-only", blurb = "Whether to show only windows of the current workspace.")]
33 public bool CurrentWorkspaceOnly { get; set; }36 public bool CurrentWorkspaceOnly { get; set; }
34 37
@@ -80,6 +83,12 @@
80 [Description(nick = "show-dock-item", blurb = "Whether to show the item for the dock itself.")]83 [Description(nick = "show-dock-item", blurb = "Whether to show the item for the dock itself.")]
81 public bool ShowDockItem { get; set; }84 public bool ShowDockItem { get; set; }
82 85
86 [Description(nick = "zoom-enabled", blurb = "Whether the dock will zoom when hovered.")]
87 public bool ZoomEnabled { get; set; }
88
89 [Description(nick = "zoom-percent", blurb = "The dock's icon-zoom (in percent).")]
90 public uint ZoomPercent { get; set; }
91
83 /**92 /**
84 * {@inheritDoc}93 * {@inheritDoc}
85 */94 */
@@ -132,6 +141,8 @@
132 PinnedOnly = false;141 PinnedOnly = false;
133 AutoPinning = true;142 AutoPinning = true;
134 ShowDockItem = true;143 ShowDockItem = true;
144 ZoomEnabled = false;
145 ZoomPercent = 150;
135 }146 }
136 147
137 /**148 /**
@@ -235,6 +246,16 @@
235 246
236 case "ShowDockItem":247 case "ShowDockItem":
237 break;248 break;
249
250 case "ZoomEnabled":
251 break;
252
253 case "ZoomPercent":
254 if (ZoomPercent < MIN_ICON_ZOOM)
255 ZoomPercent = MIN_ICON_ZOOM;
256 else if (ZoomPercent > MAX_ICON_ZOOM)
257 ZoomPercent = MAX_ICON_ZOOM;
258 break;
238 }259 }
239 }260 }
240 }261 }
241262
=== modified file 'lib/DockRenderer.vala'
--- lib/DockRenderer.vala 2015-07-03 20:25:11 +0000
+++ lib/DockRenderer.vala 2015-07-16 08:37:41 +0000
@@ -44,6 +44,18 @@
44 */44 */
45 [CCode (notify = false)]45 [CCode (notify = false)]
46 double opacity { get; private set; }46 double opacity { get; private set; }
47
48 /**
49 * The current progress [0.0..1.0] of the zoom-in-animation of the dock.
50 */
51 [CCode (notify = false)]
52 public double zoom_in_progress { get; private set; }
53
54 /**
55 * The current local cursor-position on the dock if hovered.
56 */
57 [CCode (notify = false)]
58 public Gdk.Point local_cursor { get; private set; }
4759
48 DockSurface? main_buffer = null;60 DockSurface? main_buffer = null;
49 DockSurface? fade_buffer = null;61 DockSurface? fade_buffer = null;
@@ -57,16 +69,19 @@
57 DockSurface? urgent_glow_buffer = null;69 DockSurface? urgent_glow_buffer = null;
58 70
59 int64 last_hide = 0;71 int64 last_hide = 0;
72 int64 last_hovered_changed = 0;
60 73
61 bool screen_is_composited = false;74 bool screen_is_composited = false;
62 uint reset_position_manager_timer = 0;75 uint reset_position_manager_timer = 0;
63 int window_scale_factor = 1;76 int window_scale_factor = 1;
64 bool is_first_frame = true;77 bool is_first_frame = true;
78 bool zoom_changed = false;
65 79
66 ulong gtk_theme_name_changed_id = 0;80 ulong gtk_theme_name_changed_id = 0;
67 81
68 double dynamic_animation_offset = 0.0;82 double dynamic_animation_offset = 0.0;
69 83
84 Gee.ArrayList<unowned DockItem> current_items;
70 Gee.HashSet<DockItem> transient_items;85 Gee.HashSet<DockItem> transient_items;
71#if BENCHMARK86#if BENCHMARK
72 Gee.ArrayList<string> benchmark;87 Gee.ArrayList<string> benchmark;
@@ -86,6 +101,7 @@
86 construct101 construct
87 {102 {
88 transient_items = new Gee.HashSet<DockItem> ();103 transient_items = new Gee.HashSet<DockItem> ();
104 current_items = new Gee.ArrayList<unowned DockItem> ();
89#if BENCHMARK105#if BENCHMARK
90 benchmark = new Gee.ArrayList<string> ();106 benchmark = new Gee.ArrayList<string> ();
91#endif107#endif
@@ -104,6 +120,7 @@
104 120
105 controller.window.notify["HoveredItem"].connect (animated_draw);121 controller.window.notify["HoveredItem"].connect (animated_draw);
106 controller.hide_manager.notify["Hidden"].connect (hidden_changed);122 controller.hide_manager.notify["Hidden"].connect (hidden_changed);
123 controller.hide_manager.notify["Hovered"].connect (hovered_changed);
107 }124 }
108 125
109 ~DockRenderer ()126 ~DockRenderer ()
@@ -112,6 +129,7 @@
112 theme.notify.disconnect (theme_changed);129 theme.notify.disconnect (theme_changed);
113 130
114 controller.hide_manager.notify["Hidden"].disconnect (hidden_changed);131 controller.hide_manager.notify["Hidden"].disconnect (hidden_changed);
132 controller.hide_manager.notify["Hovered"].disconnect (hovered_changed);
115 controller.window.notify["HoveredItem"].disconnect (animated_draw);133 controller.window.notify["HoveredItem"].disconnect (animated_draw);
116 }134 }
117 135
@@ -221,7 +239,9 @@
221 {239 {
222 return_if_fail (theme != null);240 return_if_fail (theme != null);
223 241
224 screen_is_composited = controller.position_manager.screen_is_composited;242 unowned PositionManager position_manager = controller.position_manager;
243
244 screen_is_composited = position_manager.screen_is_composited;
225 dynamic_animation_offset = 0.0;245 dynamic_animation_offset = 0.0;
226 246
227 var fade_opacity = theme.FadeOpacity;247 var fade_opacity = theme.FadeOpacity;
@@ -237,14 +257,78 @@
237 } else {257 } else {
238 hide_progress = (controller.hide_manager.Hidden ? 1.0 : 0.0);258 hide_progress = (controller.hide_manager.Hidden ? 1.0 : 0.0);
239 }259 }
260
261 var zoom_duration = 150 * 1000;
262 var zoom_time = int64.max (0LL, frame_time - last_hovered_changed);
263 double zoom_progress;
264 if (zoom_time < zoom_duration)
265 zoom_progress = Drawing.easing_for_mode (AnimationMode.LINEAR, zoom_time, zoom_duration);
266 else
267 zoom_progress = 1.0;
268 if (!controller.hide_manager.Hovered)
269 zoom_progress = 1.0 - zoom_progress;
270 zoom_progress *= 1.0 - hide_progress;
271 zoom_in_progress = zoom_progress;
240 } else {272 } else {
241 hide_progress = 0.0;273 hide_progress = 0.0;
274 zoom_in_progress = 0.0;
242 }275 }
243 276
244 if (fade_opacity < 1.0)277 if (fade_opacity < 1.0)
245 opacity = 1.0 - (1.0 - fade_opacity) * hide_progress;278 opacity = 1.0 - (1.0 - fade_opacity) * hide_progress;
246 else279 else
247 opacity = 1.0;280 opacity = 1.0;
281
282 // Update *ordered* list of items
283 current_items.clear ();
284 current_items.add_all (controller.VisibleItems);
285
286 if (screen_is_composited) {
287 var add_time = 0LL;
288 var remove_time = 0LL;
289 var move_time = 0LL;
290 var move_duration = theme.ItemMoveTime * 1000;
291
292 var transient_items_it = transient_items.iterator ();
293 while (transient_items_it.next ()) {
294 var item = transient_items_it.get ();
295 add_time = item.AddTime;
296 remove_time = item.RemoveTime;
297
298 if (add_time > remove_time) {
299 move_time = frame_time - add_time;
300 if (move_time < move_duration) {
301 if (!current_items.contains (item))
302 current_items.add (item);
303 } else {
304 transient_items_it.remove ();
305 }
306 } else if (remove_time > 0) {
307 move_time = frame_time - remove_time;
308 if (move_time < move_duration) {
309 if (!current_items.contains (item))
310 current_items.add (item);
311 } else {
312 transient_items_it.remove ();
313 }
314 }
315 }
316 } else {
317 transient_items.clear ();
318 }
319
320#if HAVE_GEE_0_8
321 current_items.sort ((CompareDataFunc) compare_dock_item_position);
322#else
323 current_items.sort ((CompareFunc) compare_dock_item_position);
324#endif
325
326 // Calculate positions for given ordered list of items
327 position_manager.update_draw_values (current_items,
328 (PositionManager.DockItemDrawValueFunc) animate_draw_value_for_item,
329 (PositionManager.DrawValuesFunc) post_process_draw_values);
330
331 background_rect = position_manager.get_background_region ();
248 }332 }
249 333
250 /**334 /**
@@ -262,7 +346,6 @@
262 unowned PositionManager position_manager = controller.position_manager;346 unowned PositionManager position_manager = controller.position_manager;
263 unowned DockItem dragged_item = controller.drag_manager.DragItem;347 unowned DockItem dragged_item = controller.drag_manager.DragItem;
264 var win_rect = position_manager.get_dock_window_region ();348 var win_rect = position_manager.get_dock_window_region ();
265 var items = controller.VisibleItems;
266 349
267 if (main_buffer == null) {350 if (main_buffer == null) {
268 main_buffer = new DockSurface.with_surface (win_rect.width, win_rect.height, cr.get_target ());351 main_buffer = new DockSurface.with_surface (win_rect.width, win_rect.height, cr.get_target ());
@@ -295,7 +378,7 @@
295 cr.paint ();378 cr.paint ();
296 cr.restore ();379 cr.restore ();
297 380
298 foreach (var item in items)381 foreach (unowned DockItem item in current_items)
299 draw_urgent_glow (item, cr, frame_time);382 draw_urgent_glow (item, cr, frame_time);
300 383
301 return;384 return;
@@ -320,118 +403,11 @@
320 unowned Cairo.Context item_cr = item_buffer.Context;403 unowned Cairo.Context item_cr = item_buffer.Context;
321 unowned Cairo.Context shadow_cr = shadow_buffer.Context;404 unowned Cairo.Context shadow_cr = shadow_buffer.Context;
322 405
323 // draw transient items onto the dock buffer and calculate the resulting
324 // dynamic-animation-offset used to animate the background-resize
325 if (screen_is_composited) {
326 var add_time = 0LL;
327 var remove_time = 0LL;
328 var move_time = 0LL;
329 var move_duration = theme.ItemMoveTime * 1000;
330
331 var transient_items_it = transient_items.iterator ();
332 while (transient_items_it.next ()) {
333 var item = transient_items_it.get ();
334 add_time = item.AddTime;
335 remove_time = item.RemoveTime;
336
337 if (add_time > remove_time) {
338 move_time = int64.max (0LL, frame_time - add_time);
339 if (move_time < move_duration) {
340 var move_animation_progress = 1.0 - Drawing.easing_for_mode (AnimationMode.EASE_OUT_QUINT, move_time, move_duration);
341 dynamic_animation_offset -= move_animation_progress * (position_manager.IconSize + position_manager.ItemPadding);
342 } else {
343 transient_items_it.remove ();
344 }
345 } else if (remove_time > 0) {
346 move_time = int64.max (0LL, frame_time - remove_time);
347 if (move_time < move_duration) {
348 var move_animation_progress = 1.0 - Drawing.easing_for_mode (AnimationMode.EASE_IN_QUINT, move_time, move_duration);
349 dynamic_animation_offset += move_animation_progress * (position_manager.IconSize + position_manager.ItemPadding);
350 } else {
351 transient_items_it.remove ();
352 }
353 } else {
354 continue;
355 }
356#if BENCHMARK
357 start2 = new DateTime.now_local ();
358#endif
359 // Do not draw the currently dragged item or items which are suppose to be drawn later
360 if (move_time < move_duration && item.IsVisible && dragged_item != item && !items.contains (item)) {
361 var draw_value = get_animated_draw_value_for_item (item, frame_time);
362 draw_item (item_cr, item, ref draw_value, frame_time);
363 draw_item_shadow (shadow_cr, item, ref draw_value);
364 }
365#if BENCHMARK
366 end2 = new DateTime.now_local ();
367 benchmark.add ("item render time - %f ms".printf (end2.difference (start2) / 1000.0));
368#endif
369 }
370 } else {
371 transient_items.clear ();
372 }
373
374 background_rect = position_manager.get_background_region ();
375
376 // calculate drawing offset406 // calculate drawing offset
377 var x_offset = 0, y_offset = 0;407 var x_offset = 0, y_offset = 0;
378 if (opacity == 1.0)408 if (opacity == 1.0)
379 position_manager.get_dock_draw_position (out x_offset, out y_offset);409 position_manager.get_dock_draw_position (out x_offset, out y_offset);
380 410
381 // calculate drawing animation-offset
382 var x_animation_offset = 0, y_animation_offset = 0;
383 switch (controller.prefs.Alignment) {
384 default:
385 case Gtk.Align.CENTER:
386 if (position_manager.is_horizontal_dock ())
387 x_animation_offset -= (int) Math.round (dynamic_animation_offset / 2.0);
388 else
389 y_animation_offset -= (int) Math.round (dynamic_animation_offset / 2.0);
390 background_rect = { background_rect.x + x_offset + x_animation_offset, background_rect.y + y_offset + y_animation_offset,
391 background_rect.width -2 * x_animation_offset, background_rect.height -2 * y_animation_offset };
392 break;
393 case Gtk.Align.START:
394 if (position_manager.is_horizontal_dock ())
395 background_rect = { background_rect.x + x_offset, background_rect.y + y_offset,
396 background_rect.width + (int) Math.round (dynamic_animation_offset), background_rect.height };
397 else
398 background_rect = { background_rect.x + x_offset, background_rect.y + y_offset,
399 background_rect.width, background_rect.height + (int) Math.round (dynamic_animation_offset) };
400 break;
401 case Gtk.Align.END:
402 if (position_manager.is_horizontal_dock ())
403 x_animation_offset -= (int) Math.round (dynamic_animation_offset);
404 else
405 y_animation_offset -= (int) Math.round (dynamic_animation_offset);
406 background_rect = { background_rect.x + x_offset + x_animation_offset, background_rect.y + y_offset + y_animation_offset,
407 background_rect.width - x_animation_offset, background_rect.height - y_animation_offset };
408 break;
409 case Gtk.Align.FILL:
410 switch (controller.prefs.ItemsAlignment) {
411 default:
412 case Gtk.Align.FILL:
413 case Gtk.Align.CENTER:
414 if (position_manager.is_horizontal_dock ())
415 x_animation_offset -= (int) Math.round (dynamic_animation_offset / 2.0);
416 else
417 y_animation_offset -= (int) Math.round (dynamic_animation_offset / 2.0);
418 break;
419 case Gtk.Align.START:
420 break;
421 case Gtk.Align.END:
422 if (position_manager.is_horizontal_dock ())
423 x_animation_offset -= (int) Math.round (dynamic_animation_offset);
424 else
425 y_animation_offset -= (int) Math.round (dynamic_animation_offset);
426 break;
427 }
428 background_rect = { background_rect.x + x_offset, background_rect.y + y_offset, background_rect.width, background_rect.height };
429 break;
430 }
431
432 x_offset += x_animation_offset;
433 y_offset += y_animation_offset;
434
435 // composite dock layers and make sure to draw onto the window's context with one operation411 // composite dock layers and make sure to draw onto the window's context with one operation
436 main_buffer.clear ();412 main_buffer.clear ();
437 unowned Cairo.Context main_cr = main_buffer.Context;413 unowned Cairo.Context main_cr = main_buffer.Context;
@@ -441,22 +417,22 @@
441 start2 = new DateTime.now_local ();417 start2 = new DateTime.now_local ();
442#endif418#endif
443 // draw background-layer419 // draw background-layer
444 draw_dock_background (main_cr, background_rect);420 draw_dock_background (main_cr, background_rect, x_offset, y_offset);
445#if BENCHMARK421#if BENCHMARK
446 end2 = new DateTime.now_local ();422 end2 = new DateTime.now_local ();
447 benchmark.add ("background render time - %f ms".printf (end2.difference (start2) / 1000.0));423 benchmark.add ("background render time - %f ms".printf (end2.difference (start2) / 1000.0));
448#endif424#endif
449 425
450 // draw each item onto the dock buffer426 // draw each item onto the dock buffer
451 foreach (var item in items) {427 foreach (unowned DockItem item in current_items) {
452#if BENCHMARK428#if BENCHMARK
453 start2 = new DateTime.now_local ();429 start2 = new DateTime.now_local ();
454#endif430#endif
455 // Do not draw the currently dragged item431 // Do not draw the currently dragged item
456 if (item.IsVisible && dragged_item != item) {432 if (item.IsVisible && dragged_item != item) {
457 var draw_value = get_animated_draw_value_for_item (item, frame_time);433 var draw_value = position_manager.get_draw_value_for_item (item);
458 draw_item (item_cr, item, ref draw_value, frame_time);434 draw_item (item_cr, item, draw_value, frame_time);
459 draw_item_shadow (shadow_cr, item, ref draw_value);435 draw_item_shadow (shadow_cr, item, draw_value);
460 }436 }
461#if BENCHMARK437#if BENCHMARK
462 end2 = new DateTime.now_local ();438 end2 = new DateTime.now_local ();
@@ -489,7 +465,7 @@
489 465
490 // draw urgent-glow if dock is completely hidden466 // draw urgent-glow if dock is completely hidden
491 if (hide_progress == 1.0) {467 if (hide_progress == 1.0) {
492 foreach (var item in items)468 foreach (unowned DockItem item in current_items)
493 draw_urgent_glow (item, cr, frame_time);469 draw_urgent_glow (item, cr, frame_time);
494 }470 }
495 471
@@ -520,7 +496,7 @@
520 }496 }
521 }497 }
522 498
523 void draw_dock_background (Cairo.Context cr, Gdk.Rectangle background_rect)499 void draw_dock_background (Cairo.Context cr, Gdk.Rectangle background_rect, int x_offset, int y_offset)
524 {500 {
525 unowned PositionManager position_manager = controller.position_manager;501 unowned PositionManager position_manager = controller.position_manager;
526 502
@@ -534,21 +510,20 @@
534 background_buffer = theme.create_background (background_rect.width, background_rect.height,510 background_buffer = theme.create_background (background_rect.width, background_rect.height,
535 position_manager.Position, main_buffer);511 position_manager.Position, main_buffer);
536 512
537 cr.set_source_surface (background_buffer.Internal, background_rect.x, background_rect.y);513 cr.set_source_surface (background_buffer.Internal, background_rect.x + x_offset, background_rect.y + y_offset);
538 cr.paint ();514 cr.paint ();
539 }515 }
540 516
541 PositionManager.DockItemDrawValue get_animated_draw_value_for_item (DockItem item, int64 frame_time)517 [CCode (instance_pos = -1)]
518 void animate_draw_value_for_item (DockItem item, PositionManager.DockItemDrawValue draw_value)
542 {519 {
543 unowned PositionManager position_manager = controller.position_manager;520 unowned PositionManager position_manager = controller.position_manager;
544 unowned DockItem hovered_item = controller.window.HoveredItem;521 unowned DockItem hovered_item = controller.window.HoveredItem;
545 unowned DragManager drag_manager = controller.drag_manager;522 unowned DragManager drag_manager = controller.drag_manager;
546 523
547 var icon_size = position_manager.IconSize;524 var icon_size = (int) draw_value.icon_size;
548 var position = position_manager.Position;525 var position = position_manager.Position;
549 526 var x_offset = 0.0, y_offset = 0.0;
550 // get item's draw-value
551 var draw_value = position_manager.get_draw_value_for_item (item);
552 527
553 // check for and calculate click-animation528 // check for and calculate click-animation
554 var max_click_time = item.ClickedAnimation == Animation.BOUNCE ? theme.LaunchBounceTime : theme.ClickTime;529 var max_click_time = item.ClickedAnimation == Animation.BOUNCE ? theme.LaunchBounceTime : theme.ClickTime;
@@ -564,8 +539,7 @@
564 case Animation.BOUNCE:539 case Animation.BOUNCE:
565 if (!screen_is_composited)540 if (!screen_is_composited)
566 break;541 break;
567 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)));542 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)));
568 draw_value.move_in (position, change);
569 break;543 break;
570 case Animation.DARKEN:544 case Animation.DARKEN:
571 draw_value.darken = double.max (0, Math.sin (Math.PI * click_animation_progress)) * 0.5;545 draw_value.darken = double.max (0, Math.sin (Math.PI * click_animation_progress)) * 0.5;
@@ -630,8 +604,40 @@
630 var urgent_time = int64.max (0LL, frame_time - item.LastUrgent);604 var urgent_time = int64.max (0LL, frame_time - item.LastUrgent);
631 var bounce_animation_progress = urgent_time / (double) (theme.UrgentBounceTime * 1000);605 var bounce_animation_progress = urgent_time / (double) (theme.UrgentBounceTime * 1000);
632 if (bounce_animation_progress < 1.0) {606 if (bounce_animation_progress < 1.0) {
633 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)));607 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)));
634 draw_value.move_in (position, change);608 }
609 }
610
611 // animate addition/removal
612 unowned DockContainer? container = item.Container;
613 var allow_animation = (screen_is_composited && (container == null || container.AddTime < item.AddTime));
614 if (allow_animation && item.AddTime > item.RemoveTime) {
615 var move_duration = theme.ItemMoveTime * 1000;
616 var move_time = int64.max (0LL, frame_time - item.AddTime);
617 if (move_time < move_duration) {
618 var move_animation_progress = 1.0 - Drawing.easing_for_mode (AnimationMode.LINEAR, move_time, move_duration);
619 draw_value.opacity = Drawing.easing_for_mode (AnimationMode.EASE_IN_EXPO, move_time, move_duration);
620 y_offset -= move_animation_progress * (icon_size + position_manager.BottomPadding);
621 draw_value.show_indicator = false;
622
623 // calculate the resulting incremental dynamic-animation-offset used to animate the background-resize and icon-offset
624 move_animation_progress = 1.0 - Drawing.easing_for_mode (AnimationMode.EASE_OUT_QUINT, move_time, move_duration);
625 dynamic_animation_offset -= move_animation_progress * (icon_size + position_manager.ItemPadding);
626 x_offset += dynamic_animation_offset;
627 }
628 } else if (allow_animation && item.RemoveTime > 0) {
629 var move_duration = theme.ItemMoveTime * 1000;
630 var move_time = int64.max (0LL, frame_time - item.RemoveTime);
631 if (move_time < move_duration) {
632 var move_animation_progress = Drawing.easing_for_mode (AnimationMode.LINEAR, move_time, move_duration);
633 draw_value.opacity = 1.0 - Drawing.easing_for_mode (AnimationMode.EASE_OUT_EXPO, move_time, move_duration);
634 y_offset -= move_animation_progress * (icon_size + position_manager.BottomPadding);
635 draw_value.show_indicator = false;
636
637 // calculate the resulting incremental dynamic-animation-offset used to animate the background-resize and icon-offset
638 move_animation_progress = 1.0 - Drawing.easing_for_mode (AnimationMode.EASE_IN_QUINT, move_time, move_duration);
639 dynamic_animation_offset += move_animation_progress * (icon_size + position_manager.ItemPadding);
640 x_offset += dynamic_animation_offset - (icon_size + position_manager.ItemPadding);
635 }641 }
636 }642 }
637 643
@@ -650,37 +656,12 @@
650 move_animation_progress = 1.0 - Drawing.easing_for_mode (AnimationMode.EASE_OUT_CIRC, move_time, move_duration);656 move_animation_progress = 1.0 - Drawing.easing_for_mode (AnimationMode.EASE_OUT_CIRC, move_time, move_duration);
651 }657 }
652 var change = move_animation_progress * (icon_size + position_manager.ItemPadding);658 var change = move_animation_progress * (icon_size + position_manager.ItemPadding);
653 draw_value.move_right (position, (item.Position < item.LastPosition ? change : -change));659 x_offset += (item.Position < item.LastPosition ? change : -change);
654 } else {660 } else {
655 item.unset_move_state ();661 item.unset_move_state ();
656 }662 }
657 }663 }
658 664
659 // animate addition/removal
660 unowned DockContainer? container = item.Container;
661 var allow_animation = (screen_is_composited && (container == null || container.AddTime < item.AddTime));
662 if (allow_animation && item.AddTime > item.RemoveTime) {
663 var move_duration = theme.ItemMoveTime * 1000;
664 var move_time = int64.max (0LL, frame_time - item.AddTime);
665 if (move_time < move_duration) {
666 var move_animation_progress = 1.0 - Drawing.easing_for_mode (AnimationMode.LINEAR, move_time, move_duration);
667 draw_value.opacity = Drawing.easing_for_mode (AnimationMode.EASE_IN_EXPO, move_time, move_duration);
668 var change = move_animation_progress * (icon_size + position_manager.BottomPadding);
669 draw_value.move_in (position, -change);
670 draw_value.show_indicator = false;
671 }
672 } else if (allow_animation && item.RemoveTime > 0) {
673 var move_duration = theme.ItemMoveTime * 1000;
674 var move_time = int64.max (0LL, frame_time - item.RemoveTime);
675 if (move_time < move_duration) {
676 var move_animation_progress = Drawing.easing_for_mode (AnimationMode.LINEAR, move_time, move_duration);
677 draw_value.opacity = 1.0 - Drawing.easing_for_mode (AnimationMode.EASE_OUT_EXPO, move_time, move_duration);
678 var change = move_animation_progress * (icon_size + position_manager.BottomPadding);
679 draw_value.move_in (position, -change);
680 draw_value.show_indicator = false;
681 }
682 }
683
684 // animate icon on invalid state665 // animate icon on invalid state
685 if ((item.State & ItemState.INVALID) != 0) {666 if ((item.State & ItemState.INVALID) != 0) {
686 var invalid_duration = 3000 * 1000;667 var invalid_duration = 3000 * 1000;
@@ -692,13 +673,71 @@
692 }673 }
693 }674 }
694 675
695 return draw_value;676 if (x_offset != 0.0)
696 }677 draw_value.move_right (position, x_offset);
697 678
698 void draw_item (Cairo.Context cr, DockItem item, ref PositionManager.DockItemDrawValue draw_value, int64 frame_time)679 if (y_offset != 0.0)
699 {680 draw_value.move_in (position, y_offset);
700 unowned PositionManager position_manager = controller.position_manager;681 }
701 var icon_size = position_manager.IconSize;682
683 [CCode (instance_pos = -1)]
684 void post_process_draw_values (Gee.HashMap<DockElement, PositionManager.DockItemDrawValue?> draw_values)
685 {
686 if (dynamic_animation_offset == 0.0)
687 return;
688
689 unowned PositionManager position_manager = controller.position_manager;
690 var position = position_manager.Position;
691
692 var x_offset = 0.0;
693
694 switch (position_manager.Alignment) {
695 default:
696 case Gtk.Align.CENTER:
697 x_offset -= Math.round (dynamic_animation_offset / 2.0);
698 break;
699 case Gtk.Align.START:
700 break;
701 case Gtk.Align.END:
702 x_offset -= Math.round (dynamic_animation_offset);
703 break;
704 case Gtk.Align.FILL:
705 switch (position_manager.ItemsAlignment) {
706 default:
707 case Gtk.Align.FILL:
708 case Gtk.Align.CENTER:
709 x_offset -= Math.round (dynamic_animation_offset / 2.0);
710 break;
711 case Gtk.Align.START:
712 break;
713 case Gtk.Align.END:
714 x_offset -= Math.round (dynamic_animation_offset);
715 break;
716 }
717 break;
718 }
719
720 if (x_offset == 0.0)
721 return;
722
723#if HAVE_GEE_0_8
724 draw_values.map_iterator ().foreach ((i, val) => {
725 val.move_right (position, x_offset);
726 return true;
727 });
728#else
729 var draw_values_it = draw_values.map_iterator ();
730 while (draw_values_it.next ()) {
731 var val = draw_values_it.get_value ();
732 val.move_right (position, x_offset);
733 }
734#endif
735 }
736
737 void draw_item (Cairo.Context cr, DockItem item, PositionManager.DockItemDrawValue draw_value, int64 frame_time)
738 {
739 unowned PositionManager position_manager = controller.position_manager;
740 var icon_size = (int) draw_value.icon_size;
702 var position = position_manager.Position;741 var position = position_manager.Position;
703 742
704 // load the icon743 // load the icon
@@ -710,7 +749,7 @@
710 749
711 DockSurface? icon_overlay_surface = null;750 DockSurface? icon_overlay_surface = null;
712 if (item.CountVisible || item.ProgressVisible)751 if (item.CountVisible || item.ProgressVisible)
713 icon_overlay_surface = item.get_foreground_surface (draw_item_foreground);752 icon_overlay_surface = item.get_foreground_surface (icon_size * window_scale_factor, icon_size * window_scale_factor, item_buffer, (DrawDataFunc<DockItem>) draw_item_foreground);
714 753
715 if (icon_overlay_surface != null) {754 if (icon_overlay_surface != null) {
716 icon_cr.set_source_surface (icon_overlay_surface.Internal, 0, 0);755 icon_cr.set_source_surface (icon_overlay_surface.Internal, 0, 0);
@@ -766,15 +805,17 @@
766 draw_indicator_state (cr, draw_value.hover_region, item.Indicator, item.State);805 draw_indicator_state (cr, draw_value.hover_region, item.Indicator, item.State);
767 }806 }
768 807
769 void draw_item_shadow (Cairo.Context cr, DockItem item, ref PositionManager.DockItemDrawValue draw_value)808 void draw_item_shadow (Cairo.Context cr, DockItem item, PositionManager.DockItemDrawValue draw_value)
770 {809 {
771 unowned PositionManager position_manager = controller.position_manager;810 unowned PositionManager position_manager = controller.position_manager;
772 var shadow_size = position_manager.IconShadowSize;811 var shadow_size = position_manager.IconShadowSize;
773812 // Inflate size to fit shadow
813 var icon_size = (int) draw_value.icon_size + 2 * shadow_size;
814
774 // load and draw the icon shadow815 // load and draw the icon shadow
775 DockSurface? icon_shadow_surface = null;816 DockSurface? icon_shadow_surface = null;
776 if (shadow_size > 0)817 if (shadow_size > 0)
777 icon_shadow_surface = item.get_background_surface (draw_item_background);818 icon_shadow_surface = item.get_background_surface (icon_size * window_scale_factor, icon_size * window_scale_factor, item_buffer, (DrawDataFunc<DockItem>) draw_item_background);
778 819
779 if (icon_shadow_surface != null) {820 if (icon_shadow_surface != null) {
780 if (window_scale_factor > 1) {821 if (window_scale_factor > 1) {
@@ -793,20 +834,13 @@
793 }834 }
794 }835 }
795 836
796 DockSurface draw_item_foreground (DockItem item, DockSurface icon_surface, DockSurface? current_surface)837 [CCode (instance_pos = -1)]
838 DockSurface draw_item_foreground (int width, int height, DockSurface model, DockItem item)
797 {839 {
798 unowned PositionManager position_manager = controller.position_manager;
799 var width = icon_surface.Width;
800 var height = icon_surface.Height;
801
802 if (current_surface != null
803 && width == current_surface.Width && height == current_surface.Height)
804 return current_surface;
805
806 Logger.verbose ("DockItem.draw_item_overlay (width = %i, height = %i)", width, height);840 Logger.verbose ("DockItem.draw_item_overlay (width = %i, height = %i)", width, height);
807 var surface = new DockSurface.with_dock_surface (width, height, icon_surface);841 var surface = new DockSurface.with_dock_surface (width, height, model);
808 842
809 var icon_size = position_manager.IconSize * window_scale_factor;843 var icon_size = int.min (width, height) * window_scale_factor;
810 var urgent_color = get_styled_color ();844 var urgent_color = get_styled_color ();
811 urgent_color.add_hue (theme.UrgentHueShift);845 urgent_color.add_hue (theme.UrgentHueShift);
812 846
@@ -821,21 +855,18 @@
821 return surface;855 return surface;
822 }856 }
823 857
824 DockSurface draw_item_background (DockItem item, DockSurface icon_surface, DockSurface? current_surface)858 [CCode (instance_pos = -1)]
859 DockSurface draw_item_background (int width, int height, DockSurface model, DockItem item)
825 {860 {
826 unowned PositionManager position_manager = controller.position_manager;861 unowned PositionManager position_manager = controller.position_manager;
827 var shadow_size = position_manager.IconShadowSize * window_scale_factor;862 var shadow_size = position_manager.IconShadowSize * window_scale_factor;
828 863
829 // Inflate size to fit shadow864 var draw_value = position_manager.get_draw_value_for_item (item);
830 var width = icon_surface.Width + 2 * shadow_size;865 var icon_size = (int) draw_value.icon_size;
831 var height = icon_surface.Height + 2 * shadow_size;866 var icon_surface = item.get_surface (icon_size, icon_size, model);
832
833 if (current_surface != null
834 && width == current_surface.Width && height == current_surface.Height)
835 return current_surface;
836 867
837 Logger.verbose ("DockItem.draw_icon_with_shadow (width = %i, height = %i, shadow_size = %i)", width, height, shadow_size);868 Logger.verbose ("DockItem.draw_icon_with_shadow (width = %i, height = %i, shadow_size = %i)", width, height, shadow_size);
838 var surface = new DockSurface.with_dock_surface (width, height, icon_surface);869 var surface = new DockSurface.with_dock_surface (width, height, model);
839 unowned Cairo.Context cr = surface.Context;870 unowned Cairo.Context cr = surface.Context;
840 var shadow_surface = icon_surface.create_mask (0.4, null);871 var shadow_surface = icon_surface.create_mask (0.4, null);
841 872
@@ -976,6 +1007,35 @@
976 animated_draw ();1007 animated_draw ();
977 }1008 }
978 1009
1010 void hovered_changed ()
1011 {
1012 force_frame_time_update ();
1013 var now = frame_time;
1014 var diff = now - last_hovered_changed;
1015 var time = 150 * 1000;
1016
1017 if (diff < time)
1018 last_hovered_changed = now + (diff - time);
1019 else
1020 last_hovered_changed = now;
1021
1022 animated_draw ();
1023 }
1024
1025 public void update_local_cursor (int x, int y)
1026 {
1027 Gdk.Point new_cursor = { x, y };
1028 if (local_cursor == new_cursor)
1029 return;
1030
1031 local_cursor = new_cursor;
1032
1033 if (controller.prefs.ZoomEnabled) {
1034 zoom_changed = true;
1035 animated_draw ();
1036 }
1037 }
1038
979 public void animate_items (Gee.List<DockElement> elements)1039 public void animate_items (Gee.List<DockElement> elements)
980 {1040 {
981 if (!screen_is_composited)1041 if (!screen_is_composited)
@@ -995,6 +1055,15 @@
995 */1055 */
996 protected override bool animation_needed (int64 frame_time)1056 protected override bool animation_needed (int64 frame_time)
997 {1057 {
1058 if (zoom_changed) {
1059 //FIXME reset at a better place
1060 zoom_changed = false;
1061 return true;
1062 }
1063
1064 if (frame_time - last_hovered_changed <= 150 * 1000)
1065 return true;
1066
998 if (theme.FadeOpacity == 1.0) {1067 if (theme.FadeOpacity == 1.0) {
999 if (frame_time - last_hide <= theme.HideTime * 1000)1068 if (frame_time - last_hide <= theme.HideTime * 1000)
1000 return true;1069 return true;
@@ -1006,7 +1075,7 @@
1006 if (transient_items.size > 0)1075 if (transient_items.size > 0)
1007 return true;1076 return true;
1008 1077
1009 foreach (var item in controller.VisibleItems)1078 foreach (var item in current_items)
1010 if (item_animation_needed (item, frame_time))1079 if (item_animation_needed (item, frame_time))
1011 return true;1080 return true;
1012 1081
@@ -1039,5 +1108,22 @@
1039 1108
1040 return false;1109 return false;
1041 }1110 }
1111
1112 static int compare_dock_item_position (DockItem i1, DockItem i2)
1113 {
1114 var p_i1 = i1.Position;
1115 var p_i2 = i2.Position;
1116
1117 if (p_i1 > p_i2)
1118 return 1;
1119
1120 if (p_i1 < p_i2)
1121 return -1;
1122
1123 if (i1.RemoveTime > i2.RemoveTime)
1124 return -1;
1125
1126 return 1;
1127 }
1042 }1128 }
1043}1129}
10441130
=== modified file 'lib/DragManager.vala'
--- lib/DragManager.vala 2015-06-08 09:36:14 +0000
+++ lib/DragManager.vala 2015-07-16 08:37:41 +0000
@@ -178,7 +178,7 @@
178#if HAVE_HIDPI178#if HAVE_HIDPI
179 window_scale_factor = controller.window.get_window ().get_scale_factor ();179 window_scale_factor = controller.window.get_window ().get_scale_factor ();
180#endif180#endif
181 var drag_icon_size = (int) (1.2 * controller.position_manager.IconSize);181 var drag_icon_size = (int) (1.2 * controller.position_manager.ZoomIconSize);
182 if (drag_icon_size % 2 == 1)182 if (drag_icon_size % 2 == 1)
183 drag_icon_size++;183 drag_icon_size++;
184#if HAVE_HIDPI184#if HAVE_HIDPI
@@ -441,6 +441,7 @@
441 Gdk.drag_status (context, Gdk.DragAction.COPY, time_);441 Gdk.drag_status (context, Gdk.DragAction.COPY, time_);
442 }442 }
443 443
444 controller.renderer.update_local_cursor (x, y);
444 hide_manager.update_hovered ();445 hide_manager.update_hovered ();
445 window.update_hovered (x, y);446 window.update_hovered (x, y);
446 447
447448
=== modified file 'lib/Drawing/DockSurface.vala'
--- lib/Drawing/DockSurface.vala 2015-05-16 18:48:15 +0000
+++ lib/Drawing/DockSurface.vala 2015-07-16 08:37:41 +0000
@@ -125,6 +125,27 @@
125 }125 }
126 126
127 /**127 /**
128 * Create a scaled copy of the surface
129 *
130 * @param width the resulting width
131 * @param height the resulting height
132 * @return scaled copy of this surface
133 */
134 public DockSurface scaled_copy (int width, int height)
135 {
136 var result = new DockSurface.with_dock_surface (width, height, this);
137 unowned Cairo.Context cr = result.Context;
138
139 cr.save ();
140 cr.scale ((double) width / Width, (double) height / Height);
141 cr.set_source_surface (Internal, 0, 0);
142 cr.paint ();
143 cr.restore ();
144
145 return result;
146 }
147
148 /**
128 * Saves the current dock surface to a {@link Gdk.Pixbuf}.149 * Saves the current dock surface to a {@link Gdk.Pixbuf}.
129 *150 *
130 * @return the {@link Gdk.Pixbuf}151 * @return the {@link Gdk.Pixbuf}
131152
=== added file 'lib/Drawing/SurfaceCache.vala'
--- lib/Drawing/SurfaceCache.vala 1970-01-01 00:00:00 +0000
+++ lib/Drawing/SurfaceCache.vala 2015-07-16 08:37:41 +0000
@@ -0,0 +1,322 @@
1//
2// Copyright (C) 2015 Rico Tzschichholz
3//
4// This file is part of Plank.
5//
6// Plank is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// Plank is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <http://www.gnu.org/licenses/>.
18//
19
20using Plank.Services;
21
22namespace Plank.Drawing
23{
24 /**
25 * Creates a new surface based on the given information
26 *
27 * @param width the width
28 * @param height the height
29 * @param model existing surface to use as basis of new surface
30 * @param draw_data_func function which changes the surface
31 * @return the newly created surface or NULL
32 */
33 public delegate DockSurface? DrawFunc<G> (int width, int height, DockSurface model, DrawDataFunc<G>? draw_data_func);
34
35 /**
36 * Creates a new surface using the given element and information
37 *
38 * @param width the width
39 * @param height the height
40 * @param model existing surface to use as basis of new surface
41 * @param data the data object used for drawing
42 * @return the newly created surface or NULL
43 */
44 public delegate DockSurface? DrawDataFunc<G> (int width, int height, DockSurface model, G? data);
45
46 /**
47 * Controls some internal behaviors of a {@link Plank.Drawing.SurfaceCache}
48 */
49 [Flags]
50 public enum SurfaceCacheFlags
51 {
52 NONE = 0,
53 /**
54 * Allow down-scaling of an existing cached surface for better performance
55 */
56 ALLOW_DOWNSCALE = 1 << 0,
57 /**
58 * Allow up-scaling of an existing cached surface for better performance
59 */
60 ALLOW_UPSCALE = 1 << 1,
61 /**
62 * Allow scaling of an existing cached surface for better performance
63 * (This basically means the cache will only contain one entry which will be scaled accordingly on request)
64 */
65 ALLOW_SCALE = ALLOW_UPSCALE | ALLOW_DOWNSCALE,
66 /**
67 * Allow scaling if the drawing-time is significatly high
68 */
69 ADAPTIVE_SCALE = 1 << 2,
70 }
71
72 /**
73 * Cache multiple sizes of the assumed same image
74 */
75 public class SurfaceCache<G> : GLib.Object
76 {
77 const int64 MAX_CACHE_AGE = 5 * 60 * 1000 * 1000;
78 const int64 MIN_DRAWING_TIME = 10 * 1000;
79 const int64 ACCESS_REWARD = 500 * 1000;
80
81 class SurfaceInfo
82 {
83 public uint16 width;
84 public uint16 height;
85 public uint access_count;
86 public int64 last_access_time;
87 public int64 drawing_time;
88 public double scale;
89
90 public SurfaceInfo (uint16 width, uint16 height, int64 last_access_time, int64 drawing_time)
91 {
92 this.width = width;
93 this.height = height;
94 this.last_access_time = last_access_time;
95 this.drawing_time = drawing_time;
96 this.access_count = 0;
97 this.scale = 1.0;
98 }
99
100 public static uint hash (SurfaceInfo s)
101 {
102 uint n1 = s.width, n2 = s.height;
103 return (n1 >= n2 ? n1 * n1 + n1 + n2 : n1 + n2 * n2);
104 }
105
106 public static int compare (SurfaceInfo s1, SurfaceInfo s2)
107 {
108 if (s1 == s2)
109 return 0;
110
111 return (2 * (s1.width - s2.width) + s2.height - s2.height);
112 }
113
114 public int compare_with (uint16 width, uint16 height)
115 {
116 return (2 * (this.width - width) + this.height - height);
117 }
118 }
119
120 public SurfaceCacheFlags flags { get; construct; }
121
122 Gee.TreeSet<unowned SurfaceInfo> infos;
123 Gee.HashMap<SurfaceInfo, DockSurface> cache_map;
124 unowned SurfaceInfo? last_info;
125 Mutex cache_mutex;
126
127 uint clean_up_timer = 0U;
128
129 public SurfaceCache (SurfaceCacheFlags flags = SurfaceCacheFlags.NONE)
130 {
131 Object (flags: flags);
132 }
133
134 construct
135 {
136 infos = new Gee.TreeSet<unowned SurfaceInfo> ((CompareDataFunc) SurfaceInfo.compare);
137 cache_map = new Gee.HashMap<SurfaceInfo, DockSurface> ((Gee.HashDataFunc<SurfaceInfo>) SurfaceInfo.hash);
138 last_info = null;
139
140 //TODO Adaptive delay depending on the access rate
141 clean_up_timer = Gdk.threads_add_timeout (5 * 60 * 1000, () => {
142 clean_up ();
143 return true;
144 });
145 }
146
147 ~SurfaceCache ()
148 {
149 if (clean_up_timer > 0U) {
150 GLib.Source.remove (clean_up_timer);
151 clean_up_timer = 0U;
152 }
153
154 cache_map.clear ();
155 infos.clear ();
156 last_info = null;
157 }
158
159 public DockSurface? get_surface<G> (int width, int height, DockSurface model, DrawFunc<G> draw_func, DrawDataFunc<G>? draw_data_func)
160 requires (width >= 0 && height >= 0)
161 {
162 cache_mutex.lock ();
163
164 unowned SurfaceInfo? info;
165 SurfaceInfo? current_info = null;
166 DockSurface? surface = null;
167 bool needs_scaling = false;
168
169 info = find_match ((uint16) width, (uint16) height, out needs_scaling);
170 last_info = info;
171 current_info = info;
172
173 var access_time = GLib.get_monotonic_time ();
174
175 if (current_info != null) {
176 current_info.last_access_time = access_time;
177 current_info.access_count++;
178 surface = cache_map.get (current_info);
179
180 cache_mutex.unlock ();
181
182 if (needs_scaling)
183 return surface.scaled_copy (width, height);
184 else
185 return surface;
186 }
187
188 surface = draw_func (width, height, model, draw_data_func);
189
190 var finish_time = GLib.get_monotonic_time ();
191 var time_elapsed = finish_time - access_time;
192
193 current_info = new SurfaceInfo ((uint16) width, (uint16) height, finish_time, time_elapsed);
194 current_info.access_count++;
195
196 cache_map.set (current_info, surface);
197 infos.add (current_info);
198
199 cache_mutex.unlock ();
200
201 return surface;
202 }
203
204 unowned SurfaceInfo? find_match (uint16 width, uint16 height, out bool needs_scaling)
205 {
206 needs_scaling = false;
207
208 if (infos.is_empty)
209 return null;
210
211 unowned SurfaceInfo? info;
212 // Check if the last requested entry matches already
213 if (last_info != null) {
214 info = last_info;
215 if (info.width == width && info.height == height)
216 return info;
217
218 if ((flags & SurfaceCacheFlags.ALLOW_DOWNSCALE) != 0
219 && info.width > width && info.height > height) {
220 needs_scaling = true;
221 return info;
222 }
223
224 if ((flags & SurfaceCacheFlags.ALLOW_UPSCALE) != 0
225 && info.width < width && info.height < height) {
226 needs_scaling = true;
227 return info;
228 }
229 }
230
231 Gee.BidirIterator<unowned SurfaceInfo> infos_it;
232 if (last_info != null)
233 infos_it = (Gee.BidirIterator<unowned SurfaceInfo>) infos.iterator_at (last_info);
234 else
235 infos_it = infos.bidir_iterator ();
236
237 if (last_info != null && last_info.compare_with (width, height) > 0) {
238 while (infos_it.previous ()) {
239 info = infos_it.get ();
240
241 if (info.width == width && info.height == height)
242 return info;
243
244 if ((flags & SurfaceCacheFlags.ALLOW_DOWNSCALE) != 0
245 && info.width > width && info.height > height) {
246 needs_scaling = true;
247 return info;
248 }
249
250 if ((flags & SurfaceCacheFlags.ALLOW_UPSCALE) != 0
251 && info.width < width && info.height < height) {
252 needs_scaling = true;
253 return info;
254 }
255 }
256 } else {
257 while (infos_it.next ()) {
258 info = infos_it.get ();
259
260 if (info.width == width && info.height == height)
261 return info;
262
263 if ((flags & SurfaceCacheFlags.ALLOW_DOWNSCALE) != 0
264 && info.width > width && info.height > height) {
265 needs_scaling = true;
266 return info;
267 }
268
269 if ((flags & SurfaceCacheFlags.ALLOW_UPSCALE) != 0
270 && info.width < width && info.height < height) {
271 needs_scaling = true;
272 return info;
273 }
274 }
275 }
276
277 return null;
278 }
279
280 public void clear ()
281 {
282 cache_mutex.lock ();
283
284 infos.clear ();
285 cache_map.clear ();
286 last_info = null;
287
288 cache_mutex.unlock ();
289 }
290
291 void clean_up ()
292 {
293 cache_mutex.lock ();
294
295 if (cache_map.size <= 1)
296 return;
297
298 var now = GLib.get_monotonic_time ();
299 var size_before = cache_map.size;
300
301 var cache_it = cache_map.map_iterator ();
302 while (cache_it.next ()) {
303 var info = cache_it.get_key ();
304
305 if (now - info.last_access_time < ACCESS_REWARD * info.access_count)
306 continue;
307
308 if (info.drawing_time > MIN_DRAWING_TIME)
309 continue;
310
311 infos.remove (info);
312 cache_it.unset ();
313 }
314
315 last_info = null;
316
317 Logger.verbose ("SurfaceCache.clean_up (%i -> %i) ", size_before, cache_map.size);
318
319 cache_mutex.unlock ();
320 }
321 }
322}
0323
=== modified file 'lib/Items/DockItem.vala'
--- lib/Items/DockItem.vala 2015-06-10 20:26:28 +0000
+++ lib/Items/DockItem.vala 2015-07-16 08:37:41 +0000
@@ -24,16 +24,6 @@
24namespace Plank.Items24namespace Plank.Items
25{25{
26 /**26 /**
27 * Draws a modified surface onto another newly created or given surface
28 *
29 * @param item the dock-item
30 * @param source original surface which may not be changed
31 * @param target the previously modified surface
32 * @return the modified surface or passed through target
33 */
34 public delegate DockSurface DrawItemFunc (DockItem item, DockSurface source, DockSurface? target);
35
36 /**
37 * The base class for all dock items.27 * The base class for all dock items.
38 */28 */
39 public abstract class DockItem : DockElement29 public abstract class DockItem : DockElement
@@ -134,8 +124,8 @@
134 */124 */
135 public DockItemPreferences Prefs { get; construct; }125 public DockItemPreferences Prefs { get; construct; }
136 126
137 DockSurface? surface = null;127 SurfaceCache<DockItem> buffer;
138 DockSurface? background_surface = null;128 SurfaceCache<DockItem> background_buffer;
139 DockSurface? foreground_surface = null;129 DockSurface? foreground_surface = null;
140 130
141 FileMonitor? launcher_file_monitor = null;131 FileMonitor? launcher_file_monitor = null;
@@ -154,6 +144,9 @@
154 144
155 construct145 construct
156 {146 {
147 buffer = new SurfaceCache<DockItem> (SurfaceCacheFlags.NONE);
148 background_buffer = new SurfaceCache<DockItem> (SurfaceCacheFlags.ALLOW_SCALE);
149
157 Prefs.deleted.connect (handle_deleted);150 Prefs.deleted.connect (handle_deleted);
158 Prefs.notify["Launcher"].connect (handle_launcher_changed);151 Prefs.notify["Launcher"].connect (handle_launcher_changed);
159 152
@@ -173,6 +166,9 @@
173 166
174 ~DockItem ()167 ~DockItem ()
175 {168 {
169 buffer.clear ();
170 background_buffer.clear ();
171
176 Prefs.deleted.disconnect (handle_deleted);172 Prefs.deleted.disconnect (handle_deleted);
177 Prefs.notify["Launcher"].disconnect (handle_launcher_changed);173 Prefs.notify["Launcher"].disconnect (handle_launcher_changed);
178 174
@@ -232,8 +228,8 @@
232 */228 */
233 protected void reset_icon_buffer ()229 protected void reset_icon_buffer ()
234 {230 {
235 surface = null;231 buffer.clear ();
236 background_surface = null;232 background_buffer.clear ();
237 foreground_surface = null;233 foreground_surface = null;
238 234
239 needs_redraw ();235 needs_redraw ();
@@ -244,7 +240,7 @@
244 */240 */
245 public override void reset_buffers ()241 public override void reset_buffers ()
246 {242 {
247 background_surface = null;243 background_buffer.clear ();
248 foreground_surface = null;244 foreground_surface = null;
249 }245 }
250 246
@@ -420,16 +416,31 @@
420 return true;416 return true;
421 }417 }
422 418
423 unowned DockSurface get_surface (int width, int height, DockSurface model)419 /**
424 {420 * Returns the dock surface for this item.
425 if (surface == null || width != surface.Width || height != surface.Height) {421 *
426 surface = new DockSurface.with_dock_surface (width, height, model);422 * It might trigger an internal redraw if the requested size
427 423 * isn't cached yet.
428 Logger.verbose ("DockItem.draw_icon (width = %i, height = %i)", width, height);424 *
429 draw_icon (surface);425 * @param width width of the icon surface
430 426 * @param height height of the icon surface
431 AverageIconColor = surface.average_color ();427 * @param model existing surface to use as basis of new surface
432 }428 * @return the dock surface for this item which may not be changed
429 */
430 public DockSurface get_surface (int width, int height, DockSurface model)
431 {
432 return buffer.get_surface<DockItem> (width, height, model, (DrawFunc<DockItem>) internal_get_surface, null);
433 }
434
435 [CCode (instance_pos = -1)]
436 DockSurface internal_get_surface (int width, int height, DockSurface model, DrawDataFunc<DockItem>? draw_data_func)
437 {
438 var surface = new DockSurface.with_dock_surface (width, height, model);
439
440 Logger.verbose ("DockItem.draw_icon (width = %i, height = %i)", width, height);
441 draw_icon (surface);
442
443 AverageIconColor = surface.average_color ();
433 444
434 return surface;445 return surface;
435 }446 }
@@ -442,18 +453,21 @@
442 *453 *
443 * Passing null as draw_func will destroy the internal background buffer.454 * Passing null as draw_func will destroy the internal background buffer.
444 *455 *
445 * @param draw_func function which creates/changes the background surface456 * @param draw_data_func function which creates/changes the background surface
446 * @return the background surface of this item which may not be changed457 * @return the background surface of this item which may not be changed
447 */458 */
448 public unowned DockSurface? get_background_surface (DrawItemFunc? draw_func = null)459 public DockSurface? get_background_surface (int width, int height, DockSurface model, DrawDataFunc<DockItem>? draw_data_func)
449 requires (surface != null)460 {
450 {461 return background_buffer.get_surface<DockItem> (width, height, model, (DrawFunc<DockItem>) internal_get_background_surface, (DrawDataFunc<DockItem>) draw_data_func);
451 if (draw_func != null)462 }
452 background_surface = draw_func (this, surface, background_surface);463
453 else464 [CCode (instance_pos = -1)]
454 background_surface = null;465 DockSurface? internal_get_background_surface (int width, int height, DockSurface model, DrawDataFunc<DockItem>? draw_data_func)
466 {
467 if (draw_data_func == null)
468 return null;
455 469
456 return background_surface;470 return draw_data_func (width, height, model, this);
457 }471 }
458 472
459 /**473 /**
@@ -464,16 +478,21 @@
464 *478 *
465 * Passing null as draw_func will destroy the internal foreground buffer.479 * Passing null as draw_func will destroy the internal foreground buffer.
466 *480 *
467 * @param draw_func function which creates/changes the foreground surface481 * @param draw_data_func function which creates/changes the foreground surface
468 * @return the background surface of this item which may not be changed482 * @return the background surface of this item which may not be changed
469 */483 */
470 public unowned DockSurface? get_foreground_surface (DrawItemFunc? draw_func = null)484 public DockSurface? get_foreground_surface (int width, int height, DockSurface model, DrawDataFunc<DockItem>? draw_data_func)
471 requires (surface != null)
472 {485 {
473 if (draw_func != null)486 if (draw_data_func == null) {
474 foreground_surface = draw_func (this, surface, foreground_surface);
475 else
476 foreground_surface = null;487 foreground_surface = null;
488 return null;
489 }
490
491 if (foreground_surface != null
492 && foreground_surface.Width == width && foreground_surface.Height == height)
493 return foreground_surface;
494
495 foreground_surface = draw_data_func (width, height, model, this);
477 496
478 return foreground_surface;497 return foreground_surface;
479 }498 }
480499
=== modified file 'lib/Makefile.am'
--- lib/Makefile.am 2015-06-08 21:48:12 +0000
+++ lib/Makefile.am 2015-07-16 08:37:41 +0000
@@ -79,6 +79,7 @@
79 Drawing/DockSurface.vala \79 Drawing/DockSurface.vala \
80 Drawing/DockTheme.vala \80 Drawing/DockTheme.vala \
81 Drawing/Easing.vala \81 Drawing/Easing.vala \
82 Drawing/SurfaceCache.vala \
82 Drawing/Theme.vala \83 Drawing/Theme.vala \
83 Factories/AbstractMain.vala \84 Factories/AbstractMain.vala \
84 Factories/Factory.vala \85 Factories/Factory.vala \
8586
=== modified file 'lib/PositionManager.vala'
--- lib/PositionManager.vala 2015-06-11 05:36:16 +0000
+++ lib/PositionManager.vala 2015-07-16 08:37:41 +0000
@@ -29,12 +29,41 @@
29 */29 */
30 public class PositionManager : GLib.Object30 public class PositionManager : GLib.Object
31 {31 {
32 public struct DockItemDrawValue32 public struct PointD
33 {33 {
34 public double x;
35 public double y;
36 }
37
38 /**
39 * Modify the given DrawItemValue
40 *
41 * @param item the dock-item
42 * @param draw_value the dock-item-drawvalue
43 */
44 public delegate void DockItemDrawValueFunc (DockItem item, DockItemDrawValue draw_value);
45
46 /**
47 * Modify the all DrawItemValue of all dock-items
48 *
49 * @param draw_values the map of all current dock-items and their draw-values
50 */
51 public delegate void DrawValuesFunc (Gee.HashMap<DockElement, DockItemDrawValue> draw_values);
52
53 /**
54 * Contains all positions and modifications to draw a dock-item on the dock
55 */
56 public class DockItemDrawValue
57 {
58 public PointD center;
59 public PointD static_center;
60 public double icon_size;
61
34 public Gdk.Rectangle hover_region;62 public Gdk.Rectangle hover_region;
35 public Gdk.Rectangle draw_region;63 public Gdk.Rectangle draw_region;
36 public Gdk.Rectangle background_region;64 public Gdk.Rectangle background_region;
37 65
66 public double zoom;
38 public double opacity;67 public double opacity;
39 68
40 public double darken;69 public double darken;
@@ -49,18 +78,26 @@
49 switch (position) {78 switch (position) {
50 default:79 default:
51 case Gtk.PositionType.BOTTOM:80 case Gtk.PositionType.BOTTOM:
81 center.y -= damount;
82 static_center.y -= damount;
52 hover_region.y -= amount;83 hover_region.y -= amount;
53 draw_region.y -= amount;84 draw_region.y -= amount;
54 break;85 break;
55 case Gtk.PositionType.TOP:86 case Gtk.PositionType.TOP:
87 center.y += damount;
88 static_center.y += damount;
56 hover_region.y += amount;89 hover_region.y += amount;
57 draw_region.y += amount;90 draw_region.y += amount;
58 break;91 break;
59 case Gtk.PositionType.LEFT:92 case Gtk.PositionType.LEFT:
93 center.x += damount;
94 static_center.x += damount;
60 hover_region.x += amount;95 hover_region.x += amount;
61 draw_region.x += amount;96 draw_region.x += amount;
62 break;97 break;
63 case Gtk.PositionType.RIGHT:98 case Gtk.PositionType.RIGHT:
99 center.x -= damount;
100 static_center.x -= damount;
64 hover_region.x -= amount;101 hover_region.x -= amount;
65 draw_region.x -= amount;102 draw_region.x -= amount;
66 break;103 break;
@@ -74,21 +111,29 @@
74 switch (position) {111 switch (position) {
75 default:112 default:
76 case Gtk.PositionType.BOTTOM:113 case Gtk.PositionType.BOTTOM:
114 center.x += damount;
115 static_center.x += damount;
77 hover_region.x += amount;116 hover_region.x += amount;
78 draw_region.x += amount;117 draw_region.x += amount;
79 background_region.x += amount;118 background_region.x += amount;
80 break;119 break;
81 case Gtk.PositionType.TOP:120 case Gtk.PositionType.TOP:
121 center.x += damount;
122 static_center.x += damount;
82 hover_region.x += amount;123 hover_region.x += amount;
83 draw_region.x += amount;124 draw_region.x += amount;
84 background_region.x += amount;125 background_region.x += amount;
85 break;126 break;
86 case Gtk.PositionType.LEFT:127 case Gtk.PositionType.LEFT:
128 center.y += damount;
129 static_center.y += damount;
87 hover_region.y += amount;130 hover_region.y += amount;
88 draw_region.y += amount;131 draw_region.y += amount;
89 background_region.y += amount;132 background_region.y += amount;
90 break;133 break;
91 case Gtk.PositionType.RIGHT:134 case Gtk.PositionType.RIGHT:
135 center.y += damount;
136 static_center.y += damount;
92 hover_region.y += amount;137 hover_region.y += amount;
93 draw_region.y += amount;138 draw_region.y += amount;
94 background_region.y += amount;139 background_region.y += amount;
@@ -102,7 +147,7 @@
102 public bool screen_is_composited { get; private set; }147 public bool screen_is_composited { get; private set; }
103 148
104 Gdk.Rectangle static_dock_region;149 Gdk.Rectangle static_dock_region;
105 Gee.HashMap<DockElement, DockItemDrawValue?> draw_values;150 Gee.HashMap<DockElement, DockItemDrawValue> draw_values;
106 151
107 Gdk.Rectangle monitor_geo;152 Gdk.Rectangle monitor_geo;
108 153
@@ -121,9 +166,9 @@
121 construct166 construct
122 {167 {
123 static_dock_region = {};168 static_dock_region = {};
124 draw_values = new Gee.HashMap<DockElement, DockItemDrawValue?> (); 169 draw_values = new Gee.HashMap<DockElement, DockItemDrawValue> ();
125 170
126 controller.prefs.notify["Monitor"].connect (prefs_monitor_changed);171 controller.prefs.notify.connect (prefs_changed);
127 }172 }
128 173
129 /**174 /**
@@ -151,11 +196,27 @@
151 screen.monitors_changed.disconnect (screen_changed);196 screen.monitors_changed.disconnect (screen_changed);
152 screen.size_changed.disconnect (screen_changed);197 screen.size_changed.disconnect (screen_changed);
153 screen.composited_changed.disconnect (screen_composited_changed);198 screen.composited_changed.disconnect (screen_composited_changed);
154 controller.prefs.notify["Monitor"].disconnect (prefs_monitor_changed);199 controller.prefs.notify.disconnect (prefs_changed);
155 200
156 draw_values.clear ();201 draw_values.clear ();
157 }202 }
158 203
204 void prefs_changed (Object prefs, ParamSpec prop)
205 {
206 switch (prop.name) {
207 case "Monitor":
208 prefs_monitor_changed ();
209 break;
210 case "ZoomPercent":
211 case "ZoomEnabled":
212 prefs_zoom_changed ();
213 break;
214 default:
215 // Nothing important for us changed
216 break;
217 }
218 }
219
159 public static string[] get_monitor_plug_names (Gdk.Screen screen)220 public static string[] get_monitor_plug_names (Gdk.Screen screen)
160 {221 {
161 int n_monitors = screen.get_n_monitors ();222 int n_monitors = screen.get_n_monitors ();
@@ -231,7 +292,12 @@
231 * Cached current icon size for the dock.292 * Cached current icon size for the dock.
232 */293 */
233 public int IconSize { get; private set; }294 public int IconSize { get; private set; }
234 295
296 /**
297 * Cached current icon size for the dock.
298 */
299 public int ZoomIconSize { get; private set; }
300
235 /**301 /**
236 * Cached position of the dock.302 * Cached position of the dock.
237 */303 */
@@ -330,6 +396,10 @@
330 */396 */
331 int DockBackgroundWidth;397 int DockBackgroundWidth;
332 398
399 double ZoomPercent;
400
401 Gdk.Rectangle background_rect;
402
333 /**403 /**
334 * The maximum item count which fit the dock in its maximum404 * The maximum item count which fit the dock in its maximum
335 * size with the current theme and icon-size.405 * size with the current theme and icon-size.
@@ -363,24 +433,6 @@
363 thaw_notify ();433 thaw_notify ();
364 }434 }
365 435
366 /**
367 * Resets all internal caches for the given item.
368 *
369 * @param item the dock item
370 */
371 public void reset_item_cache (DockElement item)
372 {
373 draw_values.unset (item);
374 }
375
376 /**
377 * Resets all internal item caches.
378 */
379 public void reset_item_caches ()
380 {
381 draw_values.clear ();
382 }
383
384 void update_caches (DockTheme theme)436 void update_caches (DockTheme theme)
385 {437 {
386 unowned DockPreferences prefs = controller.prefs;438 unowned DockPreferences prefs = controller.prefs;
@@ -413,6 +465,8 @@
413 }465 }
414 466
415 IconSize = int.min (MaxIconSize, prefs.IconSize);467 IconSize = int.min (MaxIconSize, prefs.IconSize);
468 ZoomPercent = (screen_is_composited ? prefs.ZoomPercent / 100.0 : 1.0);
469 ZoomIconSize = (screen_is_composited && prefs.ZoomEnabled ? (int) Math.round (IconSize * ZoomPercent) : IconSize);
416 470
417 var scaled_icon_size = IconSize / 10.0;471 var scaled_icon_size = IconSize / 10.0;
418 472
@@ -445,8 +499,14 @@
445 extra_hide_offset = (IconShadowSize - top_offset);499 extra_hide_offset = (IconShadowSize - top_offset);
446 else500 else
447 extra_hide_offset = 0;501 extra_hide_offset = 0;
502 }
503
504 void prefs_zoom_changed ()
505 {
506 unowned DockPreferences prefs = controller.prefs;
448 507
449 draw_values.clear ();508 ZoomPercent = (screen_is_composited ? prefs.ZoomPercent / 100.0 : 1.0);
509 ZoomIconSize = (screen_is_composited && prefs.ZoomEnabled ? (int) Math.round (IconSize * ZoomPercent) : IconSize);
450 }510 }
451 511
452 /**512 /**
@@ -563,6 +623,15 @@
563 window_scale_factor = controller.window.get_window ().get_scale_factor ();623 window_scale_factor = controller.window.get_window ().get_scale_factor ();
564#endif624#endif
565 625
626 // If zoom is enabled extend cursor-region based on current hovered-item
627 if (controller.prefs.ZoomEnabled) {
628 unowned DockItem? hovered_item = controller.window.HoveredItem;
629 if (hovered_item != null) {
630 var hover_region = get_hover_region_for_element (hovered_item);
631 cursor_region.union (hover_region, out cursor_region);
632 }
633 }
634
566 switch (Position) {635 switch (Position) {
567 default:636 default:
568 case Gtk.PositionType.BOTTOM:637 case Gtk.PositionType.BOTTOM:
@@ -691,9 +760,6 @@
691 760
692 update_dock_position ();761 update_dock_position ();
693 762
694 // FIXME Maybe no need to purge all cached values?
695 draw_values.clear ();
696
697 if (!screen_is_composited763 if (!screen_is_composited
698 || old_region.x != static_dock_region.x764 || old_region.x != static_dock_region.x
699 || old_region.y != static_dock_region.y765 || old_region.y != static_dock_region.y
@@ -721,91 +787,337 @@
721 */787 */
722 public DockItemDrawValue get_draw_value_for_item (DockItem item)788 public DockItemDrawValue get_draw_value_for_item (DockItem item)
723 {789 {
724 DockItemDrawValue? draw_value;790 if (draw_values.size == 0) {
725 791 critical ("Without draw_values there is trouble ahead");
726 if ((draw_value = draw_values.get (item)) == null) {792 update_draw_values (controller.VisibleItems);
727 var hover_rect = internal_get_item_hover_region (item);793 }
728 var draw_rect = get_item_draw_region (hover_rect);794
729 var background_rect = get_item_background_region (hover_rect);795 var draw_value = draw_values[item];
730 796 if (draw_value == null) {
731 draw_value = { hover_rect, draw_rect, background_rect, 1.0, 0.0, 0.0, true };797 critical ("Without a draw_value there is trouble ahead for '%s'", item.Text);
732 draw_values.set (item, draw_value);798 draw_value = new DockItemDrawValue ();
733 }799 }
734 800
735 return draw_value;801 return draw_value;
736 }802 }
737 803
738 /**804 /**
805 * Update and recalculated all internal draw-values using the given methodes for custom manipulations.
806 *
807 * @param items the ordered list of all current item which are suppose to be shown on the dock
808 * @param func a function which adjusts the draw-value per item
809 * @param post_func a function which post-processes all draw-values
810 */
811 public void update_draw_values (Gee.ArrayList<unowned DockItem> items, DockItemDrawValueFunc? func = null,
812 DrawValuesFunc? post_func = null)
813 {
814 unowned DockPreferences prefs = controller.prefs;
815
816 draw_values.clear ();
817
818 bool external_drag_active = controller.drag_manager.ExternalDragActive;
819
820 // first we do the math as if this is a top dock, to do this we need to set
821 // up some "pretend" variables. we pretend we are a top dock because 0,0 is
822 // at the top.
823 int width = DockWidth;
824 int height = DockHeight;
825 int icon_size = IconSize;
826
827 double zoom_in_progress = controller.renderer.zoom_in_progress;
828 Gdk.Point cursor = controller.renderer.local_cursor;
829
830 // "relocate" our cursor to be on the top
831 switch (Position) {
832 case Gtk.PositionType.RIGHT:
833 cursor.x = width - cursor.x;
834 break;
835 case Gtk.PositionType.BOTTOM:
836 cursor.y = height - cursor.y;
837 break;
838 default:
839 break;
840 }
841
842 // our width and height switch around if we have a vertical dock
843 if (!is_horizontal_dock ()) {
844 int tmp = cursor.y;
845 cursor.y = cursor.x;
846 cursor.x = tmp;
847
848 tmp = width;
849 width = height;
850 height = tmp;
851 }
852
853 //FIXME
854 // the line along the dock width about which the center of unzoomed icons sit
855 double center_y = (is_horizontal_dock () ? static_dock_region.height / 2.0 : static_dock_region.width / 2.0);
856
857 double center_x = (icon_size + ItemPadding) / 2.0 + items_offset;
858 if (Alignment == Gtk.Align.FILL) {
859 switch (ItemsAlignment) {
860 default:
861 case Gtk.Align.FILL:
862 case Gtk.Align.CENTER:
863 if (is_horizontal_dock ())
864 center_x += static_dock_region.x + (static_dock_region.width - 2 * items_offset - items_width) / 2;
865 else
866 center_x += static_dock_region.y + (static_dock_region.height - 2 * items_offset - items_width) / 2;
867 break;
868 case Gtk.Align.START:
869 break;
870 case Gtk.Align.END:
871 if (is_horizontal_dock ())
872 center_x += static_dock_region.x + (static_dock_region.width - 2 * items_offset - items_width);
873 else
874 center_x += static_dock_region.y + (static_dock_region.height - 2 * items_offset - items_width);
875 break;
876 }
877 } else {
878 if (is_horizontal_dock ())
879 center_x += static_dock_region.x;
880 else
881 center_x += static_dock_region.y;
882 }
883
884 PointD center = { Math.floor (center_x), Math.floor (center_y) };
885
886 // ZoomPercent is a number greater than 1. It should never be less than one.
887
888 // zoom_in_percent is a range of 1 to ZoomPercent.
889 // We need a number that is 1 when ZoomIn is 0, and ZoomPercent when ZoomIn is 1.
890 // Then we treat this as if it were the ZoomPercent for the rest of the calculation.
891 double zoom_in_percent = (prefs.ZoomEnabled ? 1.0 + (ZoomPercent - 1.0) * zoom_in_progress : 1.0);
892 double zoom_icon_size = (prefs.ZoomEnabled ? ZoomIconSize : 2.0 * icon_size);
893
894 foreach (unowned DockItem item in items) {
895 DockItemDrawValue val = new DockItemDrawValue ();
896 val.opacity = 1.0;
897 val.darken = 0.0;
898 val.lighten = 0.0;
899 val.show_indicator = true;
900 val.zoom = 1.0;
901
902 val.static_center = center;
903
904 // get us some handy doubles with fancy names
905 double cursor_position = cursor.x;
906 double center_position = center.x;
907
908 // offset from the center of the true position, ranged between 0 and the zoom size
909 double offset = double.min (Math.fabs (cursor_position - center_position), zoom_icon_size);
910
911 double offset_percent;
912 if (external_drag_active) {
913 // Provide space for dropping between items
914 offset += offset * zoom_icon_size / icon_size;
915 offset_percent = double.min (1.0, offset / (zoom_icon_size + ZoomIconSize));
916 } else {
917 offset_percent = offset / zoom_icon_size;
918 }
919
920 if (offset_percent > 0.99)
921 offset_percent = 1.0;
922
923 // pull in our offset to make things less spaced out
924 // explaination since this is a bit tricky...
925 // we have three terms, basically offset = f(x) * h(x) * g(x)
926 // f(x) == offset identity
927 // h(x) == a number from 0 to DockPreference.ZoomPercent - 1. This is used to get the smooth "zoom in" effect.
928 // additionally serves to "curve" the offset based on the max zoom
929 // g(x) == a term used to move the ends of the zoom inward. Precalculated that the edges should be 66% of the current
930 // value. The center is 100%. (1 - offset_percent) == 0,1 distance from center
931 // 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.
932
933 // for external drags with no zoom, we pretend there is actually a zoom of 200%
934 if (external_drag_active && ZoomPercent == 1.0)
935 offset *= zoom_in_progress / 2.0;
936 else
937 offset *= zoom_in_percent - 1.0;
938 offset *= 1.0 - offset_percent / 3.0;
939
940 if (cursor_position > center_position)
941 center_position -= offset;
942 else
943 center_position += offset;
944
945 // zoom is calculated as 1 through target_zoom (default 2).
946 // The larger your offset, the smaller your zoom
947
948 // First we get the point on our curve that defines our current zoom
949 // offset is always going to fall on a point on the curve >= 0
950 var zoom = 1.0 - Math.pow (offset_percent, 2);
951
952 // scale this to match our zoom_in_percent
953 zoom = 1.0 + zoom * (zoom_in_percent - 1.0);
954
955 double zoomed_center_height = (icon_size * zoom / 2.0);
956
957 if (zoom == 1.0)
958 center_position = Math.round (center_position);
959
960 val.center = { center_position, zoomed_center_height };
961 val.zoom = zoom;
962 val.icon_size = Math.round (zoom * icon_size);
963
964 // now we undo our transforms to the point
965 if (!is_horizontal_dock ()) {
966 double tmp = val.center.y;
967 val.center.y = val.center.x;
968 val.center.x = tmp;
969
970 tmp = val.static_center.y;
971 val.static_center.y = val.static_center.x;
972 val.static_center.x = tmp;
973 }
974
975 switch (Position) {
976 case Gtk.PositionType.RIGHT:
977 val.center.x = height - val.center.x;
978 val.static_center.x = height - val.static_center.x;
979 break;
980 case Gtk.PositionType.BOTTOM:
981 val.center.y = height - val.center.y;
982 val.static_center.y = height - val.static_center.y;
983 break;
984 default:
985 break;
986 }
987
988 //FIXME
989 val.move_in (Position, bottom_offset);
990
991 // let the draw-value be modified by the given function
992 if (func != null)
993 func (item, val);
994
995 draw_values[item] = val;
996
997 //FIXME
998 // Don't reserve space for removed items
999 if (item.RemoveTime == 0)
1000 center.x += icon_size + ItemPadding;
1001 }
1002
1003 if (post_func != null)
1004 post_func (draw_values);
1005
1006 update_background_region (draw_values[items.first ()], draw_values[items.last ()]);
1007
1008 // precalculate and cache regions (for the current frame)
1009#if HAVE_GEE_0_8
1010 draw_values.map_iterator ().foreach ((i, val) => {
1011 val.draw_region = get_item_draw_region (val);
1012 val.hover_region = get_item_hover_region (val);
1013 val.background_region = get_item_background_region (val);
1014 return true;
1015 });
1016#else
1017 var draw_values_it = draw_values.map_iterator ();
1018 while (draw_values_it.next ()) {
1019 var val = draw_values_it.get_value ();
1020 val.draw_region = get_item_draw_region (val);
1021 val.hover_region = get_item_hover_region (val);
1022 val.background_region = get_item_background_region (val);
1023 }
1024#endif
1025 }
1026 /**
739 * The region for drawing a dock item.1027 * The region for drawing a dock item.
740 *1028 *
741 * @param hover_rect the item's hover region1029 * @param val the item's DockItemDrawValue
742 * @return the region for the dock item1030 * @return the region for the dock item
743 */1031 */
744 Gdk.Rectangle get_item_draw_region (Gdk.Rectangle hover_rect)1032 Gdk.Rectangle get_item_draw_region (DockItemDrawValue val)
745 {1033 {
1034 var width = val.icon_size, height = val.icon_size;
1035
1036 return { (int) Math.round (val.center.x - width / 2.0),
1037 (int) Math.round (val.center.y - height / 2.0),
1038 (int) width,
1039 (int) height };
1040 }
1041
1042 /**
1043 * The intersecting region of a dock item's hover region and the background.
1044 *
1045 * @param val the item's DockItemDrawValue
1046 * @return the region for the dock item
1047 */
1048 Gdk.Rectangle get_item_background_region (DockItemDrawValue val)
1049 {
1050 Gdk.Rectangle rect;
1051
1052 if (!val.hover_region.intersect (get_background_region (), out rect))
1053 return {};
1054
1055 return rect;
1056 }
1057
1058 /**
1059 * The cursor region for interacting with a dock element.
1060 *
1061 * @param val the item's DockItemDrawValue
1062 * @return the region for the dock item
1063 */
1064 Gdk.Rectangle get_item_hover_region (DockItemDrawValue val)
1065 {
1066 Gdk.Rectangle rect;
1067
746 var item_padding = ItemPadding;1068 var item_padding = ItemPadding;
747 var top_padding = (top_offset < 0 ? 0 : top_offset);1069 var top_padding = (top_offset < 0 ? 0 : top_offset);
748 var bottom_padding = bottom_offset;1070 var bottom_padding = bottom_offset;
1071 var width = val.icon_size, height = val.icon_size;
749 1072
1073 // Apply scalable padding
750 switch (Position) {1074 switch (Position) {
751 default:1075 default:
752 case Gtk.PositionType.BOTTOM:1076 case Gtk.PositionType.BOTTOM:
753 hover_rect.x += item_padding / 2;1077 width += item_padding;
754 hover_rect.y += top_padding;
755 hover_rect.width -= item_padding;
756 hover_rect.height -= bottom_padding + top_padding;
757 break;1078 break;
758 case Gtk.PositionType.TOP:1079 case Gtk.PositionType.TOP:
759 hover_rect.x += item_padding / 2;1080 width += item_padding;
760 hover_rect.y += bottom_padding;
761 hover_rect.width -= item_padding;
762 hover_rect.height -= bottom_padding + top_padding;
763 break;1081 break;
764 case Gtk.PositionType.LEFT:1082 case Gtk.PositionType.LEFT:
765 hover_rect.x += bottom_padding;1083 height += item_padding;
766 hover_rect.y += item_padding / 2;
767 hover_rect.width -= bottom_padding + top_padding;
768 hover_rect.height -= item_padding;
769 break;1084 break;
770 case Gtk.PositionType.RIGHT:1085 case Gtk.PositionType.RIGHT:
771 hover_rect.x += top_padding;1086 height += item_padding;
772 hover_rect.y += item_padding / 2;
773 hover_rect.width -= bottom_padding + top_padding;
774 hover_rect.height -= item_padding;
775 break;1087 break;
776 }1088 }
777 1089
778 return hover_rect;1090 rect = { (int) Math.round (val.center.x - width / 2.0),
779 }1091 (int) Math.round (val.center.y - height / 2.0),
780 1092 (int) width,
781 /**1093 (int) height };
782 * The intersecting region of a dock item's hover region and the background.
783 *
784 * @param rect the item's hover region
785 * @return the region for the dock item
786 */
787 Gdk.Rectangle get_item_background_region (Gdk.Rectangle rect)
788 {
789 var top_padding = (top_offset > 0 ? 0 : top_offset);
790 1094
1095 // Apply static padding
791 switch (Position) {1096 switch (Position) {
792 default:1097 default:
793 case Gtk.PositionType.BOTTOM:1098 case Gtk.PositionType.BOTTOM:
794 rect.y -= top_padding;1099 rect.y -= top_padding;
795 rect.height += top_padding;1100 rect.height += bottom_padding + top_padding;
796 break;1101 break;
797 case Gtk.PositionType.TOP:1102 case Gtk.PositionType.TOP:
798 rect.height += top_padding;1103 rect.y -= bottom_padding;
1104 rect.height += bottom_padding + top_padding;
799 break;1105 break;
800 case Gtk.PositionType.LEFT:1106 case Gtk.PositionType.LEFT:
801 rect.width += top_padding;1107 rect.x -= bottom_padding;
1108 rect.width += bottom_padding + top_padding;
802 break;1109 break;
803 case Gtk.PositionType.RIGHT:1110 case Gtk.PositionType.RIGHT:
804 rect.x -= top_padding;1111 rect.x -= top_padding;
805 rect.width += top_padding;1112 rect.width += bottom_padding + top_padding;
806 break;1113 break;
807 }1114 }
808 1115
1116 Gdk.Rectangle background_region;
1117
1118 if (rect.intersect (get_background_region (), out background_region))
1119 background_region.union (get_item_draw_region (val), out rect);
1120
809 return rect;1121 return rect;
810 }1122 }
811 1123
@@ -815,7 +1127,7 @@
815 * @param element the dock element to find a region for1127 * @param element the dock element to find a region for
816 * @return the region for the dock item1128 * @return the region for the dock item
817 */1129 */
818 public Gdk.Rectangle get_item_hover_region (DockElement element)1130 public Gdk.Rectangle get_hover_region_for_element (DockElement element)
819 {1131 {
820 unowned DockItem? item = (element as DockItem);1132 unowned DockItem? item = (element as DockItem);
821 if (item != null)1133 if (item != null)
@@ -830,73 +1142,16 @@
830 if (items.size == 0)1142 if (items.size == 0)
831 return {};1143 return {};
832 1144
833 var first_rect = get_item_hover_region (items.first ());1145 var first_rect = get_hover_region_for_element (items.first ());
834 if (items.size == 1)1146 if (items.size == 1)
835 return first_rect;1147 return first_rect;
836 1148
837 var last_rect = get_item_hover_region (items.last ());1149 var last_rect = get_hover_region_for_element (items.last ());
838 1150
839 Gdk.Rectangle result;1151 Gdk.Rectangle result;
840 first_rect.union (last_rect, out result);1152 first_rect.union (last_rect, out result);
841 return result;1153 return result;
842 }1154 }
843
844 Gdk.Rectangle internal_get_item_hover_region (DockItem item)
845 {
846 Gdk.Rectangle rect = {};
847
848 switch (Position) {
849 default:
850 case Gtk.PositionType.BOTTOM:
851 rect.width = IconSize + ItemPadding;
852 rect.height = VisibleDockHeight;
853 rect.x = static_dock_region.x + items_offset + item.Position * (ItemPadding + IconSize);
854 rect.y = DockHeight - rect.height;
855 break;
856 case Gtk.PositionType.TOP:
857 rect.width = IconSize + ItemPadding;
858 rect.height = VisibleDockHeight;
859 rect.x = static_dock_region.x + items_offset + item.Position * (ItemPadding + IconSize);
860 rect.y = 0;
861 break;
862 case Gtk.PositionType.LEFT:
863 rect.height = IconSize + ItemPadding;
864 rect.width = VisibleDockWidth;
865 rect.y = static_dock_region.y + items_offset + item.Position * (ItemPadding + IconSize);
866 rect.x = 0;
867 break;
868 case Gtk.PositionType.RIGHT:
869 rect.height = IconSize + ItemPadding;
870 rect.width = VisibleDockWidth;
871 rect.y = static_dock_region.y + items_offset + item.Position * (ItemPadding + IconSize);
872 rect.x = DockWidth - rect.width;
873 break;
874 }
875
876 if (Alignment != Gtk.Align.FILL)
877 return rect;
878
879 switch (ItemsAlignment) {
880 default:
881 case Gtk.Align.FILL:
882 case Gtk.Align.CENTER:
883 if (is_horizontal_dock ())
884 rect.x += (static_dock_region.width - 2 * items_offset - items_width) / 2;
885 else
886 rect.y += (static_dock_region.height - 2 * items_offset - items_width) / 2;
887 break;
888 case Gtk.Align.START:
889 break;
890 case Gtk.Align.END:
891 if (is_horizontal_dock ())
892 rect.x += (static_dock_region.width - 2 * items_offset - items_width);
893 else
894 rect.y += (static_dock_region.height - 2 * items_offset - items_width);
895 break;
896 }
897
898 return rect;
899 }
900 1155
901 /**1156 /**
902 * Get's the x and y position to display a menu for a dock item.1157 * Get's the x and y position to display a menu for a dock item.
@@ -908,7 +1163,7 @@
908 */1163 */
909 public void get_menu_position (DockItem hovered, Gtk.Requisition requisition, out int x, out int y)1164 public void get_menu_position (DockItem hovered, Gtk.Requisition requisition, out int x, out int y)
910 {1165 {
911 var rect = get_item_hover_region (hovered);1166 var rect = get_hover_region_for_element (hovered);
912 1167
913 var offset = 10;1168 var offset = 10;
914 switch (Position) {1169 switch (Position) {
@@ -941,25 +1196,26 @@
941 */1196 */
942 public void get_hover_position (DockItem hovered, out int x, out int y)1197 public void get_hover_position (DockItem hovered, out int x, out int y)
943 {1198 {
944 var rect = get_item_hover_region (hovered);1199 var center = get_draw_value_for_item (hovered).static_center;
1200 var offset = (ZoomIconSize - IconSize / 2.0);
945 1201
946 switch (Position) {1202 switch (Position) {
947 default:1203 default:
948 case Gtk.PositionType.BOTTOM:1204 case Gtk.PositionType.BOTTOM:
949 x = rect.x + win_x + rect.width / 2;1205 x = (int) Math.round (center.x + win_x);
950 y = rect.y + win_y;1206 y = (int) Math.round (center.y + win_y - offset);
951 break;1207 break;
952 case Gtk.PositionType.TOP:1208 case Gtk.PositionType.TOP:
953 x = rect.x + win_x + rect.width / 2;1209 x = (int) Math.round (center.x + win_x);
954 y = rect.y + win_y + rect.height;1210 y = (int) Math.round (center.y + win_y + offset);
955 break;1211 break;
956 case Gtk.PositionType.LEFT:1212 case Gtk.PositionType.LEFT:
957 y = rect.y + win_y + rect.height / 2;1213 x = (int) Math.round (center.x + win_x + offset);
958 x = rect.x + win_x + rect.width;1214 y = (int) Math.round (center.y + win_y);
959 break;1215 break;
960 case Gtk.PositionType.RIGHT:1216 case Gtk.PositionType.RIGHT:
961 y = rect.y + win_y + rect.height / 2;1217 x = (int) Math.round (center.x + win_x - offset);
962 x = rect.x + win_x;1218 y = (int) Math.round (center.y + win_y);
963 break;1219 break;
964 }1220 }
965 }1221 }
@@ -973,7 +1229,7 @@
973 */1229 */
974 public void get_urgent_glow_position (DockItem item, out int x, out int y)1230 public void get_urgent_glow_position (DockItem item, out int x, out int y)
975 {1231 {
976 var rect = get_item_hover_region (item);1232 var rect = get_hover_region_for_element (item);
977 var glow_size = GlowSize;1233 var glow_size = GlowSize;
978 1234
979 switch (Position) {1235 switch (Position) {
@@ -1130,8 +1386,12 @@
1130 */1386 */
1131 public Gdk.Rectangle get_background_region ()1387 public Gdk.Rectangle get_background_region ()
1132 {1388 {
1133 var x = 0, y = 0;1389 return background_rect;
1134 var width = 0, height = 0;1390 }
1391
1392 void update_background_region (DockItemDrawValue val_first, DockItemDrawValue val_last)
1393 {
1394 var x = 0, y = 0, width = 0, height = 0;
1135 1395
1136 if (screen_is_composited) {1396 if (screen_is_composited) {
1137 x = static_dock_region.x;1397 x = static_dock_region.x;
@@ -1143,27 +1403,64 @@
1143 height = DockHeight;1403 height = DockHeight;
1144 }1404 }
1145 1405
1406 if (Alignment == Gtk.Align.FILL) {
1407 switch (Position) {
1408 default:
1409 case Gtk.PositionType.BOTTOM:
1410 x += (width - DockBackgroundWidth) / 2;
1411 y += height - DockBackgroundHeight;
1412 break;
1413 case Gtk.PositionType.TOP:
1414 x += (width - DockBackgroundWidth) / 2;
1415 y = 0;
1416 break;
1417 case Gtk.PositionType.LEFT:
1418 x = 0;
1419 y += (height - DockBackgroundHeight) / 2;
1420 break;
1421 case Gtk.PositionType.RIGHT:
1422 x += width - DockBackgroundWidth;
1423 y += (height - DockBackgroundHeight) / 2;
1424 break;
1425 }
1426
1427 background_rect = { x, y, DockBackgroundWidth, DockBackgroundHeight };
1428 return;
1429 }
1430
1431 var center_first = val_first.center;
1432 var center_last = val_last.center;
1433 var padding = IconSize + ItemPadding + 2 * HorizPadding + 4 * LineWidth;
1434
1146 switch (Position) {1435 switch (Position) {
1147 default:1436 default:
1148 case Gtk.PositionType.BOTTOM:1437 case Gtk.PositionType.BOTTOM:
1149 x += (width - DockBackgroundWidth) / 2;1438 x = (int) Math.round (center_first.x - padding / 2.0);
1150 y += height - DockBackgroundHeight;1439 y += height - DockBackgroundHeight;
1440 width = (int) Math.round (center_last.x - center_first.x + padding);
1441 height = DockBackgroundHeight;
1151 break;1442 break;
1152 case Gtk.PositionType.TOP:1443 case Gtk.PositionType.TOP:
1153 x += (width - DockBackgroundWidth) / 2;1444 x = (int) Math.round (center_first.x - padding / 2.0);
1154 y = 0;1445 y = 0;
1446 width = (int) Math.round (center_last.x - center_first.x + padding);
1447 height = DockBackgroundHeight;
1155 break;1448 break;
1156 case Gtk.PositionType.LEFT:1449 case Gtk.PositionType.LEFT:
1157 x = 0;1450 x = 0;
1158 y += (height - DockBackgroundHeight) / 2;1451 y = (int) Math.round (center_first.y - padding / 2.0);
1452 width = DockBackgroundWidth;
1453 height = (int) Math.round (center_last.y - center_first.y + padding);
1159 break;1454 break;
1160 case Gtk.PositionType.RIGHT:1455 case Gtk.PositionType.RIGHT:
1161 x += width - DockBackgroundWidth;1456 x += width - DockBackgroundWidth;
1162 y += (height - DockBackgroundHeight) / 2;1457 y = (int) Math.round (center_first.y - padding / 2.0);
1458 width = DockBackgroundWidth;
1459 height = (int) Math.round (center_last.y - center_first.y + padding);
1163 break;1460 break;
1164 }1461 }
1165 1462
1166 return { x, y, DockBackgroundWidth, DockBackgroundHeight };1463 background_rect = { x, y, width, height };
1167 }1464 }
1168 1465
1169 /**1466 /**
@@ -1175,7 +1472,7 @@
1175 */1472 */
1176 public Gdk.Rectangle get_icon_geometry (ApplicationDockItem item, bool for_hidden)1473 public Gdk.Rectangle get_icon_geometry (ApplicationDockItem item, bool for_hidden)
1177 {1474 {
1178 var region = get_item_hover_region (item);1475 var region = get_hover_region_for_element (item);
1179 1476
1180 if (!for_hidden) {1477 if (!for_hidden) {
1181 region.x += win_x;1478 region.x += win_x;
11821479
=== modified file 'lib/Widgets/DockWindow.vala'
--- lib/Widgets/DockWindow.vala 2015-06-10 16:44:08 +0000
+++ lib/Widgets/DockWindow.vala 2015-07-16 08:37:41 +0000
@@ -234,6 +234,7 @@
234 if (menu_is_visible ())234 if (menu_is_visible ())
235 return Gdk.EVENT_STOP;235 return Gdk.EVENT_STOP;
236 236
237 controller.renderer.update_local_cursor ((int) event.x, (int) event.y);
237 update_hovered ((int) event.x, (int) event.y);238 update_hovered ((int) event.x, (int) event.y);
238 239
239 return Gdk.EVENT_PROPAGATE;240 return Gdk.EVENT_PROPAGATE;
@@ -394,7 +395,7 @@
394 395
395 // check if there already was a hovered-item and if it is still hovered to speed up things396 // check if there already was a hovered-item and if it is still hovered to speed up things
396 if (HoveredItem != null) {397 if (HoveredItem != null) {
397 rect = position_manager.get_item_hover_region (HoveredItem);398 rect = position_manager.get_hover_region_for_element (HoveredItem);
398 if (y >= rect.y && y < rect.y + rect.height && x >= rect.x && x < rect.x + rect.width)399 if (y >= rect.y && y < rect.y + rect.height && x >= rect.x && x < rect.x + rect.width)
399 // Do not allow the hovered-item to be the drag-item400 // Do not allow the hovered-item to be the drag-item
400 if (drag_item == HoveredItem) {401 if (drag_item == HoveredItem) {
@@ -421,7 +422,7 @@
421 foreach (var element in controller.VisibleElements) {422 foreach (var element in controller.VisibleElements) {
422 item = (element as DockItem);423 item = (element as DockItem);
423 if (item != null) {424 if (item != null) {
424 rect = position_manager.get_item_hover_region (item);425 rect = position_manager.get_hover_region_for_element (item);
425 if (y < rect.y || y >= rect.y + rect.height || x < rect.x || x >= rect.x + rect.width)426 if (y < rect.y || y >= rect.y + rect.height || x < rect.x || x >= rect.x + rect.width)
426 continue;427 continue;
427 428
@@ -438,7 +439,7 @@
438 if (provider == null)439 if (provider == null)
439 continue;440 continue;
440 441
441 rect = position_manager.get_item_hover_region (provider);442 rect = position_manager.get_hover_region_for_element (provider);
442 if (y < rect.y || y >= rect.y + rect.height || x < rect.x || x >= rect.x + rect.width)443 if (y < rect.y || y >= rect.y + rect.height || x < rect.x || x >= rect.x + rect.width)
443 continue;444 continue;
444 445
@@ -446,7 +447,7 @@
446 found_hovered_provider = true;447 found_hovered_provider = true;
447 448
448 foreach (var element2 in provider.VisibleElements) {449 foreach (var element2 in provider.VisibleElements) {
449 rect = position_manager.get_item_hover_region (element2);450 rect = position_manager.get_hover_region_for_element (element2);
450 if (y < rect.y || y >= rect.y + rect.height || x < rect.x || x >= rect.x + rect.width)451 if (y < rect.y || y >= rect.y + rect.height || x < rect.x || x >= rect.x + rect.width)
451 continue;452 continue;
452 453
453454
=== modified file 'lib/Widgets/PreferencesWindow.vala'
--- lib/Widgets/PreferencesWindow.vala 2015-07-12 09:40:05 +0000
+++ lib/Widgets/PreferencesWindow.vala 2015-07-16 08:37:41 +0000
@@ -40,11 +40,13 @@
40 Gtk.SpinButton sp_hide_delay;40 Gtk.SpinButton sp_hide_delay;
41 Gtk.SpinButton sp_unhide_delay;41 Gtk.SpinButton sp_unhide_delay;
42 Gtk.Scale s_offset;42 Gtk.Scale s_offset;
43 Gtk.Scale s_zoom_percent;
43 44
44 Gtk.Adjustment adj_hide_delay;45 Gtk.Adjustment adj_hide_delay;
45 Gtk.Adjustment adj_unhide_delay;46 Gtk.Adjustment adj_unhide_delay;
46 Gtk.Adjustment adj_iconsize;47 Gtk.Adjustment adj_iconsize;
47 Gtk.Adjustment adj_offset;48 Gtk.Adjustment adj_offset;
49 Gtk.Adjustment adj_zoom_percent;
48 50
49 Gtk.Switch sw_hide;51 Gtk.Switch sw_hide;
50 Gtk.Switch sw_primary_display;52 Gtk.Switch sw_primary_display;
@@ -54,6 +56,7 @@
54 Gtk.Switch sw_auto_pinning;56 Gtk.Switch sw_auto_pinning;
55 Gtk.Switch sw_pressure_reveal;57 Gtk.Switch sw_pressure_reveal;
56 Gtk.Switch sw_show_dock_item;58 Gtk.Switch sw_show_dock_item;
59 Gtk.Switch sw_zoom_enabled;
57 60
58 public PreferencesWindow (DockPreferences prefs)61 public PreferencesWindow (DockPreferences prefs)
59 {62 {
@@ -105,7 +108,9 @@
105 adj_unhide_delay = builder.get_object ("adj_unhide_delay") as Gtk.Adjustment;108 adj_unhide_delay = builder.get_object ("adj_unhide_delay") as Gtk.Adjustment;
106 adj_iconsize = builder.get_object ("adj_iconsize") as Gtk.Adjustment;109 adj_iconsize = builder.get_object ("adj_iconsize") as Gtk.Adjustment;
107 adj_offset = builder.get_object ("adj_offset") as Gtk.Adjustment;110 adj_offset = builder.get_object ("adj_offset") as Gtk.Adjustment;
111 adj_zoom_percent = builder.get_object ("adj_zoom_percent") as Gtk.Adjustment;
108 s_offset = builder.get_object ("s_offset") as Gtk.Scale;112 s_offset = builder.get_object ("s_offset") as Gtk.Scale;
113 s_zoom_percent = builder.get_object ("s_zoom_percent") as Gtk.Scale;
109 sw_hide = builder.get_object ("sw_hide") as Gtk.Switch;114 sw_hide = builder.get_object ("sw_hide") as Gtk.Switch;
110 sw_primary_display = builder.get_object ("sw_primary_display") as Gtk.Switch;115 sw_primary_display = builder.get_object ("sw_primary_display") as Gtk.Switch;
111 sw_workspace_only = builder.get_object ("sw_workspace_only") as Gtk.Switch;116 sw_workspace_only = builder.get_object ("sw_workspace_only") as Gtk.Switch;
@@ -114,6 +119,7 @@
114 sw_auto_pinning = builder.get_object ("sw_auto_pinning") as Gtk.Switch;119 sw_auto_pinning = builder.get_object ("sw_auto_pinning") as Gtk.Switch;
115 sw_pressure_reveal = builder.get_object ("sw_pressure_reveal") as Gtk.Switch;120 sw_pressure_reveal = builder.get_object ("sw_pressure_reveal") as Gtk.Switch;
116 sw_show_dock_item = builder.get_object ("sw_show_dock_item") as Gtk.Switch;121 sw_show_dock_item = builder.get_object ("sw_show_dock_item") as Gtk.Switch;
122 sw_zoom_enabled = builder.get_object ("sw_zoom_enabled") as Gtk.Switch;
117 cb_alignment = builder.get_object ("cb_alignment") as Gtk.ComboBoxText;123 cb_alignment = builder.get_object ("cb_alignment") as Gtk.ComboBoxText;
118 cb_items_alignment = builder.get_object ("cb_items_alignment") as Gtk.ComboBoxText;124 cb_items_alignment = builder.get_object ("cb_items_alignment") as Gtk.ComboBoxText;
119 125
@@ -197,6 +203,12 @@
197 case "UnhideDelay":203 case "UnhideDelay":
198 adj_unhide_delay.value = prefs.UnhideDelay;204 adj_unhide_delay.value = prefs.UnhideDelay;
199 break;205 break;
206 case "ZoomEnabled":
207 sw_zoom_enabled.set_active (prefs.ZoomEnabled);
208 break;
209 case "ZoomPercent":
210 adj_zoom_percent.value = prefs.ZoomPercent;
211 break;
200 // Ignored settings212 // Ignored settings
201 case "DockItems":213 case "DockItems":
202 break;214 break;
@@ -292,6 +304,17 @@
292 prefs.ShowDockItem = ((Gtk.Switch) widget).get_active ();304 prefs.ShowDockItem = ((Gtk.Switch) widget).get_active ();
293 }305 }
294 306
307 void zoom_enabled_toggled (GLib.Object widget, ParamSpec param)
308 {
309 if (((Gtk.Switch) widget).get_active ()) {
310 prefs.ZoomEnabled = true;
311 s_zoom_percent.sensitive = true;
312 } else {
313 prefs.ZoomEnabled = false;
314 s_zoom_percent.sensitive = false;
315 }
316 }
317
295 void iconsize_changed (Gtk.Adjustment adj)318 void iconsize_changed (Gtk.Adjustment adj)
296 {319 {
297 prefs.IconSize = (int) adj.value;320 prefs.IconSize = (int) adj.value;
@@ -312,6 +335,11 @@
312 prefs.UnhideDelay = (int) adj.value;335 prefs.UnhideDelay = (int) adj.value;
313 }336 }
314 337
338 void zoom_percent_changed (Gtk.Adjustment adj)
339 {
340 prefs.ZoomPercent = (int) adj.value;
341 }
342
315 void monitor_changed (Gtk.ComboBox widget)343 void monitor_changed (Gtk.ComboBox widget)
316 {344 {
317 prefs.Monitor = ((Gtk.ComboBoxText) widget).get_active_text ();345 prefs.Monitor = ((Gtk.ComboBoxText) widget).get_active_text ();
@@ -329,6 +357,7 @@
329 cb_display_plug.changed.connect (monitor_changed);357 cb_display_plug.changed.connect (monitor_changed);
330 adj_iconsize.value_changed.connect (iconsize_changed);358 adj_iconsize.value_changed.connect (iconsize_changed);
331 adj_offset.value_changed.connect (offset_changed);359 adj_offset.value_changed.connect (offset_changed);
360 adj_zoom_percent.value_changed.connect (zoom_percent_changed);
332 sw_hide.notify["active"].connect (hide_toggled);361 sw_hide.notify["active"].connect (hide_toggled);
333 sw_primary_display.notify["active"].connect (primary_display_toggled);362 sw_primary_display.notify["active"].connect (primary_display_toggled);
334 sw_workspace_only.notify["active"].connect (workspace_only_toggled);363 sw_workspace_only.notify["active"].connect (workspace_only_toggled);
@@ -337,6 +366,7 @@
337 sw_auto_pinning.notify["active"].connect (auto_pinning_toggled);366 sw_auto_pinning.notify["active"].connect (auto_pinning_toggled);
338 sw_pressure_reveal.notify["active"].connect (pressure_reveal_toggled);367 sw_pressure_reveal.notify["active"].connect (pressure_reveal_toggled);
339 sw_show_dock_item.notify["active"].connect (show_dock_item_toggled);368 sw_show_dock_item.notify["active"].connect (show_dock_item_toggled);
369 sw_zoom_enabled.notify["active"].connect (zoom_enabled_toggled);
340 cb_alignment.changed.connect (cb_alignment_changed);370 cb_alignment.changed.connect (cb_alignment_changed);
341 cb_items_alignment.changed.connect (cb_items_alignment_changed);371 cb_items_alignment.changed.connect (cb_items_alignment_changed);
342 }372 }
@@ -373,7 +403,9 @@
373 403
374 adj_iconsize.value = prefs.IconSize;404 adj_iconsize.value = prefs.IconSize;
375 adj_offset.value = prefs.Offset;405 adj_offset.value = prefs.Offset;
406 adj_zoom_percent.value = prefs.ZoomPercent;
376 s_offset.sensitive = (prefs.Alignment == Gtk.Align.CENTER);407 s_offset.sensitive = (prefs.Alignment == Gtk.Align.CENTER);
408 s_zoom_percent.sensitive = prefs.ZoomEnabled;
377 sw_hide.set_active (prefs.HideMode != HideType.NONE);409 sw_hide.set_active (prefs.HideMode != HideType.NONE);
378 sw_primary_display.set_active (prefs.Monitor == "");410 sw_primary_display.set_active (prefs.Monitor == "");
379 sw_workspace_only.set_active (prefs.CurrentWorkspaceOnly);411 sw_workspace_only.set_active (prefs.CurrentWorkspaceOnly);
@@ -382,6 +414,7 @@
382 sw_auto_pinning.set_active (prefs.AutoPinning);414 sw_auto_pinning.set_active (prefs.AutoPinning);
383 sw_pressure_reveal.set_active (prefs.PressureReveal);415 sw_pressure_reveal.set_active (prefs.PressureReveal);
384 sw_show_dock_item.set_active (prefs.ShowDockItem);416 sw_show_dock_item.set_active (prefs.ShowDockItem);
417 sw_zoom_enabled.set_active (prefs.ZoomEnabled);
385 cb_alignment.active_id = ((int) prefs.Alignment).to_string ();418 cb_alignment.active_id = ((int) prefs.Alignment).to_string ();
386 cb_items_alignment.active_id = ((int) prefs.ItemsAlignment).to_string ();419 cb_items_alignment.active_id = ((int) prefs.ItemsAlignment).to_string ();
387 cb_items_alignment.sensitive = (prefs.Alignment == Gtk.Align.FILL);420 cb_items_alignment.sensitive = (prefs.Alignment == Gtk.Align.FILL);

Subscribers

People subscribed via source and target branches

to status/vote changes: