~and471/+junk/do-with-docky

« back to all changes in this revision

Viewing changes to Do.Interface.Linux.Docky/src/Docky.Interface/DockArea.cs

  • Committer: rugby471 at gmail
  • Date: 2010-10-15 16:08:38 UTC
  • Revision ID: rugby471@gmail.com-20101015160838-z9m3utbf7bxzb5ty
reverted to before docky removal

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// DockArea.cs
 
2
// 
 
3
// Copyright (C) 2008 GNOME Do
 
4
//
 
5
// This program is free software: you can redistribute it and/or modify
 
6
// it under the terms of the GNU General Public License as published by
 
7
// the Free Software Foundation, either version 3 of the License, or
 
8
// (at your option) any later version.
 
9
//
 
10
// This program is distributed in the hope that it will be useful,
 
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
// GNU General Public License for more details.
 
14
//
 
15
// You should have received a copy of the GNU General Public License
 
16
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
17
//
 
18
 
 
19
using System;
 
20
using System.Collections.Generic;
 
21
using System.Collections.ObjectModel;
 
22
using System.Linq;
 
23
 
 
24
using Cairo;
 
25
using Gdk;
 
26
using Gtk;
 
27
 
 
28
using Do.Platform;
 
29
using Do.Interface.Wink;
 
30
using Do.Interface.Xlib;
 
31
 
 
32
using Docky.Core;
 
33
using Docky.Utilities;
 
34
using Docky.Interface.Menus;
 
35
using Docky.Interface.Painters;
 
36
 
 
37
namespace Docky.Interface
 
38
{
 
39
        
 
40
        
 
41
        internal partial class DockArea : Gtk.DrawingArea
 
42
        {
 
43
                public static readonly TimeSpan BaseAnimationTime = new TimeSpan (0, 0, 0, 0, 150);
 
44
                
 
45
                static DateTime UpdateTimeStamp (DateTime lastStamp, TimeSpan animationLength)
 
46
                {
 
47
                        TimeSpan delta = DateTime.UtcNow - lastStamp;
 
48
                        if (delta < animationLength)
 
49
                                return DateTime.UtcNow.Subtract (animationLength - delta);
 
50
                        return DateTime.UtcNow;
 
51
                }
 
52
                
 
53
                const uint OffDockWakeupTime = 250;
 
54
                const uint OnDockWakeupTime = 20;
 
55
                
 
56
                const int UrgentBounceHeight = 80;
 
57
                const int LaunchBounceHeight = 30;
 
58
 
 
59
                TimeSpan BounceTime = new TimeSpan (0, 0, 0, 0, 700);
 
60
                TimeSpan InsertAnimationTime = new TimeSpan (0, 0, 0, 0, 150*5);
 
61
                
 
62
                #region Private Variables
 
63
                DateTime enter_time = new DateTime (0);
 
64
                DateTime interface_change_time = new DateTime (0);
 
65
                DateTime last_draw_timeout = new DateTime (0);
 
66
                DateTime showhide_time = new DateTime (0);
 
67
                DateTime painter_time = new DateTime (0);
 
68
                
 
69
                TimeSpan painter_span;
 
70
                
 
71
                uint animation_timer;
 
72
                
 
73
                DockWindow window;
 
74
                
 
75
                DrawingService drawing_service;
 
76
                
 
77
                #endregion
 
78
                
 
79
                #region Public Properties
 
80
                //// <value>
 
81
                /// Returns true if the cursor is over the visible part of the dock or the pixel closest to its autohide edge
 
82
                /// </value>
 
83
                public bool CursorIsOverDockArea { get; private set; }
 
84
                
 
85
                /// <value>
 
86
                /// The width of the docks window, but not the visible dock
 
87
                /// </value>
 
88
                public int Width { get; private set; }
 
89
                
 
90
                /// <value>
 
91
                /// The height of the docks window
 
92
                /// </value>
 
93
                public int Height { get; private set; }
 
94
                
 
95
                //// <value>
 
96
                /// Returns true if the dock is currently being overlayed by an IDockPainter
 
97
                /// </value>
 
98
                public bool PainterOverlayVisible { get; private set; }
 
99
                
 
100
                /// <value>
 
101
                /// The width of the visible dock
 
102
                /// </value>
 
103
                public int DockWidth {
 
104
                        get { return PositionProvider.DockWidth; }
 
105
                }
 
106
                
 
107
                /// <summary>
 
108
                /// The height of the visible dock
 
109
                /// </summary>
 
110
                public int DockHeight {
 
111
                        get { return PositionProvider.DockHeight; }
 
112
                }
 
113
                
 
114
                public uint[] StrutRequest {
 
115
                        get {
 
116
                                uint[] values = new uint[12];
 
117
                                Gdk.Rectangle geo = LayoutUtils.MonitorGeometry ();
 
118
                                
 
119
                                if (DockPreferences.AutohideType != AutohideType.None)
 
120
                                        return values;
 
121
                                
 
122
                                switch (DockPreferences.Orientation) {
 
123
                                case DockOrientation.Bottom:
 
124
                                        values [(int) Struts.Bottom] = (uint) (DockHeight + (Screen.Height - (geo.Y + geo.Height)));
 
125
                                        values [(int) Struts.BottomStart] = (uint) geo.X;
 
126
                                        values [(int) Struts.BottomEnd] = (uint) (geo.X + geo.Width - 1);
 
127
                                        break;
 
128
                                case DockOrientation.Top:
 
129
                                        values [(int) Struts.Top] = (uint) (DockHeight + geo.Y);
 
130
                                        values [(int) Struts.TopStart] = (uint) geo.X;
 
131
                                        values [(int) Struts.TopEnd] = (uint) (geo.X + geo.Width - 1);
 
132
                                        break;
 
133
                                }
 
134
                                return values;
 
135
                        }
 
136
                }
 
137
 
 
138
                /// <value>
 
139
                /// The current cursor as known to the dock.
 
140
                /// </value>
 
141
                public Gdk.Point Cursor {
 
142
                        get {
 
143
                                return CursorTracker.Cursor;
 
144
                        }
 
145
                }
 
146
                
 
147
                public Gdk.Rectangle MinimumDockArea {
 
148
                        get {
 
149
                                return PositionProvider.MinimumDockArea;
 
150
                        }
 
151
                }
 
152
                #endregion
 
153
                
 
154
                AutohideTracker AutohideTracker { get; set; }
 
155
                
 
156
                CursorTracker CursorTracker { get; set; }
 
157
                
 
158
                DnDTracker DnDTracker { get; set; }
 
159
                
 
160
                DockAnimationState AnimationState { get; set; }
 
161
                
 
162
                ItemPositionProvider PositionProvider { get; set; }
 
163
 
 
164
                new DockItemMenu PopupMenu { get; set; }
 
165
                
 
166
                ReadOnlyCollection<AbstractDockItem> DockItems { 
 
167
                        get { return DockServices.ItemsService.DockItems; } 
 
168
                }
 
169
                
 
170
                AbstractDockItem CurrentDockItem {
 
171
                        get {
 
172
                                int index = PositionProvider.IndexAtPosition (Cursor);
 
173
                                if (index >= 0 && index < DockItems.Count)
 
174
                                        return DockItems [index];
 
175
                                return null;
 
176
                        }
 
177
                }
 
178
                
 
179
                TimeSpan SummonTime {
 
180
                        get { return DockPreferences.SummonTime; }
 
181
                }
 
182
                
 
183
                bool WindowIntersectingOther { 
 
184
                        get { return AutohideTracker.WindowIntersectingOther; }
 
185
                }
 
186
                
 
187
                IEnumerable<Gdk.Window> WindowStack {
 
188
                        get {
 
189
                                try {
 
190
                                        return Screen.WindowStack;
 
191
                                } catch { 
 
192
                                        try {
 
193
                                                return Wnck.Screen.Default.WindowsStacked.Select (wnk => Gdk.Window.ForeignNew ((uint) wnk.Xid));
 
194
                                        } catch {
 
195
                                                return null;
 
196
                                        }
 
197
                                }
 
198
                        }
 
199
                }
 
200
                
 
201
                public DockArea (DockWindow window) : base ()
 
202
                {
 
203
                        drawing_service = new DrawingService (this);
 
204
                        DockServices.RegisterService (drawing_service);
 
205
                        
 
206
                        this.window = window;
 
207
                        
 
208
                        ScreenUtils.Initialize ();
 
209
                        WindowUtils.Initialize ();
 
210
                        
 
211
                        AnimationState   = new DockAnimationState ();
 
212
                        AutohideTracker  = new AutohideTracker (this);
 
213
                        CursorTracker    = new CursorTracker (window, OffDockWakeupTime);
 
214
                        PositionProvider = new ItemPositionProvider (this);
 
215
                        DnDTracker       = new DnDTracker (this, PositionProvider, CursorTracker);
 
216
                        PopupMenu        = new DockItemMenu ();
 
217
                        
 
218
                        BuildAnimationStateEngine ();
 
219
 
 
220
                        this.SetCompositeColormap ();
 
221
 
 
222
                        AddEvents ((int) EventMask.ButtonPressMask | 
 
223
                                   (int) EventMask.ButtonReleaseMask |
 
224
                                   (int) EventMask.ScrollMask |
 
225
                                   (int) EventMask.FocusChangeMask);
 
226
                        
 
227
                        SetSize ();
 
228
                        DoubleBuffered = false;
 
229
 
 
230
                        BuildRendering ();
 
231
                        
 
232
                        RegisterEvents ();
 
233
                        
 
234
                        ResetCursorTimer ();
 
235
                }
 
236
                
 
237
                void SetSize ()
 
238
                {
 
239
                        Gdk.Rectangle geo;
 
240
                        geo = LayoutUtils.MonitorGeometry ();
 
241
                        
 
242
                        Width = geo.Width;
 
243
                        Height = DockPreferences.FullIconSize + 2 * PositionProvider.VerticalBuffer + UrgentBounceHeight;
 
244
                        Height = Math.Max (150, Height);
 
245
                        
 
246
                        SetSizeRequest (Width, Height);
 
247
                }
 
248
 
 
249
                void RegisterEvents ()
 
250
                {
 
251
                        DockServices.ItemsService.DockItemsChanged += OnDockItemsChanged;
 
252
                        DockServices.ItemsService.ItemNeedsUpdate += HandleItemNeedsUpdate;
 
253
                        
 
254
                        DockPreferences.MonitorChanged += HandleMonitorChanged; 
 
255
                        DockPreferences.IconSizeChanged += HandleIconSizeChanged; 
 
256
                        DockPreferences.OrientationChanged += HandleOrientationChanged; 
 
257
                        
 
258
                        DockServices.PainterService.PainterShowRequest += HandlePainterShowRequest;
 
259
                        DockServices.PainterService.PainterHideRequest += HandlePainterHideRequest;
 
260
 
 
261
                        Screen.SizeChanged += HandleSizeChanged; 
 
262
                        
 
263
                        PopupMenu.Hidden += OnDockItemMenuHidden;
 
264
                        PopupMenu.Shown += OnDockItemMenuShown;
 
265
 
 
266
                        Services.Core.UniverseInitialized += HandleUniverseInitialized;
 
267
                        
 
268
                        Realized += (o, e) => SetParentInputMask ();
 
269
                        Realized += (o, a) => GdkWindow.SetBackPixmap (null, false);
 
270
                        
 
271
                        AutohideTracker.IntersectionChanged += HandleIntersectionChanged;
 
272
                        Wnck.Screen.Default.ActiveWindowChanged += HandleActiveWindowChanged;
 
273
                        
 
274
                        CursorTracker.CursorUpdated += HandleCursorUpdated;
 
275
                        
 
276
                        DnDTracker.DragEnded += HandleDragEnded;
 
277
                        DnDTracker.DrawRequired += HandleDrawRequired; 
 
278
                        
 
279
                        window.KeyPressEvent += HandleKeyPressEvent;
 
280
                        
 
281
                        StyleSet += (o, a) => { 
 
282
                                if (IsRealized)
 
283
                                        GdkWindow.SetBackPixmap (null, false);
 
284
                        };
 
285
                }
 
286
 
 
287
                void UnregisterEvents ()
 
288
                {
 
289
                        DockServices.ItemsService.DockItemsChanged -= OnDockItemsChanged;
 
290
                        DockServices.ItemsService.ItemNeedsUpdate -= HandleItemNeedsUpdate;
 
291
                        
 
292
                        DockPreferences.MonitorChanged -= HandleMonitorChanged;
 
293
                        DockPreferences.IconSizeChanged -= HandleIconSizeChanged; 
 
294
                        DockPreferences.OrientationChanged -= HandleOrientationChanged; 
 
295
                        
 
296
                        DockServices.PainterService.PainterShowRequest -= HandlePainterShowRequest;
 
297
                        DockServices.PainterService.PainterHideRequest -= HandlePainterHideRequest;
 
298
 
 
299
                        Screen.SizeChanged -= HandleSizeChanged;
 
300
                        
 
301
                        PopupMenu.Hidden -= OnDockItemMenuHidden;
 
302
                        PopupMenu.Shown -= OnDockItemMenuShown;
 
303
                        
 
304
                        Services.Core.UniverseInitialized -= HandleUniverseInitialized;
 
305
                        
 
306
                        AutohideTracker.IntersectionChanged -= HandleIntersectionChanged;
 
307
                        Wnck.Screen.Default.ActiveWindowChanged -= HandleActiveWindowChanged;
 
308
                        
 
309
                        CursorTracker.CursorUpdated -= HandleCursorUpdated;
 
310
                        
 
311
                        DnDTracker.DragEnded -= HandleDragEnded;
 
312
                        DnDTracker.DrawRequired -= HandleDrawRequired; 
 
313
                        
 
314
                        window.KeyPressEvent -= HandleKeyPressEvent;
 
315
                }
 
316
                
 
317
                void BuildAnimationStateEngine ()
 
318
                {
 
319
                        AnimationState.AddCondition (Animations.IconInsert, 
 
320
                                                     () => DockItems.Any (di => di.TimeSinceAdd < InsertAnimationTime));
 
321
                        
 
322
                        AnimationState.AddCondition (Animations.Zoom,
 
323
                                                     () => (CursorIsOverDockArea && ZoomIn != 1) || (!CursorIsOverDockArea && ZoomIn != 0));
 
324
                        
 
325
                        AnimationState.AddCondition (Animations.Open,
 
326
                                                     () => DateTime.UtcNow - enter_time < BaseAnimationTime ||
 
327
                                                     DateTime.UtcNow - interface_change_time < BaseAnimationTime);
 
328
                        
 
329
                        AnimationState.AddCondition (Animations.Bounce,
 
330
                                                     () => DockItems.Any (di => di.TimeSinceClick <= BounceTime));
 
331
                        
 
332
                        AnimationState.AddCondition (Animations.UrgencyChanged,
 
333
                                                     () => DockItems.Any (di => DateTime.UtcNow - di.AttentionRequestStartTime < BounceTime));
 
334
                        
 
335
                        AnimationState.AddCondition (Animations.InputModeChanged,
 
336
                                                     () => DateTime.UtcNow - interface_change_time < SummonTime || 
 
337
                                                     DateTime.UtcNow - showhide_time < SummonTime);
 
338
                }
 
339
                
 
340
                void HandleKeyPressEvent (Gdk.EventKey key)
 
341
                {
 
342
                        KeyBinding clearKeyBinding = Services.Keybinder.Bindings.Where(p => p.Description == Mono.Unix.Catalog.GetString ("Clear")).FirstOrDefault();
 
343
                        if (PainterOverlayVisible &&
 
344
                                clearKeyBinding != null && Services.Keybinder.KeyEventToString (key) == clearKeyBinding.KeyString)
 
345
                                InterruptPainter ();
 
346
                }
 
347
                
 
348
                void HandleCursorUpdated (object sender, CursorUpdatedArgs args)
 
349
                {
 
350
                        if (PopupMenu.Visible)
 
351
                                return;
 
352
                        
 
353
                        UpdateCursorIsOverDockArea ();
 
354
 
 
355
                        bool cursorMoveWarrantsDraw = CursorIsOverDockArea && args.OldCursor.X != args.NewCursor.X;
 
356
 
 
357
                        if (DnDTracker.DragResizing || cursorMoveWarrantsDraw) 
 
358
                                AnimatedDraw ();
 
359
                }
 
360
                
 
361
                void HandleDrawRequired(object sender, EventArgs e)
 
362
                {
 
363
                        AnimatedDraw ();
 
364
                }
 
365
 
 
366
                void HandleDragEnded(object sender, EventArgs e)
 
367
                {
 
368
                        ResetCursorTimer ();
 
369
                        Reconfigure ();
 
370
                }
 
371
 
 
372
                void HandleItemNeedsUpdate (object sender, UpdateRequestArgs args)
 
373
                {
 
374
                        if (args.Type == UpdateRequestType.NeedsAttentionSet) {
 
375
                                SetParentInputMask ();
 
376
                                Reconfigure ();
 
377
                                
 
378
                                GLib.Timeout.Add ((uint) BounceTime.Milliseconds + 20, delegate {
 
379
                                        Reconfigure ();
 
380
                                        return false;
 
381
                                });
 
382
                        }
 
383
                        
 
384
                        if (args.Type == UpdateRequestType.IconChanged || args.Type == UpdateRequestType.NameChanged) {
 
385
                                RequestIconRender (args.Item);
 
386
                        } else {
 
387
                                RequestFullRender ();
 
388
                        }
 
389
                        AnimatedDraw ();
 
390
                }
 
391
 
 
392
                void HandleMonitorChanged()
 
393
                {
 
394
                        Reconfigure ();
 
395
                }
 
396
 
 
397
                void HandleOrientationChanged()
 
398
                {
 
399
                        Reconfigure ();
 
400
                        window.Reposition ();
 
401
                }
 
402
                
 
403
                void HandleSizeChanged (object sender, EventArgs e)
 
404
                {
 
405
                        Reconfigure ();
 
406
                }
 
407
                
 
408
                public void Reconfigure ()
 
409
                {
 
410
                        if (!Visible || !IsRealized || DnDTracker.DragResizing)
 
411
                                return;
 
412
                        
 
413
                        SetSize ();
 
414
                        ResetBuffers ();
 
415
                        PositionProvider.ForceUpdate ();
 
416
                        SetParentInputMask ();
 
417
                        SetIconRegions ();
 
418
                        window.DelaySetStruts ();
 
419
                        AnimatedDraw ();
 
420
                }
 
421
                
 
422
                void HandleUniverseInitialized (object sender, EventArgs e)
 
423
                {
 
424
                        GLib.Timeout.Add (2000, delegate {
 
425
                                DockServices.ItemsService.ForceUpdate ();
 
426
                                SetIconRegions ();
 
427
                                return false;
 
428
                        });
 
429
                }
 
430
                
 
431
                void HandleIconSizeChanged()
 
432
                {
 
433
                        Reconfigure ();
 
434
                        AnimatedDraw ();
 
435
                }
 
436
 
 
437
                void HandlePaintNeeded (object sender, PaintNeededArgs args)
 
438
                {
 
439
                        if (sender != Painter && sender != LastPainter) return;
 
440
                        
 
441
                        if (args.Animated) {
 
442
                                painter_span = args.AnimationLength;
 
443
                                painter_time = DateTime.UtcNow;
 
444
                                if (!AnimationState.Contains (Animations.Painter))
 
445
                                        AnimationState.AddCondition (Animations.Painter, () => DateTime.UtcNow - painter_time < painter_span);
 
446
                        }
 
447
                        AnimatedDraw ();
 
448
                }
 
449
                
 
450
                void HandlePainterHideRequest(object sender, EventArgs e)
 
451
                {
 
452
                        IDockPainter painter = sender as IDockPainter;
 
453
                        if (Painter != painter)
 
454
                                return;
 
455
 
 
456
                        Painter = null;
 
457
                        PainterOverlayVisible = false;
 
458
                        interface_change_time = UpdateTimeStamp (interface_change_time, SummonTime);
 
459
 
 
460
                        SetParentInputMask ();
 
461
                        AnimatedDraw ();
 
462
 
 
463
                        GLib.Timeout.Add (500, () => { 
 
464
                                DockServices.ItemsService.ForceUpdate (); 
 
465
                                return false; 
 
466
                        });
 
467
 
 
468
                        window.UnpresentWindow ();
 
469
                        DnDTracker.Enable ();
 
470
                }
 
471
 
 
472
                void HandlePainterShowRequest(object sender, EventArgs e)
 
473
                {
 
474
                        IDockPainter painter = sender as IDockPainter;
 
475
                        if (Painter == painter)
 
476
                                return;
 
477
                        
 
478
                        if (Painter == null || Painter.Interruptable) {
 
479
                                if (Painter != null)
 
480
                                        Painter.Interrupt ();
 
481
                                Painter = painter;
 
482
                                PainterOverlayVisible = true;
 
483
                                interface_change_time = UpdateTimeStamp (interface_change_time, SummonTime);
 
484
 
 
485
                                SetParentInputMask ();
 
486
                                AnimatedDraw ();
 
487
                        } else {
 
488
                                painter.Interrupt ();
 
489
                        }
 
490
                        
 
491
                        window.PresentWindow ();
 
492
                        DnDTracker.Disable ();
 
493
                }
 
494
                
 
495
                void ResetCursorTimer ()
 
496
                {
 
497
                        CursorTracker.TimerLength = (CursorIsOverDockArea || DnDTracker.DragResizing) ? OnDockWakeupTime : OffDockWakeupTime;
 
498
                }
 
499
                
 
500
                void UpdateCursorIsOverDockArea ()
 
501
                {
 
502
                        bool tmp = CursorIsOverDockArea;
 
503
                        
 
504
                        Gdk.Rectangle dockRegion;
 
505
                        if (PainterOverlayVisible)
 
506
                                dockRegion = GetDockArea ();
 
507
                        else
 
508
                                dockRegion = MinimumDockArea;
 
509
                        
 
510
                        if (tmp) {
 
511
                                dockRegion.Inflate (0, (int) (IconSize * (DockPreferences.ZoomPercent - 1)) + 22);
 
512
                        } else {
 
513
                                if (IsHidden) {
 
514
                                        switch (DockPreferences.Orientation) {
 
515
                                        case DockOrientation.Bottom:
 
516
                                                dockRegion.Y += dockRegion.Height - 1;
 
517
                                                dockRegion.Height = 1;
 
518
                                                break;
 
519
                                        case DockOrientation.Top:
 
520
                                                dockRegion.Height = 1;
 
521
                                                break;
 
522
                                        }
 
523
                                }
 
524
                        }
 
525
                        
 
526
                        if (PainterOverlayVisible)
 
527
                                CursorIsOverDockArea = dockRegion.Contains (new Gdk.Point (dockRegion.X, Cursor.Y));
 
528
                        else
 
529
                                CursorIsOverDockArea = dockRegion.Contains (Cursor);
 
530
                        
 
531
                        if (CursorIsOverDockArea != tmp) {
 
532
                                ResetCursorTimer ();
 
533
                                enter_time = UpdateTimeStamp (enter_time, BaseAnimationTime);
 
534
                                
 
535
                                switch (DockPreferences.AutohideType) {
 
536
                                case AutohideType.Autohide:
 
537
                                        showhide_time = enter_time;
 
538
                                        break;
 
539
                                case AutohideType.Intellihide:
 
540
                                        if (WindowIntersectingOther)
 
541
                                                showhide_time = enter_time;
 
542
                                        break;
 
543
                                }
 
544
                                AnimatedDraw ();
 
545
                                
 
546
                                if (PainterOverlayVisible) {
 
547
                                        GLib.Timeout.Add (500, delegate {
 
548
                                                if (!CursorIsOverDockArea && PainterOverlayVisible && (DateTime.UtcNow - enter_time).TotalMilliseconds > 400)
 
549
                                                        InterruptPainter ();
 
550
                                                return false;
 
551
                                        });
 
552
                                }
 
553
                        }
 
554
                        
 
555
                }
 
556
                
 
557
                void AnimatedDraw ()
 
558
                {
 
559
                        if (0 < animation_timer) {
 
560
                                if ((DateTime.UtcNow - last_draw_timeout).TotalMilliseconds > 500) {
 
561
                                        // honestly this should never happen.  I am not sure if it does but we are going
 
562
                                        // to protect against it because there are reports of rendering failing. A condition
 
563
                                        // where the animation_timer is > 0 without an actual callback tied to it would
 
564
                                        // forever block future animations.
 
565
                                        GLib.Source.Remove (animation_timer);
 
566
                                        animation_timer = 0;
 
567
                                } else {
 
568
                                        return;
 
569
                                }
 
570
                        }
 
571
                        
 
572
                        // the presense of this queue draw has caused some confusion, so I will explain.
 
573
                        // first its here to draw the "first frame".  Without it, we have a 16ms delay till that happens,
 
574
                        // however minor that is.
 
575
                        MaskAndDraw ();
 
576
                        
 
577
                        if (AnimationState.AnimationNeeded)
 
578
                                animation_timer = GLib.Timeout.Add (1000/60, OnDrawTimeoutElapsed);
 
579
                }
 
580
                
 
581
                bool OnDrawTimeoutElapsed ()
 
582
                {
 
583
                        last_draw_timeout = DateTime.UtcNow;
 
584
                        
 
585
                        MaskAndDraw ();
 
586
                        
 
587
                        if (AnimationState.AnimationNeeded)
 
588
                                return true;
 
589
                        
 
590
                        //reset the timer to 0 so that the next time AnimatedDraw is called we fall back into
 
591
                        //the draw loop.
 
592
                        animation_timer = 0;
 
593
                        return false;
 
594
                }
 
595
                
 
596
                void MaskAndDraw ()
 
597
                {
 
598
                        QueueDraw ();
 
599
                        // this is a "protected method".  We need to be sure that our input mask is okay on every frame.
 
600
                        // 99% of the time this means nothing at all will be done
 
601
                        SetParentInputMask ();
 
602
                }
 
603
                
 
604
                void OnDockItemsChanged (IEnumerable<AbstractDockItem> items)
 
605
                {
 
606
                        DockPreferences.MaxIconSize = (int) (((double) Width / MinimumDockArea.Width) * IconSize);
 
607
                        
 
608
                        SetIconRegions ();
 
609
                        RequestFullRender ();
 
610
                        UpdateCursorIsOverDockArea ();
 
611
                        AnimatedDraw ();
 
612
                }
 
613
                
 
614
                void OnDockItemMenuHidden (object o, System.EventArgs args)
 
615
                {
 
616
                        // While an popup menus are being showing, the dock does not recieve mouse updates.  This is
 
617
                        // both a good thing and a bad thing.  We must at the very least update the cursor position once the
 
618
                        // popup is no longer in view.
 
619
                        CursorTracker.Enabled = true;
 
620
                        AnimatedDraw ();
 
621
                }
 
622
                
 
623
                /// <summary>
 
624
                /// Only purpose is to trigger one last redraw to eliminate the hover text
 
625
                /// </summary>
 
626
                void OnDockItemMenuShown (object o, EventArgs args)
 
627
                {
 
628
                        CursorTracker.Enabled = false;
 
629
                        AnimatedDraw ();
 
630
                }
 
631
 
 
632
                public void ProxyButtonReleaseEvent (Gdk.EventButton evnt)
 
633
                {
 
634
                        HandleButtonReleaseEvent (evnt);
 
635
                }
 
636
                
 
637
                protected override bool OnButtonReleaseEvent (Gdk.EventButton evnt)
 
638
                {
 
639
                        bool result = base.OnButtonPressEvent (evnt);
 
640
                        HandleButtonReleaseEvent (evnt);
 
641
                        
 
642
                        return result;
 
643
                }
 
644
                
 
645
                private void HandleButtonReleaseEvent (Gdk.EventButton evnt)
 
646
                {
 
647
                        // lets not do anything in this case
 
648
                        if (DnDTracker.DragResizing) return;
 
649
                        
 
650
                        if (PainterOverlayVisible) {
 
651
                                Painter.Clicked (GetDockArea (), Cursor);
 
652
                                if (PainterOverlayVisible && !GetDockArea ().Contains (Cursor)) {
 
653
                                        InterruptPainter ();
 
654
                                }
 
655
                        } else {
 
656
                                int item = PositionProvider.IndexAtPosition ((int) evnt.X, (int) evnt.Y); //sometimes clicking is not good!
 
657
                                if (item < 0 || item >= DockItems.Count || !CursorIsOverDockArea || PainterOverlayVisible)
 
658
                                        return;
 
659
                                
 
660
                                //handling right clicks for those icons which request simple right click handling
 
661
                                if (evnt.Button == 3) {
 
662
                                        if (CurrentDockItem is IRightClickable && (CurrentDockItem as IRightClickable).GetMenuItems ().Any ()) {
 
663
                                                PointD itemPosition_;
 
664
                                                double itemZoom;
 
665
                                                IconZoomedPosition (PositionProvider.IndexAtPosition (Cursor), out itemPosition_, out itemZoom);
 
666
 
 
667
                                                Gdk.Point itemPosition = new Gdk.Point ((int) itemPosition_.X, (int) itemPosition_.Y);
 
668
                                                
 
669
                                                itemPosition = itemPosition.RelativeMovePoint ((int) (IconSize * itemZoom * .9 * .5), RelativeMove.Inward);
 
670
                                                itemPosition = itemPosition.RelativePointToRootPoint (window);
 
671
                                                
 
672
                                                PopupMenu.PopUp (CurrentDockItem.Description, 
 
673
                                                                 (CurrentDockItem as IRightClickable).GetMenuItems (), 
 
674
                                                                 itemPosition.X, 
 
675
                                                                 itemPosition.Y);
 
676
                                                return;
 
677
                                        }
 
678
                                }
 
679
                                
 
680
                                //send off the clicks
 
681
                                PointD relative_point = RelativePointOverItem (item);
 
682
                                DockItems [item].Clicked (evnt.Button, evnt.State, relative_point);
 
683
                                
 
684
                                AnimatedDraw ();
 
685
                        }
 
686
                        return;
 
687
                }
 
688
                
 
689
                PointD RelativePointOverItem (int item)
 
690
                {
 
691
                        PointD relative_point = new PointD (0,0);
 
692
                        double zoom;
 
693
                        PointD center;
 
694
                        IconZoomedPosition (item, out center, out zoom);
 
695
                        
 
696
                        int left = (int) (center.X - DockItems [item].Width * zoom / 2);
 
697
                        int top = (int) (center.Y - DockItems [item].Height * zoom / 2);
 
698
                        int right = (int) (center.X + DockItems [item].Width * zoom / 2);
 
699
                        int bottom = (int) (center.Y + DockItems [item].Height * zoom / 2);
 
700
                        
 
701
                        relative_point.X = (Cursor.X - left) / (double) (right - left);
 
702
                        relative_point.Y = (Cursor.Y - top) / (double) (bottom - top);
 
703
                        
 
704
                        return relative_point;
 
705
                }
 
706
 
 
707
                protected override bool OnScrollEvent (Gdk.EventScroll evnt)
 
708
                {
 
709
                        if (PainterOverlayVisible) {
 
710
                                Painter.Scrolled (evnt.Direction);
 
711
                        } else {
 
712
                                int item = PositionProvider.IndexAtPosition ((int) evnt.X, (int) evnt.Y);
 
713
                                if (item >= 0 && item < DockItems.Count)
 
714
                                        DockItems [item].Scrolled (evnt.Direction);
 
715
                        }
 
716
                        return base.OnScrollEvent (evnt);
 
717
                }
 
718
                
 
719
                void SetIconRegions ()
 
720
                {
 
721
                        Gdk.Rectangle pos, area;
 
722
                        window.GetPosition (out pos.X, out pos.Y);
 
723
                        window.GetSize (out pos.Width, out pos.Height);
 
724
                        
 
725
                        // we use geo here instead of our position for the Y value because we know the parent window
 
726
                        // may offset us when hidden. This is not desired...
 
727
                        for (int i = 0; i < DockItems.Count; i++) {
 
728
                                Gdk.Point position = PositionProvider.IconUnzoomedPosition (i);
 
729
                                area = new Gdk.Rectangle (pos.X + (position.X - IconSize / 2),
 
730
                                                          pos.Y + (position.Y - IconSize / 2),
 
731
                                                          IconSize,
 
732
                                                          IconSize);
 
733
                                DockItems [i].SetIconRegion (area);
 
734
                        }
 
735
                }
 
736
                
 
737
                void SetParentInputMask ()
 
738
                {
 
739
                        if (window == null)
 
740
                                return;
 
741
                        
 
742
                        int offset;
 
743
                        if (PainterOverlayVisible) {
 
744
                                offset = 0;
 
745
                        } else if (CursorIsOverDockArea) {
 
746
                                offset = GetDockArea ().Height;
 
747
                                offset = offset * 2 + 10;
 
748
                        } else {
 
749
                                if (IsHidden && !DnDTracker.DragResizing) {
 
750
                                        offset = 1;
 
751
                                } else {
 
752
                                        offset = GetDockArea ().Height;
 
753
                                }
 
754
                        }
 
755
                        
 
756
                        int dockSize = (DnDTracker.DragResizing) ? Width : MinimumDockArea.Width;
 
757
                        
 
758
                        switch (DockPreferences.Orientation) {
 
759
                        case DockOrientation.Bottom:
 
760
                                window.SetInputMask (new Gdk.Rectangle ((Width - dockSize) / 2, 
 
761
                                                                        Height - offset, 
 
762
                                                                        dockSize, 
 
763
                                                                        offset));
 
764
                                break;
 
765
                        case DockOrientation.Top:
 
766
                                window.SetInputMask (new Gdk.Rectangle ((Width - dockSize) / 2, 
 
767
                                                                        0, 
 
768
                                                                        dockSize, 
 
769
                                                                        offset));
 
770
                                break;
 
771
                        }
 
772
                }
 
773
 
 
774
                void InterruptPainter ()
 
775
                {
 
776
                        if (Painter == null || !Painter.Interruptable) return;
 
777
 
 
778
                        Painter.Interrupt ();
 
779
                        Painter = null;
 
780
                        PainterOverlayVisible = false;
 
781
                        interface_change_time = DateTime.UtcNow;
 
782
                        
 
783
                        DnDTracker.Enable ();
 
784
                        window.UnpresentWindow ();
 
785
                        
 
786
                        SetParentInputMask ();
 
787
                        AnimatedDraw ();
 
788
                }
 
789
                
 
790
                public override void Dispose ()
 
791
                {
 
792
                        DockServices.UnregisterService (drawing_service).Dispose ();
 
793
                        
 
794
                        UnregisterEvents ();
 
795
                        DnDTracker.Disable ();
 
796
 
 
797
                        AutohideTracker.Dispose ();
 
798
                        CursorTracker.Dispose ();
 
799
                        DnDTracker.Dispose ();
 
800
                        PositionProvider.Dispose ();
 
801
                        AnimationState.Dispose ();
 
802
                        PopupMenu.Destroy ();
 
803
                        PopupMenu.Dispose ();
 
804
 
 
805
                        PositionProvider = null;
 
806
                        AnimationState = null;
 
807
                        PopupMenu = null;
 
808
 
 
809
                        if (backbuffer != null)
 
810
                                backbuffer.Destroy ();
 
811
 
 
812
                        if (input_area_buffer != null)
 
813
                                input_area_buffer.Destroy ();
 
814
 
 
815
                        if (dock_icon_buffer != null)
 
816
                                dock_icon_buffer.Destroy ();
 
817
                        
 
818
                        if (LastPainter != null) {
 
819
                                LastPainter.PaintNeeded -= HandlePaintNeeded;
 
820
                        }
 
821
                        
 
822
                        if (Painter != null) {
 
823
                                Painter.PaintNeeded -= HandlePaintNeeded;
 
824
                        }
 
825
                        
 
826
                        window = null;
 
827
                        
 
828
                        if (animation_timer > 0)
 
829
                                GLib.Source.Remove (animation_timer);
 
830
 
 
831
                        Destroy ();
 
832
                        base.Dispose ();
 
833
                }
 
834
 
 
835
        }
 
836
}