42
43
public static readonly TimeSpan BaseAnimationTime = new TimeSpan (0, 0, 0, 0, 150);
45
static DateTime UpdateTimeStamp (DateTime lastStamp, TimeSpan animationLength)
47
TimeSpan delta = DateTime.UtcNow - lastStamp;
48
if (delta < animationLength)
49
return DateTime.UtcNow.Subtract (animationLength - delta);
50
return DateTime.UtcNow;
44
53
const uint OffDockWakeupTime = 250;
45
54
const uint OnDockWakeupTime = 20;
46
const int UrgentBounceHeight = 100;
56
const int UrgentBounceHeight = 80;
47
57
const int LaunchBounceHeight = 30;
49
59
TimeSpan BounceTime = new TimeSpan (0, 0, 0, 0, 700);
50
60
TimeSpan InsertAnimationTime = new TimeSpan (0, 0, 0, 0, 150*5);
52
62
#region Private Variables
55
63
DateTime enter_time = new DateTime (0);
56
64
DateTime interface_change_time = new DateTime (0);
57
65
DateTime last_draw_timeout = new DateTime (0);
58
DateTime cursor_update = new DateTime (0);
66
DateTime showhide_time = new DateTime (0);
67
DateTime painter_time = new DateTime (0);
69
TimeSpan painter_span;
62
71
uint animation_timer;
75
DrawingService drawing_service;
69
79
#region Public Properties
81
/// Returns true if the cursor is over the visible part of the dock or the pixel closest to its autohide edge
83
public bool CursorIsOverDockArea { get; private set; }
72
86
/// The width of the docks window, but not the visible dock
139
/// The current cursor as known to the dock.
141
public Gdk.Point Cursor {
143
return CursorTracker.Cursor;
147
public Gdk.Rectangle MinimumDockArea {
149
return PositionProvider.MinimumDockArea;
154
AutohideTracker AutohideTracker { get; set; }
156
CursorTracker CursorTracker { get; set; }
158
DnDTracker DnDTracker { get; set; }
121
160
DockAnimationState AnimationState { get; set; }
123
162
ItemPositionProvider PositionProvider { get; set; }
125
164
new DockItemMenu PopupMenu { get; set; }
127
bool CursorIsOverDockArea { get; set; }
129
ModifierType CursorModifier { get; set; }
131
166
ReadOnlyCollection<AbstractDockItem> DockItems {
132
167
get { return DockServices.ItemsService.DockItems; }
135
170
AbstractDockItem CurrentDockItem {
137
try { return DockItems [PositionProvider.IndexAtPosition (Cursor)]; }
138
catch { return null; }
172
int index = PositionProvider.IndexAtPosition (Cursor);
173
if (index >= 0 && index < DockItems.Count)
174
return DockItems [index];
143
180
get { return DockPreferences.SummonTime; }
147
/// The current cursor as known to the dock.
149
public Gdk.Point Cursor {
183
bool WindowIntersectingOther {
184
get { return AutohideTracker.WindowIntersectingOther; }
187
IEnumerable<Gdk.Window> WindowStack {
154
bool cursorIsOverDockArea = CursorIsOverDockArea;
157
// We set this value here instead of dynamically checking due to performance constraints.
158
// Ideally our CursorIsOverDockArea getter would do this fairly simple calculation, but it gets
159
// called about 20 to 30 times per render loop, so the savings do add up.
160
Gdk.Rectangle dockRegion;
161
if (PainterOverlayVisible)
162
dockRegion = GetDockArea ();
164
dockRegion = MinimumDockArea;
166
if (cursorIsOverDockArea) {
167
dockRegion.Inflate (0, (int) (IconSize * (DockPreferences.ZoomPercent - 1)) + 22);
168
CursorIsOverDockArea = dockRegion.Contains (cursor);
170
if (DockPreferences.AutoHide) {
171
switch (DockPreferences.Orientation) {
172
case DockOrientation.Bottom:
173
dockRegion.Y += dockRegion.Height - 1;
174
dockRegion.Height = 1;
176
case DockOrientation.Top:
177
dockRegion.Height = 1;
190
return Screen.WindowStack;
193
return Wnck.Screen.Default.WindowsStacked.Select (wnk => Gdk.Window.ForeignNew ((uint) wnk.Xid));
182
CursorIsOverDockArea = dockRegion.Contains (cursor);
185
// When we change over this boundry, it will normally trigger an animation, we need to be sure to catch it
186
if (CursorIsOverDockArea != cursorIsOverDockArea) {
188
enter_time = DateTime.UtcNow;
196
Gdk.Rectangle MinimumDockArea {
198
return PositionProvider.MinimumDockArea;
202
201
public DockArea (DockWindow window) : base ()
203
drawing_service = new DrawingService (this);
204
DockServices.RegisterService (drawing_service);
204
206
this.window = window;
208
ScreenUtils.Initialize ();
209
WindowUtils.Initialize ();
211
AnimationState = new DockAnimationState ();
212
AutohideTracker = new AutohideTracker (this);
213
CursorTracker = new CursorTracker (window, OffDockWakeupTime);
206
214
PositionProvider = new ItemPositionProvider (this);
210
AnimationState = new DockAnimationState ();
215
DnDTracker = new DnDTracker (this, PositionProvider, CursorTracker);
216
PopupMenu = new DockItemMenu ();
211
218
BuildAnimationStateEngine ();
213
PopupMenu = new DockItemMenu ();
215
Cursor = new Gdk.Point (-1, -1);
217
220
this.SetCompositeColormap ();
219
// fixme, we should be using the PointerMotionHintMask
220
AddEvents ((int) EventMask.PointerMotionMask |
221
(int) EventMask.EnterNotifyMask |
222
(int) EventMask.ButtonPressMask |
222
AddEvents ((int) EventMask.ButtonPressMask |
223
223
(int) EventMask.ButtonReleaseMask |
224
224
(int) EventMask.ScrollMask |
225
225
(int) EventMask.FocusChangeMask);
227
228
DoubleBuffered = false;
229
230
BuildRendering ();
232
232
RegisterEvents ();
233
RegisterGtkDragDest ();
234
RegisterGtkDragSource ();
236
234
ResetCursorTimer ();
268
268
Realized += (o, e) => SetParentInputMask ();
269
269
Realized += (o, a) => GdkWindow.SetBackPixmap (null, false);
271
AutohideTracker.IntersectionChanged += HandleIntersectionChanged;
272
Wnck.Screen.Default.ActiveWindowChanged += HandleActiveWindowChanged;
274
CursorTracker.CursorUpdated += HandleCursorUpdated;
276
DnDTracker.DragEnded += HandleDragEnded;
277
DnDTracker.DrawRequired += HandleDrawRequired;
271
279
StyleSet += (o, a) => {
273
281
GdkWindow.SetBackPixmap (null, false);
302
319
() => (CursorIsOverDockArea && ZoomIn != 1) || (!CursorIsOverDockArea && ZoomIn != 0));
304
321
AnimationState.AddCondition (Animations.Open,
305
() => DateTime.UtcNow - enter_time < SummonTime ||
306
DateTime.UtcNow - interface_change_time < SummonTime);
322
() => DateTime.UtcNow - enter_time < BaseAnimationTime ||
323
DateTime.UtcNow - interface_change_time < BaseAnimationTime);
308
325
AnimationState.AddCondition (Animations.Bounce,
309
326
() => DockItems.Any (di => di.TimeSinceClick <= BounceTime));
312
329
() => DockItems.Any (di => DateTime.UtcNow - di.AttentionRequestStartTime < BounceTime));
314
331
AnimationState.AddCondition (Animations.InputModeChanged,
315
() => DateTime.UtcNow - interface_change_time < SummonTime);
332
() => DateTime.UtcNow - interface_change_time < SummonTime ||
333
DateTime.UtcNow - showhide_time < SummonTime);
336
void HandleCursorUpdated (object sender, CursorUpdatedArgs args)
338
if (PopupMenu.Visible)
341
UpdateCursorIsOverDockArea ();
343
bool cursorMoveWarrantsDraw = CursorIsOverDockArea && args.OldCursor.X != args.NewCursor.X;
345
if (DnDTracker.DragResizing || cursorMoveWarrantsDraw)
349
void HandleDrawRequired(object sender, EventArgs e)
354
void HandleDragEnded(object sender, EventArgs e)
318
360
void HandleItemNeedsUpdate (object sender, UpdateRequestArgs args)
320
362
if (args.Type == UpdateRequestType.NeedsAttentionSet) {
321
363
SetParentInputMask ();
366
GLib.Timeout.Add ((uint) BounceTime.Milliseconds + 20, delegate {
372
if (args.Type == UpdateRequestType.IconChanged || args.Type == UpdateRequestType.NameChanged) {
373
RequestIconRender (args.Item);
375
RequestFullRender ();
365
427
if (sender != Painter && sender != LastPainter) return;
367
429
if (args.Animated) {
368
if (AnimationState.Contains (Animations.Painter))
369
AnimationState.RemoveCondition (Animations.Painter);
370
TimeSpan span = args.AnimationLength;
372
DateTime current_time = DateTime.UtcNow;
373
AnimationState.AddCondition (Animations.Painter, () => DateTime.UtcNow - current_time < span);
430
painter_span = args.AnimationLength;
431
painter_time = DateTime.UtcNow;
432
if (!AnimationState.Contains (Animations.Painter))
433
AnimationState.AddCondition (Animations.Painter, () => DateTime.UtcNow - painter_time < painter_span);
419
479
window.PresentWindow ();
420
UnregisterGtkDragSource ();
480
DnDTracker.Disable ();
423
483
void ResetCursorTimer ()
427
if (cursor_timer > 0)
428
GLib.Source.Remove (cursor_timer);
430
uint time = (CursorIsOverDockArea || drag_resizing) ? OnDockWakeupTime : OffDockWakeupTime;
431
cursor_timer = GLib.Timeout.Add (time, OnCursorTimerEllapsed);
485
CursorTracker.TimerLength = (CursorIsOverDockArea || DnDTracker.DragResizing) ? OnDockWakeupTime : OffDockWakeupTime;
434
bool OnCursorTimerEllapsed ()
488
void UpdateCursorIsOverDockArea ()
436
ManualCursorUpdate ();
438
// if we have a painter visible this takes care of interrupting it on mouse off
439
if (!CursorIsOverDockArea && PainterOverlayVisible && (DateTime.UtcNow - enter_time).TotalMilliseconds > 400)
490
bool tmp = CursorIsOverDockArea;
492
Gdk.Rectangle dockRegion;
493
if (PainterOverlayVisible)
494
dockRegion = GetDockArea ();
496
dockRegion = MinimumDockArea;
499
dockRegion.Inflate (0, (int) (IconSize * (DockPreferences.ZoomPercent - 1)) + 22);
502
switch (DockPreferences.Orientation) {
503
case DockOrientation.Bottom:
504
dockRegion.Y += dockRegion.Height - 1;
505
dockRegion.Height = 1;
507
case DockOrientation.Top:
508
dockRegion.Height = 1;
514
if (PainterOverlayVisible)
515
CursorIsOverDockArea = dockRegion.Contains (new Gdk.Point (dockRegion.X, Cursor.Y));
517
CursorIsOverDockArea = dockRegion.Contains (Cursor);
519
if (CursorIsOverDockArea != tmp) {
521
enter_time = UpdateTimeStamp (enter_time, BaseAnimationTime);
523
switch (DockPreferences.AutohideType) {
524
case AutohideType.Autohide:
525
showhide_time = enter_time;
527
case AutohideType.Intellihide:
528
if (WindowIntersectingOther)
529
showhide_time = enter_time;
534
if (PainterOverlayVisible) {
535
GLib.Timeout.Add (500, delegate {
536
if (!CursorIsOverDockArea && PainterOverlayVisible && (DateTime.UtcNow - enter_time).TotalMilliseconds > 400)
445
545
void AnimatedDraw ()
512
614
void OnDockItemMenuShown (object o, EventArgs args)
616
CursorTracker.Enabled = false;
517
void ManualCursorUpdate ()
519
if ((DateTime.UtcNow - cursor_update).TotalMilliseconds < 15) {
527
Display.GetPointer (out screen, out x, out y, out mod);
529
if (screen == Screen) {
530
Gdk.Rectangle geo, hide_offset;
531
window.GetBufferedPosition (out geo.X, out geo.Y);
532
window.WindowHideOffset (out hide_offset.X, out hide_offset.Y);
534
x -= geo.X - hide_offset.X;
535
y -= geo.Y - hide_offset.Y;
541
SetupCursor (x, y, mod);
544
void SetupCursor (int x, int y, ModifierType mod)
546
CursorModifier = mod;
548
if ((Cursor.X == x && Cursor.Y == y) || PopupMenu.Visible)
551
Gdk.Point old_cursor_location = Cursor;
552
Cursor = new Gdk.Point (x, y);
559
bool cursorMoveWarrantsDraw = CursorIsOverDockArea && old_cursor_location.X != Cursor.X;
561
if (drag_resizing || cursorMoveWarrantsDraw)
565
protected override bool OnMotionNotifyEvent (Gdk.EventMotion evnt)
568
SetupCursor ((int) evnt.X, (int) evnt.Y, evnt.State);
569
cursor_update = DateTime.UtcNow;
570
return base.OnMotionNotifyEvent (evnt);
573
protected override bool OnEnterNotifyEvent (Gdk.EventCrossing evnt)
576
ManualCursorUpdate ();
577
return base.OnEnterNotifyEvent (evnt);
580
protected override bool OnButtonPressEvent (Gdk.EventButton evnt)
582
if (CursorNearDraggableEdge)
585
return base.OnButtonPressEvent (evnt);
588
620
public void ProxyButtonReleaseEvent (Gdk.EventButton evnt)
590
622
HandleButtonReleaseEvent (evnt);
639
668
//send off the clicks
640
Gdk.Point relative_point = Gdk.Point.Zero;
669
PointD relative_point = RelativePointOverItem (item);
641
670
DockItems [item].Clicked (evnt.Button, evnt.State, relative_point);
677
PointD RelativePointOverItem (int item)
679
PointD relative_point = new PointD (0,0);
682
IconZoomedPosition (item, out center, out zoom);
684
int left = (int) (center.X - DockItems [item].Width * zoom / 2);
685
int top = (int) (center.Y - DockItems [item].Height * zoom / 2);
686
int right = (int) (center.X + DockItems [item].Width * zoom / 2);
687
int bottom = (int) (center.Y + DockItems [item].Height * zoom / 2);
689
relative_point.X = (Cursor.X - left) / (double) (right - left);
690
relative_point.Y = (Cursor.Y - top) / (double) (bottom - top);
692
return relative_point;
648
695
protected override bool OnScrollEvent (Gdk.EventScroll evnt)
650
int item = PositionProvider.IndexAtPosition ((int) evnt.X, (int) evnt.Y);
654
DockItems [item].Scrolled (evnt.Direction);
697
if (PainterOverlayVisible) {
698
Painter.Scrolled (evnt.Direction);
700
int item = PositionProvider.IndexAtPosition ((int) evnt.X, (int) evnt.Y);
701
if (item >= 0 && item < DockItems.Count)
702
DockItems [item].Scrolled (evnt.Direction);
655
704
return base.OnScrollEvent (evnt);
658
707
void SetIconRegions ()
660
Gdk.Rectangle pos, area, offset;
709
Gdk.Rectangle pos, area;
661
710
window.GetPosition (out pos.X, out pos.Y);
662
711
window.GetSize (out pos.Width, out pos.Height);
664
window.WindowHideOffset (out offset.X, out offset.Y);
665
713
// we use geo here instead of our position for the Y value because we know the parent window
666
714
// may offset us when hidden. This is not desired...
667
715
for (int i = 0; i < DockItems.Count; i++) {
668
716
Gdk.Point position = PositionProvider.IconUnzoomedPosition (i);
669
area = new Gdk.Rectangle (pos.X + (position.X - IconSize / 2) - offset.X,
670
pos.Y + (position.Y - IconSize / 2) - offset.Y,
717
area = new Gdk.Rectangle (pos.X + (position.X - IconSize / 2),
718
pos.Y + (position.Y - IconSize / 2),
673
721
DockItems [i].SetIconRegion (area);
686
734
offset = GetDockArea ().Height;
687
735
offset = offset * 2 + 10;
689
if (DockPreferences.AutoHide && !drag_resizing) {
690
// setting the offset to 2 will trigger the parent window to unhide us if we are hidden.
691
if (AnimationState [Animations.UrgencyChanged])
737
if (IsHidden && !DnDTracker.DragResizing) {
696
740
offset = GetDockArea ().Height;
700
int dockSize = (drag_resizing) ? Width : MinimumDockArea.Width;
744
int dockSize = (DnDTracker.DragResizing) ? Width : MinimumDockArea.Width;
702
746
switch (DockPreferences.Orientation) {
703
747
case DockOrientation.Bottom:
724
768
PainterOverlayVisible = false;
725
769
interface_change_time = DateTime.UtcNow;
727
RegisterGtkDragSource ();
771
DnDTracker.Enable ();
728
772
window.UnpresentWindow ();
730
774
SetParentInputMask ();
734
778
public override void Dispose ()
780
DockServices.UnregisterService (drawing_service).Dispose ();
737
782
UnregisterEvents ();
738
UnregisterGtkDragSource ();
783
DnDTracker.Disable ();
785
AutohideTracker.Dispose ();
786
CursorTracker.Dispose ();
787
DnDTracker.Dispose ();
740
788
PositionProvider.Dispose ();
741
789
AnimationState.Dispose ();
742
790
PopupMenu.Destroy ();
791
PopupMenu.Dispose ();
744
793
PositionProvider = null;
745
794
AnimationState = null;