~ubuntu-branches/ubuntu/trusty/gnome-do/trusty-proposed

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Daniel T Chen
  • Date: 2009-03-13 18:00:35 UTC
  • mfrom: (1.1.6 upstream) (0.1.3 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090313180035-08lo8130dasdg7n8
Tags: 0.8.1.3-0ubuntu1
* New upstream release (LP: #344578).
  + Gnome Do causes keyboard keys to be remapped (LP: #308143)
  + Docky window too small when summoned (LP: #317381)
  + Minimize/Maximize does not work on all windows (LP: #317908)
  + Docky blocks drag and drop over large areas of the screen
    (LP: #318471)
  + Docky fails to autohide properly when changing themes
    (LP: #318672)
  + Paste via ctrl+v does not work in 1st pane (LP: #318922)
  + Autostart is in wrong assembly (LP: #319114)
  + Docky has no results list (LP: #319797)
  + Docky trash applet does not reflect current state
    (LP: #320621)
  + Docky panels splits into two when over filled (LP: #324648)
  + Docky ui division is inconsistent and confusing
    (LP: #324718)
  + poor performance with two screens (LP: #323294)
  + Docky trash applet doesn't check if trash exists
    (LP: #323453)
  + docky panel splits into two when overfilled (LP: #324648)
  + Docky's UI division is inconsistent and confusing
    (LP: #324718)
  + Do crashes when using a pastebin launcher with docky
    (LP: #325178)
  + Make docky aware of icon theme switch (LP: #328721)
  + Docky doesn't update icon status for some apps that minimize
    to system tray. (LP: #329120)
  + Docky does not work properly with pull-down window
    (LP: #334663)
  + sensitivity of zooming the icons in the dock isn't
    configurable (LP: #336214)
  + Regression: In 0.8.1, "Request attention" is no longer
    indicated (LP: #337594)
  + Clock's Calendar mode auto-hides when leaving the bounds of
    the original dock (LP: #337783)
  + gnome-do does not notice change of icon theme (LP: #204368)
  + Thumbnails are never displayed when files have spaces in
    their names (LP: #311551)
  + Open improperly escapes URLs. (LP: #317416)
  + Docky: Right-click dialog appears on wrong monitor
    (LP: #319062)
  + Dragging items off Docky possible in summon mode
    (LP: #319452)
  + Docky shows icon according to the filename (LP: #320892)
  + Mouse click inactive when Do(cky) is summoned (LP: #324937)
  + Docky trash don't have a right-click menu (LP: #317947)
  + Polish docky's window name labels (LP: #318487)
  + Docky: Scroll on window icon should switch between windows
    of that app (LP: #319805)
  + Docky does not preserve window stack (z?) order when
    switching apps by clicking on app icon (LP: #326661)
  + Docky window switching should be easier. (LP: #327079)
  + Color of indicators on Docky cannot be changed
    (LP: #332936)
  + Do's ResultWindow is using wrong text color (LP: #288771)
  + Docky won't unhide after rev 1053 (LP: #337113)
  + Do's icon label in Docky should be "GNOME Do" instead of
    "Summon GNOME Do" (LP: #338496)
* Build against gtk, gnome mono packages from Experimental.
* debian/control:
  + Bump versioned dep on libgtk2.0-cil to ensure
    Gdk.Screen.IsComposited exists
  + Add libwnck2.20-cil build-dep
  + Add librsvg2-2.18-cil build-dep
  + gnome-sharp2 transition.
* debian/patches/03_show_in_all_DEs
  + Drop; fixed in new upstream
* debian/gnome-do.1
  + Update for new version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 
19
19
using System;
20
20
using System.Collections.Generic;
 
21
using System.Collections.ObjectModel;
21
22
using System.Linq;
22
 
using System.Text.RegularExpressions;
23
 
 
24
 
using System.Diagnostics;
25
23
 
26
24
using Cairo;
27
25
using Gdk;
28
26
using Gtk;
29
27
 
30
28
using Do.Platform;
31
 
using Do.Interface;
32
 
using Do.Universe;
33
 
using Do.Interface.CairoUtils;
34
 
using Do;
35
29
 
 
30
using Docky.Core;
36
31
using Docky.Utilities;
37
 
using Docky.Interface.Renderers;
 
32
using Docky.Interface.Menus;
 
33
using Docky.Interface.Painters;
38
34
 
39
35
namespace Docky.Interface
40
36
{
41
37
        
42
38
        
43
 
        public class DockArea : Gtk.DrawingArea
 
39
        internal partial class DockArea : Gtk.DrawingArea
44
40
        {
45
 
                enum DragEdge {
46
 
                        None = 0,
47
 
                        Top,
48
 
                        Left,
49
 
                        Right,
50
 
                }
51
 
 
52
 
                public readonly TimeSpan BaseAnimationTime = new TimeSpan (0, 0, 0, 0, 150);
 
41
                public static readonly TimeSpan BaseAnimationTime = new TimeSpan (0, 0, 0, 0, 150);
53
42
                
54
 
                const int WindowHeight = 300;
55
43
                const uint OffDockWakeupTime = 250;
56
44
                const uint OnDockWakeupTime = 20;
57
45
 
58
46
                TimeSpan BounceTime = new TimeSpan (0, 0, 0, 0, 700);
59
47
                TimeSpan InsertAnimationTime = new TimeSpan (0, 0, 0, 0, 150*5);
60
48
                
61
 
                #region private variables
62
 
                Gdk.Point cursor, drag_start_point;
63
 
                
64
 
                Gdk.CursorType cursor_type = CursorType.LeftPtr;
65
 
                
66
 
                DateTime enter_time = DateTime.UtcNow - new TimeSpan (0, 10, 0);
67
 
                DateTime interface_change_time = DateTime.UtcNow - new TimeSpan (0, 10, 0);
68
 
                
69
 
                bool drag_resizing;
70
 
                bool gtk_drag_source_set;
71
 
                bool previous_icon_animation_needed = true;
 
49
                #region Private Variables
 
50
                Gdk.Point cursor;
 
51
                
 
52
                DateTime enter_time = new DateTime (0);
 
53
                DateTime interface_change_time = new DateTime (0);
 
54
                DateTime last_draw_timeout = new DateTime (0);
 
55
                DateTime cursor_update = new DateTime (0);
 
56
                
72
57
                bool disposed;
73
58
                
74
 
                int drag_start_icon_size;
75
 
                int remove_drag_start_x;
76
 
                int previous_item_count;
77
 
                int previous_x = -1;
78
 
                
79
59
                uint animation_timer;
80
60
                uint cursor_timer;
81
61
                
82
 
                double previous_zoom;
83
 
                
84
 
                DragEdge drag_edge;
85
 
                
86
62
                DockWindow window;
87
 
                DockItemProvider item_provider;
88
 
                Surface backbuffer, input_area_buffer, dock_icon_buffer;
89
63
                
90
 
                Matrix default_matrix;
91
64
                #endregion
92
65
                
93
 
                #region public properties
94
 
                public bool InputInterfaceVisible { get; set; }
 
66
                #region Public Properties
95
67
                
96
68
                /// <value>
97
69
                /// The width of the docks window, but not the visible dock
101
73
                /// <value>
102
74
                /// The height of the docks window
103
75
                /// </value>
104
 
                public int Height { 
105
 
                        get { return WindowHeight; } 
106
 
                }
 
76
                public int Height { get; private set; }
107
77
                
108
78
                /// <value>
109
79
                /// The width of the visible dock
116
86
                /// The height of the visible dock
117
87
                /// </summary>
118
88
                public int DockHeight {
119
 
                        get { return DockPreferences.AutoHide || DockPreferences.AllowOverlap  ? 0 : MinimumDockArea.Height; }
 
89
                        get { return PositionProvider.DockHeight; }
120
90
                }
121
 
                
122
 
                public Pane CurrentPane {
 
91
 
 
92
                public uint[] StrutRequest {
123
93
                        get {
124
 
                                return State.CurrentPane;
125
 
                        }
126
 
                        set {
127
 
                                State.CurrentPane = value;
128
 
                                AnimatedDraw (false);
129
 
                        }
130
 
                }
131
 
                
132
 
                public bool ThirdPaneVisible { 
133
 
                        get { return State.ThirdPaneVisible; }
134
 
                        set { 
135
 
                                if (State.ThirdPaneVisible == value)
136
 
                                        return;
137
 
                                State.ThirdPaneVisible = value;
138
 
                                AnimatedDraw (false);
139
 
                        }
140
 
                }
 
94
                                uint[] values = new uint[12];
 
95
                                Gdk.Rectangle geo = LayoutUtils.MonitorGemonetry ();
 
96
                                
 
97
                                if (DockPreferences.AutoHide || DockPreferences.AllowOverlap)
 
98
                                        return values;
 
99
                                
 
100
                                switch (DockPreferences.Orientation) {
 
101
                                case DockOrientation.Bottom:
 
102
                                        values [(int) XLib.Struts.Bottom] = (uint) (DockHeight + (Screen.Height - (geo.Y + geo.Height)));
 
103
                                        values [(int) XLib.Struts.BottomStart] = (uint) geo.X;
 
104
                                        values [(int) XLib.Struts.BottomEnd] = (uint) (geo.X + geo.Width - 1);
 
105
                                        break;
 
106
                                case DockOrientation.Top:
 
107
                                        values [(int) XLib.Struts.Top] = (uint) (DockHeight + geo.Y);
 
108
                                        values [(int) XLib.Struts.TopStart] = (uint) geo.X;
 
109
                                        values [(int) XLib.Struts.TopEnd] = (uint) (geo.X + geo.Width - 1);
 
110
                                        break;
 
111
                                }
 
112
                                return values;
 
113
                        }
 
114
                }
 
115
 
141
116
                #endregion
142
117
                
143
 
                public new DockState State { get; set; }
144
 
                
145
118
                DockAnimationState AnimationState { get; set; }
146
119
                
147
120
                ItemPositionProvider PositionProvider { get; set; }
148
 
                
 
121
 
149
122
                new DockItemMenu PopupMenu { get; set; }
150
123
                
151
 
                bool GtkDragging { get; set; }
152
 
                
153
 
                bool FullRenderFlag { get; set; }
154
 
                
155
 
                SummonModeRenderer SummonRenderer { get; set; }
156
 
                
157
 
                List<BaseDockItem> DockItems { 
158
 
                        get { return item_provider.DockItems; } 
 
124
                bool CursorIsOverDockArea {     get; set; }
 
125
 
 
126
                ModifierType CursorModifier { get; set; }
 
127
                
 
128
                ReadOnlyCollection<AbstractDockItem> DockItems { 
 
129
                        get { return DockServices.ItemsService.DockItems; } 
159
130
                }
160
131
                
161
 
                BaseDockItem CurrentDockItem {
 
132
                AbstractDockItem CurrentDockItem {
162
133
                        get {
163
 
                                try { return DockItems [PositionProvider.IndexAtPosition (Cursor.X)]; }
 
134
                                try { return DockItems [PositionProvider.IndexAtPosition (Cursor)]; }
164
135
                                catch { return null; }
165
136
                        }
166
137
                }
167
138
                
168
139
                TimeSpan SummonTime {
169
 
                        get {
170
 
                                return DockPreferences.SummonTime;
171
 
                        }
172
 
                }
173
 
                
174
 
                /// <value>
175
 
                /// Returns the zoom in percentage (0 through 1)
176
 
                /// </value>
177
 
                double ZoomIn {
178
 
                        get {
179
 
                                if (drag_resizing && drag_start_point != Cursor)
180
 
                                        return 0;
181
 
                                
182
 
                                double zoom = Math.Min (1, (DateTime.UtcNow - enter_time).TotalMilliseconds / BaseAnimationTime.TotalMilliseconds);
183
 
                                if (CursorIsOverDockArea) {
184
 
                                        if (DockPreferences.AutoHide)
185
 
                                                zoom = 1;
186
 
                                } else {
187
 
                                        zoom = 1 - zoom;
188
 
                                }
189
 
                                
190
 
                                if (InputInterfaceVisible)
191
 
                                        zoom = zoom * DockIconOpacity;
192
 
                                
193
 
                                return zoom;
194
 
                        }
195
 
                }
196
 
                
197
 
                //// <value>
198
 
                /// The overall offset of the dock as a whole
199
 
                /// </value>
200
 
                int VerticalOffset {
201
 
                        get {
202
 
                                double offset = 0;
203
 
                                // we never hide in these conditions
204
 
                                if (!DockPreferences.AutoHide || drag_resizing || InputAreaOpacity == 1)
205
 
                                        return 0;
206
 
 
207
 
                                if (InputAreaOpacity > 0) {
208
 
                                        if (CursorIsOverDockArea) {
209
 
                                                return 0;
210
 
                                        } else {
211
 
                                                offset = Math.Min (1, (DateTime.UtcNow - enter_time).TotalMilliseconds / SummonTime.TotalMilliseconds);
212
 
                                                offset = Math.Min (offset, Math.Min (1, (DateTime.UtcNow - interface_change_time).TotalMilliseconds / SummonTime.TotalMilliseconds));
213
 
                                        }
214
 
                                        
215
 
                                        if (InputInterfaceVisible)
216
 
                                                offset = 1 - offset;
217
 
                                } else {
218
 
                                        offset = Math.Min (1, (DateTime.UtcNow - enter_time).TotalMilliseconds / SummonTime.TotalMilliseconds);
219
 
                                        if (CursorIsOverDockArea)
220
 
                                                offset = 1 - offset;
221
 
                                }
222
 
                                return (int) (offset * MinimumDockArea.Height * 1.5);
223
 
                        }
224
 
                }
225
 
                
226
 
                /// <value>
227
 
                /// Determins the opacity of the icons on the normal dock
228
 
                /// </value>
229
 
                double DockIconOpacity {
230
 
                        get {
231
 
                                if (SummonTime < DateTime.UtcNow - interface_change_time) {
232
 
                                        if (InputInterfaceVisible)
233
 
                                                return 0;
234
 
                                        return 1;
235
 
                                }
236
 
 
237
 
                                double total_time = (DateTime.UtcNow - interface_change_time).TotalMilliseconds;
238
 
                                if (InputInterfaceVisible) {
239
 
                                        return 1 - (total_time / SummonTime.TotalMilliseconds);
240
 
                                } else {
241
 
                                        return total_time / SummonTime.TotalMilliseconds;
242
 
                                }
243
 
                        }
244
 
                }
245
 
                
246
 
                double InputAreaOpacity {
247
 
                        get { return 1 - DockIconOpacity; }
248
 
                }
249
 
                
250
 
                int IconSize { 
251
 
                        get { return DockPreferences.IconSize; } 
 
140
                        get { return DockPreferences.SummonTime; }
252
141
                }
253
142
                
254
143
                /// <value>
261
150
                        set {
262
151
                                bool cursorIsOverDockArea = CursorIsOverDockArea;
263
152
                                cursor = value;
264
 
                                
 
153
 
265
154
                                // We set this value here instead of dynamically checking due to performance constraints.
266
155
                                // Ideally our CursorIsOverDockArea getter would do this fairly simple calculation, but it gets
267
156
                                // called about 20 to 30 times per render loop, so the savings do add up.
 
157
                                Gdk.Rectangle dockRegion;
 
158
                                if (PainterOverlayVisible)
 
159
                                        dockRegion = GetDockArea ();
 
160
                                else
 
161
                                        dockRegion = MinimumDockArea;
 
162
                                
268
163
                                if (cursorIsOverDockArea) {
269
 
                                        Gdk.Rectangle rect = MinimumDockArea;
270
 
                                        rect.Inflate (0, (int) (IconSize * (DockPreferences.ZoomPercent - 1)) + 22);
271
 
                                        CursorIsOverDockArea = rect.Contains (cursor);
 
164
                                        dockRegion.Inflate (0, (int) (IconSize * (DockPreferences.ZoomPercent - 1)) + 22);
 
165
                                        CursorIsOverDockArea = dockRegion.Contains (cursor);
272
166
                                } else {
273
 
                                        Gdk.Rectangle small = MinimumDockArea;
274
167
                                        if (DockPreferences.AutoHide) {
275
 
                                                small.Y += small.Height - 1;
276
 
                                                small.Height = 1;
 
168
                                                switch (DockPreferences.Orientation) {
 
169
                                                case DockOrientation.Bottom:
 
170
                                                        dockRegion.Y += dockRegion.Height - 1;
 
171
                                                        dockRegion.Height = 1;
 
172
                                                        break;
 
173
                                                case DockOrientation.Top:
 
174
                                                        dockRegion.Height = 1;
 
175
                                                        break;
 
176
                                                }
277
177
                                        }
278
 
                                        CursorIsOverDockArea = small.Contains (cursor);
 
178
                                        CursorIsOverDockArea = dockRegion.Contains (cursor);
279
179
                                }
280
180
                                
281
181
                                // When we change over this boundry, it will normally trigger an animation, we need to be sure to catch it
282
182
                                if (CursorIsOverDockArea != cursorIsOverDockArea) {
283
183
                                        ResetCursorTimer ();
284
184
                                        enter_time = DateTime.UtcNow;
285
 
                                        AnimatedDraw (false);
 
185
                                        AnimatedDraw ();
286
186
                                }
 
187
 
 
188
                                DragCursorUpdate ();
287
189
                        }
288
190
                }
289
191
                
293
195
                        }
294
196
                }
295
197
                
296
 
                bool CursorNearTopDraggableEdge {
297
 
                        get {
298
 
                                return Cursor.Y > MinimumDockArea.Y && CursorIsOverDockArea && CurrentDockItem is SeparatorItem;
299
 
                        }
300
 
                }
301
 
                
302
 
                bool CursorNearLeftEdge {
303
 
                        get {
304
 
                                return CursorIsOverDockArea && Math.Abs (Cursor.X - MinimumDockArea.X) < 8;
305
 
                        }
306
 
                }
307
 
                
308
 
                bool CursorNearRightEdge {
309
 
                        get {
310
 
                                return CursorIsOverDockArea && Math.Abs (Cursor.X - (MinimumDockArea.X + MinimumDockArea.Width)) < 8;
311
 
                        }
312
 
                }
313
 
                
314
 
                bool CursorNearDraggableEdge {
315
 
                        get {
316
 
                                return CursorNearTopDraggableEdge || 
317
 
                                           CursorNearRightEdge || 
318
 
                                           CursorNearLeftEdge;
319
 
                        }
320
 
                }
321
 
                
322
 
                DragEdge CurrentDragEdge {
323
 
                        get {
324
 
                                if (CursorNearTopDraggableEdge)
325
 
                                        return DragEdge.Top;
326
 
                                else if (CursorNearLeftEdge)
327
 
                                        return DragEdge.Left;
328
 
                                else if (CursorNearRightEdge)
329
 
                                        return DragEdge.Right;
330
 
                                return DragEdge.None;
331
 
                        }
332
 
                }
333
 
                
334
 
                #region Animation properties
335
 
                bool CursorIsOverDockArea {     get; set; }
336
 
                
337
 
                bool IconAnimationNeeded {
338
 
                        get {
339
 
                                return AnimationState ["BounceAnimationNeeded"] ||
340
 
                                           AnimationState ["IconInsertAnimationNeeded"] ||
341
 
                                           AnimationState ["UrgentAnimationNeeded"];
342
 
                        }
343
 
                }
344
 
                
345
 
                bool CanFastRender {
346
 
                        get {
347
 
                                // Some conditions are not good for doing partial draws.
348
 
                                // we have a couple conditions were this render peformance boost will result in "badness".
349
 
                                // in these cases we need to do a full render.
350
 
                                return ZoomIn == 1 && 
351
 
                                        previous_zoom == 1 && 
352
 
                                        previous_item_count == DockItems.Count && 
353
 
                                        !IconAnimationNeeded &&
354
 
                                        !previous_icon_animation_needed &&
355
 
                                        !drag_resizing &&
356
 
                                        !FullRenderFlag;
357
 
                        }
358
 
                }
359
 
                #endregion
360
 
                
361
198
                public DockArea (DockWindow window) : base ()
362
199
                {
363
 
                        default_matrix = new Matrix ();
364
200
                        this.window = window;
365
201
                        
366
 
                        Gdk.Rectangle geo;
367
 
                        geo = LayoutUtils.MonitorGemonetry ();
368
 
                        
369
 
                        Width = geo.Width;
370
 
                        SetSizeRequest (Width, Height);
371
 
                        
372
 
                        item_provider = new DockItemProvider ();
373
 
                        State = new DockState ();
374
 
                        PositionProvider = new ItemPositionProvider (item_provider, new Gdk.Rectangle (0, 0, Width, Height));
 
202
                        SetSize ();
 
203
                        
 
204
                        PositionProvider = new ItemPositionProvider (this);
375
205
                        
376
206
                        AnimationState = new DockAnimationState ();
377
207
                        BuildAnimationStateEngine ();
378
208
                        
379
 
                        SummonRenderer = new SummonModeRenderer (this);
380
209
                        PopupMenu = new DockItemMenu ();
381
 
                        
 
210
 
382
211
                        Cursor = new Gdk.Point (-1, -1);
383
 
                        
 
212
 
384
213
                        this.SetCompositeColormap ();
385
 
                        
386
 
                        AddEvents ((int) EventMask.PointerMotionMask | 
 
214
 
 
215
                        // fixme, we should be using the PointerMotionHintMask
 
216
                        AddEvents ((int) EventMask.PointerMotionMask |
387
217
                                   (int) EventMask.EnterNotifyMask |
388
218
                                   (int) EventMask.ButtonPressMask | 
389
219
                                   (int) EventMask.ButtonReleaseMask |
 
220
                                   (int) EventMask.ScrollMask |
390
221
                                   (int) EventMask.FocusChangeMask);
391
222
                        
392
223
                        DoubleBuffered = false;
 
224
 
 
225
                        BuildRendering ();
 
226
                        BuildDragAndDrop ();
393
227
                        
394
228
                        RegisterEvents ();
395
229
                        RegisterGtkDragDest ();
397
231
                        
398
232
                        ResetCursorTimer ();
399
233
                }
 
234
                
 
235
                void SetSize ()
 
236
                {
 
237
                        Gdk.Rectangle geo;
 
238
                        geo = LayoutUtils.MonitorGemonetry ();
 
239
                        
 
240
                        Width = geo.Width;
 
241
                        Height = 300;
 
242
                        
 
243
                        SetSizeRequest (Width, Height);
 
244
                }
400
245
 
401
246
                void RegisterEvents ()
402
247
                {
403
 
                        item_provider.DockItemsChanged += OnDockItemsChanged;
404
 
                        item_provider.ItemNeedsUpdate += HandleItemNeedsUpdate;
 
248
                        DockServices.ItemsService.DockItemsChanged += OnDockItemsChanged;
 
249
                        DockServices.ItemsService.ItemNeedsUpdate += HandleItemNeedsUpdate;
 
250
                        
 
251
                        DockPreferences.MonitorChanged += HandleMonitorChanged; 
 
252
                        DockPreferences.IconSizeChanged += HandleIconSizeChanged; 
 
253
                        
 
254
                        DockServices.PainterService.PainterShowRequest += HandlePainterShowRequest;
 
255
                        DockServices.PainterService.PainterHideRequest += HandlePainterHideRequest;
 
256
 
 
257
                        Screen.SizeChanged += HandleSizeChanged; 
405
258
                        
406
259
                        PopupMenu.Hidden += OnDockItemMenuHidden;
407
260
                        PopupMenu.Shown += OnDockItemMenuShown;
408
261
 
409
262
                        Services.Core.UniverseInitialized += HandleUniverseInitialized;
410
263
                        
411
 
                        Wnck.Screen.Default.ViewportsChanged += OnWnckViewportsChanged;
412
 
 
413
264
                        Realized += (o, e) => SetParentInputMask ();
414
265
                        Realized += (o, a) => GdkWindow.SetBackPixmap (null, false);
415
266
                        
421
272
 
422
273
                void UnregisterEvents ()
423
274
                {
424
 
                        item_provider.DockItemsChanged -= OnDockItemsChanged;
425
 
                        item_provider.ItemNeedsUpdate -= HandleItemNeedsUpdate;
 
275
                        DockServices.ItemsService.DockItemsChanged -= OnDockItemsChanged;
 
276
                        DockServices.ItemsService.ItemNeedsUpdate -= HandleItemNeedsUpdate;
 
277
                        
 
278
                        DockPreferences.MonitorChanged -= HandleMonitorChanged;
 
279
                        DockPreferences.IconSizeChanged -= HandleIconSizeChanged; 
 
280
                        
 
281
                        DockServices.PainterService.PainterShowRequest -= HandlePainterShowRequest;
 
282
                        DockServices.PainterService.PainterHideRequest -= HandlePainterHideRequest;
 
283
 
 
284
                        Screen.SizeChanged -= HandleSizeChanged;
426
285
                        
427
286
                        PopupMenu.Hidden -= OnDockItemMenuHidden;
428
287
                        PopupMenu.Shown -= OnDockItemMenuShown;
429
 
 
 
288
                        
430
289
                        Services.Core.UniverseInitialized -= HandleUniverseInitialized;
431
 
                        
432
 
                        Wnck.Screen.Default.ViewportsChanged -= OnWnckViewportsChanged;
433
290
                }
434
291
                
435
292
                void BuildAnimationStateEngine ()
436
293
                {
437
 
                        AnimationState.AddCondition ("IconInsertAnimationNeeded", 
 
294
                        AnimationState.AddCondition (Animations.IconInsert, 
438
295
                                                     () => DockItems.Any (di => di.TimeSinceAdd < InsertAnimationTime));
439
296
                        
440
 
                        AnimationState.AddCondition ("PaneChangeAnimationNeeded",
441
 
                                                     () => (DateTime.UtcNow - State.CurrentPaneTime) < BaseAnimationTime);
442
 
                
443
 
                        AnimationState.AddCondition ("ZoomAnimationNeeded",
 
297
                        AnimationState.AddCondition (Animations.Zoom,
444
298
                                                     () => (CursorIsOverDockArea && ZoomIn != 1) || (!CursorIsOverDockArea && ZoomIn != 0));
445
299
                        
446
 
                        AnimationState.AddCondition ("OpenAnimationNeeded",
 
300
                        AnimationState.AddCondition (Animations.Open,
447
301
                                                     () => DateTime.UtcNow - enter_time < SummonTime ||
448
302
                                                     DateTime.UtcNow - interface_change_time < SummonTime);
449
303
                        
450
 
                        AnimationState.AddCondition ("BounceAnimationNeeded",
 
304
                        AnimationState.AddCondition (Animations.Bounce,
451
305
                                                     () => DockItems.Any (di => di.TimeSinceClick <= BounceTime));
452
306
                        
453
 
                        AnimationState.AddCondition ("UrgentAnimationNeeded",
454
 
                                                     () => DockItems.Where (di => di is IDockAppItem)
455
 
                                                     .Cast<IDockAppItem> ()
456
 
                                                     .Where (dai => dai.NeedsAttention)
457
 
                                                     .Any (dai => DateTime.UtcNow - dai.AttentionRequestStartTime < BounceTime));
458
 
                        
459
 
                        AnimationState.AddCondition ("UrgentRecentChange",
460
 
                                                     () => DockItems.Where (di => di is IDockAppItem)
461
 
                                                     .Cast<IDockAppItem> ()
462
 
                                                     .Any (dai => DateTime.UtcNow - dai.AttentionRequestStartTime < BounceTime));
463
 
                        
464
 
                        AnimationState.AddCondition ("InputModeChangeAnimationNeeded",
 
307
                        AnimationState.AddCondition (Animations.UrgencyChanged,
 
308
                                                     () => DockItems.Any (di => DateTime.UtcNow - di.AttentionRequestStartTime < BounceTime));
 
309
                        
 
310
                        AnimationState.AddCondition (Animations.InputModeChanged,
465
311
                                                     () => DateTime.UtcNow - interface_change_time < SummonTime);
466
 
                        
467
 
                        AnimationState.AddCondition ("InputModeSlideAnimationNeeded",
468
 
                                                     () => DateTime.UtcNow - State.LastCursorChange < BaseAnimationTime);
469
 
                        
470
 
                        AnimationState.AddCondition ("ThirdPaneVisibilityAnimationNeeded",
471
 
                                                     () => DateTime.UtcNow - State.ThirdChangeTime < BaseAnimationTime);
472
312
                }
473
313
 
474
314
                void HandleItemNeedsUpdate (object sender, UpdateRequestArgs args)
476
316
                        if (args.Type == UpdateRequestType.NeedsAttentionSet) {
477
317
                                SetParentInputMask ();
478
318
                        }
479
 
                        AnimatedDraw (true);
 
319
                        AnimatedDraw ();
480
320
                }
481
321
 
 
322
                void HandleMonitorChanged()
 
323
                {
 
324
                        Reconfigure ();
 
325
                }
 
326
                
 
327
                void HandleSizeChanged(object sender, EventArgs e)
 
328
                {
 
329
                        Reconfigure ();
 
330
                }
 
331
                
 
332
                void Reconfigure ()
 
333
                {
 
334
                        SetSize ();
 
335
                        ResetBuffers ();
 
336
                        PositionProvider.ForceUpdate ();
 
337
                        SetParentInputMask ();
 
338
                        SetIconRegions ();
 
339
                        window.DelaySetStruts ();
 
340
                }
 
341
                
482
342
                void HandleUniverseInitialized(object sender, EventArgs e)
483
343
                {
484
344
                        GLib.Timeout.Add (2000, delegate {
 
345
                                DockServices.ItemsService.ForceUpdate ();
485
346
                                SetIconRegions ();
486
347
                                return false;
487
348
                        });
488
349
                }
489
350
                
490
 
                void RegisterGtkDragSource ()
491
 
                {
492
 
                        gtk_drag_source_set = true;
493
 
                        TargetEntry te = new TargetEntry ("text/uri-list", TargetFlags.OtherApp, 0);
494
 
                        Gtk.Drag.SourceSet (this, Gdk.ModifierType.Button1Mask, new [] {te}, DragAction.Copy);
495
 
                }
496
 
                
497
 
                void RegisterGtkDragDest ()
498
 
                {
499
 
                        TargetEntry dest_te = new TargetEntry ("text/uri-list", 0, 0);
500
 
                        Gtk.Drag.DestSet (this, DestDefaults.Motion | DestDefaults.Drop, new [] {dest_te}, Gdk.DragAction.Copy);
501
 
                }
502
 
                
503
 
                void UnregisterGtkDragSource ()
504
 
                {
505
 
                        gtk_drag_source_set = false;
506
 
                        Gtk.Drag.SourceUnset (this);
 
351
                void HandleIconSizeChanged()
 
352
                {
 
353
                        AnimatedDraw ();
 
354
                }
 
355
 
 
356
                void HandlePaintNeeded (object sender, PaintNeededArgs args)
 
357
                {
 
358
                        if (sender != Painter && sender != LastPainter) return;
 
359
                        
 
360
                        if (args.Animated) {
 
361
                                if (AnimationState.Contains (Animations.Painter))
 
362
                                        AnimationState.RemoveCondition (Animations.Painter);
 
363
                                TimeSpan span = args.AnimationLength;
 
364
                                
 
365
                                DateTime current_time = DateTime.UtcNow;
 
366
                                AnimationState.AddCondition (Animations.Painter, () => DateTime.UtcNow - current_time < span);
 
367
                        }
 
368
                        AnimatedDraw ();
 
369
                }
 
370
                
 
371
                void HandlePainterHideRequest(object sender, EventArgs e)
 
372
                {
 
373
                        IDockPainter painter = sender as IDockPainter;
 
374
                        if (Painter != painter)
 
375
                                return;
 
376
 
 
377
                        Painter = null;
 
378
                        PainterOverlayVisible = false;
 
379
                        interface_change_time = DateTime.UtcNow;
 
380
 
 
381
                        SetParentInputMask ();
 
382
                        AnimatedDraw ();
 
383
 
 
384
                        GLib.Timeout.Add (500, () => { 
 
385
                                DockServices.ItemsService.ForceUpdate (); 
 
386
                                return false; 
 
387
                        });
 
388
 
 
389
                        window.UnpresentWindow ();
 
390
                        RegisterGtkDragSource ();
 
391
                }
 
392
 
 
393
                void HandlePainterShowRequest(object sender, EventArgs e)
 
394
                {
 
395
                        IDockPainter painter = sender as IDockPainter;
 
396
                        if (Painter == painter)
 
397
                                return;
 
398
                        
 
399
                        if (Painter == null || Painter.Interruptable) {
 
400
                                if (Painter != null)
 
401
                                        Painter.Interrupt ();
 
402
                                Painter = painter;
 
403
                                PainterOverlayVisible = true;
 
404
                                interface_change_time = DateTime.UtcNow;
 
405
 
 
406
                                SetParentInputMask ();
 
407
                                AnimatedDraw ();
 
408
                        } else {
 
409
                                painter.Interrupt ();
 
410
                        }
 
411
                        
 
412
                        window.PresentWindow ();
 
413
                        UnregisterGtkDragSource ();
507
414
                }
508
415
                
509
416
                void ResetCursorTimer ()
520
427
                bool OnCursorTimerEllapsed ()
521
428
                {
522
429
                        ManualCursorUpdate ();
 
430
                        
 
431
                        // if we have a painter visible this takes care of interrupting it on mouse off
 
432
                        if (!CursorIsOverDockArea && PainterOverlayVisible && (DateTime.UtcNow - enter_time).TotalMilliseconds > 400)
 
433
                                InterruptPainter ();
 
434
                        
523
435
                        return true;
524
436
                }
525
437
                
526
 
                void AnimatedDraw (bool fullRenderRequired)
 
438
                void AnimatedDraw ()
527
439
                {
528
 
                        if (fullRenderRequired)
529
 
                                FullRenderFlag = true;
530
 
                        
531
 
                        if (0 < animation_timer)
532
 
                                return;
 
440
                        if (0 < animation_timer) {
 
441
                                if ((DateTime.UtcNow - last_draw_timeout).TotalMilliseconds > 500) {
 
442
                                        // honestly this should never happen.  I am not sure if it does but we are going
 
443
                                        // to protect against it because there are reports of rendering failing. A condition
 
444
                                        // where the animation_timer is > 0 without an actual callback tied to it would
 
445
                                        // forever block future animations.
 
446
                                        GLib.Source.Remove (animation_timer);
 
447
                                        animation_timer = 0;
 
448
                                } else {
 
449
                                        return;
 
450
                                }
 
451
                        }
533
452
                        
534
453
                        // the presense of this queue draw has caused some confusion, so I will explain.
535
454
                        // first its here to draw the "first frame".  Without it, we have a 16ms delay till that happens,
536
 
                        // however minor that is.  We do everything after 16ms (about 60fps) so we will keep this up.
537
 
                        QueueDraw ();
 
455
                        // however minor that is.
 
456
                        MaskAndDraw ();
 
457
                        
538
458
                        if (AnimationState.AnimationNeeded)
539
 
                                animation_timer = GLib.Timeout.Add (1000/50, OnDrawTimeoutElapsed);
 
459
                                animation_timer = GLib.Timeout.Add (1000/60, OnDrawTimeoutElapsed);
540
460
                }
541
461
                
542
462
                bool OnDrawTimeoutElapsed ()
543
463
                {
544
 
                        QueueDraw ();
545
 
                        // this is a "protected method".  We need to be sure that our input mask is okay on every frame.
546
 
                        // 99% of the time this means nothing at all will be done
547
 
                        SetParentInputMask ();
 
464
                        last_draw_timeout = DateTime.UtcNow;
 
465
                        
 
466
                        MaskAndDraw ();
548
467
                        
549
468
                        if (AnimationState.AnimationNeeded)
550
469
                                return true;
555
474
                        return false;
556
475
                }
557
476
                
558
 
                void DrawDrock (Context cr)
559
 
                {
560
 
                        // We need to initilize this the first time we use it. However we cant initialize it until our
561
 
                        // very first draw starts, and after that it must maintain state, so we signal this with -1;
562
 
                        if (previous_x == -1)
563
 
                                previous_x = Cursor.X;
564
 
                        
565
 
                        Gdk.Rectangle dockArea = GetDockArea ();
566
 
                        DockBackgroundRenderer.RenderDockBackground (cr, dockArea);
567
 
                        
568
 
                        if (InputAreaOpacity > 0) {
569
 
                                if (input_area_buffer == null)
570
 
                                        input_area_buffer = cr.Target.CreateSimilar (cr.Target.Content, Width, Height);
571
 
                                
572
 
                                using (Context input_cr = new Context (input_area_buffer)) {
573
 
                                        input_cr.AlphaFill ();
574
 
                                        SummonRenderer.RenderSummonMode (input_cr, dockArea);
575
 
                                }
576
 
                                
577
 
                                cr.SetSource (input_area_buffer);
578
 
                                cr.PaintWithAlpha (InputAreaOpacity);
579
 
                        }
580
 
                        
581
 
                        bool isNotSummonTransition = InputAreaOpacity == 0 || CursorIsOverDockArea || !DockPreferences.AutoHide;
582
 
                        if (DockIconOpacity > 0 && isNotSummonTransition) {
583
 
                                if (dock_icon_buffer == null)
584
 
                                        dock_icon_buffer = cr.Target.CreateSimilar (cr.Target.Content, Width, Height);
585
 
                                
586
 
                                using (Context input_cr = new Context (dock_icon_buffer)) {
587
 
                                        DrawIcons (input_cr);
588
 
                                }
589
 
                                
590
 
                                cr.SetSource (dock_icon_buffer, 0, IconSize * (1 - DockIconOpacity));
591
 
                                cr.PaintWithAlpha (DockIconOpacity);
592
 
                        }
593
 
                }
594
 
                
595
 
                void DrawIcons (Context cr)
596
 
                {
597
 
                        if (CanFastRender) {
598
 
                                StoreFastRenderData ();
599
 
                                do {
600
 
                                        // If the cursor has not moved and the PopupMenu is not visible (this causes a 
601
 
                                        // render change without moving the cursor) we can do no rendering at all and just 
602
 
                                        // take our previous frame as our current result.
603
 
                                        if (previous_x == Cursor.X && !PopupMenu.Visible && !AnimationState ["UrgentRecentChange"])
604
 
                                                break;
605
 
                                        
606
 
                                        // we need to know the left and right items for the parabolic zoom.  These items 
607
 
                                        // represent the only icons that are actually undergoing change.  By noting what 
608
 
                                        // these icons are, we can only draw these icons and those between them.
609
 
                                        int leftItem = Math.Max (0, PositionProvider.IndexAtPosition (Math.Min (Cursor.X, previous_x) - DockPreferences.ZoomSize / 2));
610
 
                                        int rightItem = PositionProvider.IndexAtPosition (Math.Max (Cursor.X, previous_x) + DockPreferences.ZoomSize / 2);
611
 
                                        if (rightItem == -1) 
612
 
                                                rightItem = DockItems.Count - 1;
613
 
                                        
614
 
                                        int leftX, rightX;
615
 
                                        double leftZoom, rightZoom;
616
 
                                        
617
 
                                        // calculates the actual x postions of the borders of the left and right most changing icons
618
 
                                        if (leftItem == 0) {
619
 
                                                leftX = 0;
620
 
                                        } else {
621
 
                                                IconZoomedPosition (leftItem, out leftX, out leftZoom);
622
 
                                                leftX -= (int) (leftZoom * DockItems [leftItem].Width / 2) + DockPreferences.IconBorderWidth;
623
 
                                        }
624
 
                                        
625
 
                                        if (rightItem == DockItems.Count - 1) {
626
 
                                                rightX = Width;
627
 
                                        } else {
628
 
                                                IconZoomedPosition (rightItem, out rightX, out rightZoom);
629
 
                                                rightX += (int) (rightZoom * DockItems [rightItem].Width / 2) + DockPreferences.IconBorderWidth;
630
 
                                        }
631
 
                                        
632
 
                                        // only clear that area for which we are going to redraw.  If we land this in the middle of an icon
633
 
                                        // things are going to look ugly, so this calculation MUST be correct.
634
 
                                        cr.Rectangle (leftX, 0, rightX - leftX, Height);
635
 
                                        cr.Rectangle (0, 0, Width, Height - (MinimumDockArea.Height + 2));
636
 
                                        cr.Color = new Cairo.Color (1, 1, 1, 0);
637
 
                                        cr.Operator = Operator.Source;
638
 
                                        cr.Fill ();
639
 
                                        cr.Operator = Operator.Over;
640
 
                                        
641
 
                                        for (int i = leftItem; i <= rightItem; i++)
642
 
                                                DrawIcon (cr, i);
643
 
                                } while (false);
644
 
                        } else {
645
 
                                FullRenderFlag = false;
646
 
                                // less code, twice as slow...
647
 
                                cr.AlphaFill ();
648
 
                                for (int i = 0; i < DockItems.Count; i++)
649
 
                                        DrawIcon (cr, i);
650
 
                        }
651
 
                }
652
 
                
653
 
                void StoreFastRenderData ()
654
 
                {
655
 
                        // To enable this render optimization, we have to keep track of several state items that otherwise
656
 
                        // are unimportant.  This is an unfortunate reality we must live with.
657
 
                        previous_zoom = ZoomIn;
658
 
                        previous_item_count = DockItems.Count;
659
 
                        previous_x = Cursor.X;
660
 
                        previous_icon_animation_needed = IconAnimationNeeded;
661
 
                }
662
 
                
663
 
                void DrawIcon (Context cr, int icon)
664
 
                {
665
 
                        // Don't draw the icon we are dragging around
666
 
                        if (GtkDragging) {
667
 
                                int item = PositionProvider.IndexAtPosition (remove_drag_start_x);
668
 
                                if (item == icon && item_provider.ItemCanBeMoved (item))
669
 
                                        return;
670
 
                        }
671
 
                        
672
 
                        int center;
673
 
                        double zoom;
674
 
                        IconZoomedPosition (icon, out center, out zoom);
675
 
                        
676
 
                        // This gives the actual x,y coordinates of the icon 
677
 
                        double x = center - zoom * DockItems [icon].Width / 2;
678
 
                        double y = Height - (zoom * DockItems [icon].Height) - PositionProvider.VerticalBuffer;
679
 
                        
680
 
                        ClickAnimationType animationType = IconAnimation (icon);
681
 
                        
682
 
                        // we will set this flag now
683
 
                        bool drawUrgency = false;
684
 
                        if (animationType == ClickAnimationType.Bounce) {
685
 
                                // bounces twice
686
 
                                y -= Math.Abs (30 * Math.Sin (DockItems [icon].TimeSinceClick.TotalMilliseconds * Math.PI / (BounceTime.TotalMilliseconds / 2)));
687
 
                        } else {
688
 
                                IDockAppItem dai = DockItems [icon] as IDockAppItem;
689
 
                                if (dai != null && dai.NeedsAttention) {
690
 
                                        drawUrgency = true;
691
 
                                        if (DateTime.UtcNow - dai.AttentionRequestStartTime < BounceTime) {
692
 
                                                double urgentMs = (DateTime.UtcNow - dai.AttentionRequestStartTime).TotalMilliseconds;
693
 
                                                y -= 100 * Math.Sin (urgentMs * Math.PI / (BounceTime.TotalMilliseconds));
694
 
                                        }
695
 
                                }
696
 
                        }
697
 
                        
698
 
                        double scale = zoom/DockPreferences.IconQuality;
699
 
                        
700
 
                        if (DockItems [icon].Scalable) {
701
 
                                if (scale != 1)
702
 
                                        cr.Scale (scale, scale);
703
 
                                // we need to multiply x and y by 1 / scale to undo the scaling of the context.  We only want to zoom
704
 
                                // the icon, not move it around.
705
 
                                
706
 
                                double fadeInOpacity = Math.Min (DockItems [icon].TimeSinceAdd.TotalMilliseconds / InsertAnimationTime.TotalMilliseconds, 1);
707
 
                                cr.SetSource (DockItems [icon].GetIconSurface (cr.Target), x/scale, y/scale);
708
 
                                cr.PaintWithAlpha (fadeInOpacity);
709
 
                                
710
 
                                bool shade_light = GtkDragging && DockItems [icon].IsAcceptingDrops && icon == PositionProvider.IndexAtPosition (Cursor.X);
711
 
                                bool shade_dark = animationType == ClickAnimationType.Darken;
712
 
                                if (shade_dark || shade_light) {
713
 
                                        cr.Rectangle (x / scale, y / scale, DockPreferences.FullIconSize, DockPreferences.FullIconSize);
714
 
                                        
715
 
                                        if (shade_light) {
716
 
                                                cr.Color = new Cairo.Color (.9, .95, 1, .5);
717
 
                                        } else {
718
 
                                                double opacity = (BounceTime - DockItems [icon].TimeSinceClick).TotalMilliseconds / BounceTime.TotalMilliseconds - .7;
719
 
                                                cr.Color = new Cairo.Color (0, 0, 0, opacity);
720
 
                                        }
721
 
                                                
722
 
                                        cr.Operator = Operator.Atop;
723
 
                                        cr.Fill ();
724
 
                                        cr.Operator = Operator.Over;
725
 
                                }
726
 
                                
727
 
                                if (scale != 1)
728
 
                                        cr.Matrix = default_matrix;
729
 
                        } else {
730
 
                                // since these dont scale, we have some extra work to do to keep them
731
 
                                // centered
732
 
                                double startx = x + (zoom * DockItems [icon].Width - DockItems [icon].Width) / 2;
733
 
                                cr.SetSource (DockItems [icon].GetIconSurface (cr.Target), (int) startx, 
734
 
                                              Height - DockItems [icon].Height - (MinimumDockArea.Height - DockItems [icon].Height) / 2);
735
 
                                cr.Paint ();
736
 
                        }
737
 
                        
738
 
                        if (0 < DockItems [icon].WindowCount) {
739
 
                                // draws a simple triangle indicator.  Should be replaced by something
740
 
                                // nicer some day
741
 
                                Util.DrawGlowIndicator (cr, center, Height - 1, drawUrgency, DockItems [icon].WindowCount);
742
 
                        }
743
 
                        
744
 
                        // we do a null check here to allow things like separator items to supply
745
 
                        // a null.  This allows us to draw nothing at all instead of rendering a
746
 
                        // blank surface (which is slow)
747
 
                        if (!PopupMenu.Visible && PositionProvider.IndexAtPosition (Cursor.X) == icon && 
748
 
                            CursorIsOverDockArea && DockItems [icon].GetTextSurface (cr.Target) != null) {
749
 
                                
750
 
                                int textx = PositionProvider.IconUnzoomedPosition (icon) - (DockPreferences.TextWidth / 2);
751
 
                                int texty = Height - (int) (DockPreferences.ZoomPercent * IconSize) - 32;
752
 
                                DockItems [icon].GetTextSurface (cr.Target).Show (cr, textx, texty);
753
 
                        }
754
 
                }
755
 
                
756
 
                ClickAnimationType IconAnimation (int icon)
757
 
                {
758
 
                        return (DockItems [icon].TimeSinceClick < BounceTime) ? DockItems [icon].AnimationType : ClickAnimationType.None;
759
 
                }
760
 
                
761
 
                void IconZoomedPosition (int icon, out int x, out double zoom)
762
 
                {
763
 
                        PositionProvider.IconZoomedPosition (icon, ZoomIn, Cursor, out x, out zoom);
764
 
                }
765
 
                
766
 
                Gdk.Rectangle GetDockArea ()
767
 
                {
768
 
                        // this method is more than somewhat slow on the complexity scale, we want to avoid doing it
769
 
                        // more than we have to.  Further, when we do call it, we should always check for this shortcut.
770
 
                        if (DockIconOpacity == 0 || ZoomIn == 0)
771
 
                                return MinimumDockArea;
772
 
 
773
 
                        return PositionProvider.DockArea (ZoomIn, Cursor);
774
 
                }
775
 
                
776
 
                void OnDockItemsChanged (IEnumerable<BaseDockItem> items)
 
477
                void MaskAndDraw ()
 
478
                {
 
479
                        QueueDraw ();
 
480
                        // this is a "protected method".  We need to be sure that our input mask is okay on every frame.
 
481
                        // 99% of the time this means nothing at all will be done
 
482
                        SetParentInputMask ();
 
483
                }
 
484
                
 
485
                void OnDockItemsChanged (IEnumerable<AbstractDockItem> items)
777
486
                {
778
487
                        DockPreferences.MaxIconSize = (int) (((double) Width / MinimumDockArea.Width) * IconSize);
779
488
                        
780
489
                        SetIconRegions ();
781
 
                        AnimatedDraw (true);
 
490
                        AnimatedDraw ();
782
491
                }
783
492
                
784
493
                void OnDockItemMenuHidden (object o, System.EventArgs args)
787
496
                        // both a good thing and a bad thing.  We must at the very least update the cursor position once the
788
497
                        // popup is no longer in view.
789
498
                        ManualCursorUpdate ();
790
 
                        AnimatedDraw (false);
791
 
                }
792
 
                
793
 
                void OnWnckViewportsChanged (object o, EventArgs e)
794
 
                {
795
 
                        ManualCursorUpdate ();
796
 
                        AnimatedDraw (false);
 
499
                        AnimatedDraw ();
797
500
                }
798
501
                
799
502
                /// <summary>
801
504
                /// </summary>
802
505
                void OnDockItemMenuShown (object o, EventArgs args)
803
506
                {
804
 
                        AnimatedDraw (false);
 
507
                        AnimatedDraw ();
805
508
                }
806
509
                
807
 
                public void ManualCursorUpdate ()
 
510
                void ManualCursorUpdate ()
808
511
                {
 
512
                        if ((DateTime.UtcNow - cursor_update).TotalMilliseconds < 15) {
 
513
                                return;
 
514
                        }
 
515
                        
809
516
                        int x, y;
810
 
                        
811
 
                        Display.GetPointer (out x, out y);
 
517
                        ModifierType mod;
 
518
                        Gdk.Screen screen;
 
519
                        
 
520
                        Display.GetPointer (out screen, out x, out y, out mod);
 
521
                        
 
522
                        if (screen == Screen) {
 
523
                                Gdk.Rectangle geo, hide_offset;
 
524
                                window.GetBufferedPosition (out geo.X, out geo.Y);
 
525
                                window.WindowHideOffset (out hide_offset.X, out hide_offset.Y);
 
526
 
 
527
                                x -= geo.X - hide_offset.X;
 
528
                                y -= geo.Y - hide_offset.Y;
 
529
                        } else {
 
530
                                x = -4000;
 
531
                                y = -4000;
 
532
                        }
 
533
                        
 
534
                        SetupCursor (x, y, mod);
 
535
                }
 
536
                
 
537
                void SetupCursor (int x, int y, ModifierType mod)
 
538
                {
 
539
                        CursorModifier = mod;
 
540
                        
812
541
                        if ((Cursor.X == x && Cursor.Y == y) || PopupMenu.Visible)
813
542
                                return;
814
543
                        
815
 
                        Gdk.Rectangle geo;
816
 
                        window.GetPosition (out geo.X, out geo.Y);
817
 
                        
818
 
                        x -= geo.X;
819
 
                        y -= geo.Y - window.WindowHideOffset ();
820
544
                        Gdk.Point old_cursor_location = Cursor;
821
545
                        Cursor = new Gdk.Point (x, y);
822
546
 
828
552
                        bool cursorMoveWarrantsDraw = CursorIsOverDockArea && old_cursor_location.X != Cursor.X;
829
553
 
830
554
                        if (drag_resizing || cursorMoveWarrantsDraw) 
831
 
                                AnimatedDraw (drag_resizing);
832
 
                }
833
 
                
834
 
                #region Drag Code
835
 
                
836
 
                protected override bool OnDragMotion (Gdk.DragContext context, int x, int y, uint time)
837
 
                {
838
 
                        GtkDragging = true;
839
 
                        AnimatedDraw (false);
840
 
                        return base.OnDragMotion (context, x, y, time);
841
 
                }
842
 
 
843
 
                protected override void OnDragDataReceived (Gdk.DragContext context, int x, int y, Gtk.SelectionData selectionData, 
844
 
                                                            uint info, uint time)
845
 
                {
846
 
                        if (!CursorIsOverDockArea) return;
847
 
                        
848
 
                        string data = System.Text.Encoding.UTF8.GetString ( selectionData.Data );
849
 
                        data = System.Uri.UnescapeDataString (data);
850
 
                        //sometimes we get a null at the end, and it crashes us
851
 
                        data = data.TrimEnd ('\0'); 
852
 
                        
853
 
                        string [] uriList = Regex.Split (data, "\r\n");
854
 
                        if (CurrentDockItem != null && CurrentDockItem.IsAcceptingDrops) {
855
 
                                uriList.Where (uri => uri.StartsWith ("file://"))
856
 
                                        .ForEach (uri => CurrentDockItem.ReceiveItem (uri.Substring ("file://".Length)));
857
 
                        } else {
858
 
                                uriList.Where (uri => uri.StartsWith ("file://"))
859
 
                                        .ForEach (uri => item_provider.AddCustomItem (uri.Substring ("file://".Length)));
860
 
                        }
861
 
                        
862
 
                        base.OnDragDataReceived (context, x, y, selectionData, info, time);
863
 
                }
864
 
                
865
 
                protected override void OnDragBegin (Gdk.DragContext context)
866
 
                {
867
 
                        // the user might not end the drag on the same horizontal position they start it on
868
 
                        remove_drag_start_x = Cursor.X;
869
 
                        int item = PositionProvider.IndexAtPosition (Cursor.X);
870
 
                        
871
 
                        Gdk.Pixbuf pbuf;
872
 
                        if (item == -1 || !item_provider.ItemCanBeMoved (item)) {
873
 
                                pbuf = IconProvider.PixbufFromIconName ("gtk-remove", DockPreferences.IconSize);
874
 
                        } else {
875
 
                                pbuf = DockItems [item].GetDragPixbuf ();
876
 
                        }
877
 
                                
878
 
                        if (pbuf != null)
879
 
                                Gtk.Drag.SetIconPixbuf (context, pbuf, pbuf.Width / 2, pbuf.Height / 2);
880
 
                        base.OnDragBegin (context);
881
 
                }
882
 
                
883
 
                protected override void OnDragEnd (Gdk.DragContext context)
884
 
                {
885
 
                        if (PositionProvider.IndexAtPosition (remove_drag_start_x) != -1) {
886
 
                                GtkDragging = false;
887
 
                                int draggedPosition = PositionProvider.IndexAtPosition (remove_drag_start_x);
888
 
                                int currentPosition = PositionProvider.IndexAtPosition (Cursor.X);
889
 
                                if (context.DestWindow != window.GdkWindow || !CursorIsOverDockArea) {
890
 
                                        item_provider.RemoveItem (PositionProvider.IndexAtPosition (remove_drag_start_x));
891
 
                                } else if (CursorIsOverDockArea && currentPosition != draggedPosition) {
892
 
                                        item_provider.MoveItemToPosition (draggedPosition, currentPosition);
893
 
                                }
894
 
                                AnimatedDraw (true);
895
 
                        }
896
 
                        remove_drag_start_x = -1;
897
 
                        base.OnDragEnd (context);
898
 
                }
899
 
 
900
 
                #endregion
 
555
                                AnimatedDraw ();
 
556
                }
 
557
 
 
558
                protected override bool OnMotionNotifyEvent (Gdk.EventMotion evnt)
 
559
                {
 
560
                        GtkDragging = false;
 
561
                        SetupCursor ((int) evnt.X, (int) evnt.Y, evnt.State);
 
562
                        cursor_update = DateTime.UtcNow;
 
563
                        return base.OnMotionNotifyEvent (evnt);
 
564
                }
901
565
                
902
566
                protected override bool OnEnterNotifyEvent (Gdk.EventCrossing evnt)
903
567
                {
 
568
                        ResetCursorTimer ();
904
569
                        ManualCursorUpdate ();
905
570
                        return base.OnEnterNotifyEvent (evnt);
906
571
                }
907
 
                
908
 
                protected override bool OnExposeEvent(EventExpose evnt)
909
 
                {
910
 
                        bool ret_val = base.OnExposeEvent (evnt);
911
 
                        
912
 
                        if (!IsDrawable || window.WindowHideOffset () == Height)
913
 
                                return ret_val;
914
 
                        
915
 
                        Context cr;
916
 
                        if (backbuffer == null) {
917
 
                                cr = Gdk.CairoHelper.Create (GdkWindow);
918
 
                                backbuffer = cr.Target.CreateSimilar (cr.Target.Content, Width, Height);
919
 
                                
920
 
                                cr.Target.Destroy ();
921
 
                                (cr.Target as IDisposable).Dispose ();
922
 
                                (cr as IDisposable).Dispose ();
923
 
                        }
924
 
                        
925
 
                        cr = new Cairo.Context (backbuffer);
926
 
                        cr.AlphaFill ();
927
 
                        cr.Operator = Operator.Over;
928
 
                        
929
 
                        if (item_provider.UpdatesEnabled)
930
 
                                DrawDrock (cr);
931
 
                        (cr as IDisposable).Dispose ();
932
 
                        
933
 
                        Context cr2 = Gdk.CairoHelper.Create (GdkWindow);
934
 
                        cr2.SetSource (backbuffer, 0, VerticalOffset);
935
 
                        cr2.Operator = Operator.Source;
936
 
                        cr2.Paint ();
937
 
                        
938
 
                        cr2.Target.Destroy ();
939
 
                        ((IDisposable)cr2.Target).Dispose ();
940
 
                        ((IDisposable)cr2).Dispose ();
941
 
                        
942
 
                        return ret_val;
943
 
                }
944
 
                
945
 
                protected override bool OnMotionNotifyEvent(EventMotion evnt)
946
 
                {
947
 
                        GtkDragging = false;
948
 
                        return base.OnMotionNotifyEvent (evnt);
949
 
                }
950
 
                
951
 
                void ConfigureCursor ()
952
 
                {
953
 
                        // we do this so that our custom drag isn't destroyed by gtk's drag
954
 
                        if (gtk_drag_source_set && CursorNearDraggableEdge) {
955
 
                                UnregisterGtkDragSource ();
956
 
                                
957
 
                                if (cursor_type != CursorType.SbVDoubleArrow && CursorNearTopDraggableEdge)
958
 
                                        SetCursor (CursorType.SbVDoubleArrow);
959
 
                                else if (cursor_type != CursorType.LeftSide && CursorNearLeftEdge)
960
 
                                        SetCursor (CursorType.LeftSide);
961
 
                                else if (cursor_type != CursorType.RightSide && CursorNearRightEdge)
962
 
                                        SetCursor (CursorType.RightSide);
963
 
                                
964
 
                        } else if (!gtk_drag_source_set && !drag_resizing && !CursorNearDraggableEdge) {
965
 
                                RegisterGtkDragSource ();
966
 
                                if (cursor_type != CursorType.LeftPtr)
967
 
                                        SetCursor (CursorType.LeftPtr);
968
 
                        }
969
 
                }
970
 
                
971
 
                void SetCursor (Gdk.CursorType type)
972
 
                {
973
 
                        cursor_type = type;
974
 
                        Gdk.Cursor tmp_cursor = new Gdk.Cursor (type);
975
 
                        GdkWindow.Cursor = tmp_cursor;
976
 
                        tmp_cursor.Dispose ();
977
 
                }
978
 
                
 
572
 
979
573
                protected override bool OnButtonPressEvent (Gdk.EventButton evnt)
980
574
                {
981
575
                        if (CursorNearDraggableEdge)
984
578
                        return base.OnButtonPressEvent (evnt);
985
579
                }
986
580
                
 
581
                public void ProxyButtonReleaseEvent (Gdk.EventButton evnt)
 
582
                {
 
583
                        HandleButtonReleaseEvent (evnt);
 
584
                }
 
585
                
987
586
                protected override bool OnButtonReleaseEvent (Gdk.EventButton evnt)
988
587
                {
989
 
                        bool ret_val = base.OnButtonPressEvent (evnt);
 
588
                        bool result = base.OnButtonPressEvent (evnt);
 
589
                        HandleButtonReleaseEvent (evnt);
990
590
                        
 
591
                        return result;
 
592
                }
 
593
                
 
594
                private void HandleButtonReleaseEvent (Gdk.EventButton evnt)
 
595
                {
991
596
                        // lets not do anything in this case
992
597
                        if (drag_resizing) {
993
598
                                EndDrag ();
994
 
                                return ret_val;
 
599
                                return;
995
600
                        }
996
601
                        
997
 
                        if (InputInterfaceVisible) {
998
 
                                switch (SummonRenderer.GetClickEvent (GetDockArea ())) {
999
 
                                case SummonClickEvent.AddItemToDock:
1000
 
                                        item_provider.AddCustomItem (State [State.CurrentPane]);
1001
 
                                        window.RequestClickOff ();
1002
 
                                        break;
1003
 
                                case SummonClickEvent.None:
1004
 
                                        // Do nothing
1005
 
                                        break;
 
602
                        if (PainterOverlayVisible) {
 
603
                                Painter.Clicked (GetDockArea (), Cursor);
 
604
                                if (PainterOverlayVisible && !GetDockArea ().Contains (Cursor)) {
 
605
                                        InterruptPainter ();
1006
606
                                }
1007
 
                                if (!CursorIsOverDockArea)
1008
 
                                        window.RequestClickOff ();
1009
607
                        } else {
1010
 
                                int item = PositionProvider.IndexAtPosition ((int) evnt.X); //sometimes clicking is not good!
1011
 
                                if (item < 0 || item >= DockItems.Count || !CursorIsOverDockArea || InputInterfaceVisible)
1012
 
                                        return ret_val;
 
608
                                int item = PositionProvider.IndexAtPosition ((int) evnt.X, (int) evnt.Y); //sometimes clicking is not good!
 
609
                                if (item < 0 || item >= DockItems.Count || !CursorIsOverDockArea || PainterOverlayVisible)
 
610
                                        return;
1013
611
                                
1014
612
                                //handling right clicks for those icons which request simple right click handling
1015
613
                                if (evnt.Button == 3) {
1016
614
                                        if (CurrentDockItem is IRightClickable && (CurrentDockItem as IRightClickable).GetMenuItems ().Any ()) {
1017
 
                                                
1018
 
                                                int item_x;
1019
 
                                                double item_zoom;
1020
 
                                                IconZoomedPosition (PositionProvider.IndexAtPosition (Cursor.X), out item_x, out item_zoom);
1021
 
                                                int menu_y = LayoutUtils.MonitorGemonetry ().Height - (int) (DockPreferences.IconSize * item_zoom);
1022
 
                                                PopupMenu.PopUp ((CurrentDockItem as IRightClickable).GetMenuItems (), 
1023
 
                                                                      ((int) evnt.XRoot - Cursor.X) + item_x, menu_y);
1024
 
                                                return ret_val;
 
615
                                                PointD itemPosition_;
 
616
                                                double itemZoom;
 
617
                                                IconZoomedPosition (PositionProvider.IndexAtPosition (Cursor), out itemPosition_, out itemZoom);
 
618
 
 
619
                                                Gdk.Point itemPosition = new Gdk.Point ((int) itemPosition_.X, (int) itemPosition_.Y);
 
620
                                                
 
621
                                                itemPosition = itemPosition.RelativeMovePoint ((int) (IconSize * itemZoom * .9 * .5), RelativeMove.Inward);
 
622
                                                itemPosition = itemPosition.RelativePointToRootPoint (window);
 
623
                                                
 
624
                                                PopupMenu.PopUp (CurrentDockItem.Description, 
 
625
                                                                 (CurrentDockItem as IRightClickable).GetMenuItems (), 
 
626
                                                                 itemPosition.X, 
 
627
                                                                 itemPosition.Y);
 
628
                                                return;
1025
629
                                        }
1026
630
                                }
1027
631
                                
1028
632
                                //send off the clicks
1029
 
                                DockItems [item].Clicked (evnt.Button);
1030
 
                                AnimatedDraw (false);
1031
 
                        }
1032
 
                        return ret_val;
1033
 
                }
1034
 
                
1035
 
                void StartDrag ()
1036
 
                {
1037
 
                        drag_start_point = Cursor;
1038
 
                        drag_start_icon_size = DockPreferences.IconSize;
1039
 
                        drag_resizing = true;
1040
 
                        drag_edge = CurrentDragEdge;
1041
 
                }
1042
 
                
1043
 
                void EndDrag ()
1044
 
                {
1045
 
                        drag_edge = DragEdge.None;
1046
 
                        drag_resizing = false;
1047
 
                        SetIconRegions ();
1048
 
                        window.SetStruts ();
1049
 
                        
1050
 
                        AnimatedDraw (true);
1051
 
                        
1052
 
                        ResetCursorTimer ();
1053
 
                }
1054
 
                
1055
 
                void HandleDragMotion ()
1056
 
                {
1057
 
                        int movement = 0;
1058
 
                        switch (drag_edge) {
1059
 
                        case DragEdge.Top:
1060
 
                                DockPreferences.IconSize = Math.Min (drag_start_icon_size + (drag_start_point.Y - Cursor.Y), 
1061
 
                                                                     DockPreferences.MaxIconSize);
1062
 
                                return;
1063
 
                        case DragEdge.Left:
1064
 
                                movement = drag_start_point.X - Cursor.X;
1065
 
                                break;
1066
 
                        case DragEdge.Right:
1067
 
                                movement = Cursor.X - drag_start_point.X;
1068
 
                                break;
1069
 
                        }
 
633
                                Gdk.Point relative_point = Gdk.Point.Zero;
 
634
                                DockItems [item].Clicked (evnt.Button, evnt.State, relative_point);
 
635
                                
 
636
                                AnimatedDraw ();
 
637
                        }
 
638
                        return;
 
639
                }
1070
640
 
1071
 
                        if (movement > IconSize / 2 + 2) {
1072
 
                                DockPreferences.AutomaticIcons++;
1073
 
                        } else if (movement < 0 - (IconSize / 2 + 2)) {
1074
 
                                DockPreferences.AutomaticIcons--;
1075
 
                        } else {
1076
 
                                return;
1077
 
                        }
 
641
                protected override bool OnScrollEvent (Gdk.EventScroll evnt)
 
642
                {
 
643
                        int item = PositionProvider.IndexAtPosition ((int) evnt.X, (int) evnt.Y);
 
644
                        if (item == -1)
 
645
                                return false;
1078
646
                        
1079
 
                        drag_start_point.X = Cursor.X;
 
647
                        DockItems [item].Scrolled (evnt.Direction);
 
648
                        return base.OnScrollEvent (evnt);
1080
649
                }
1081
650
                
1082
651
                void SetIconRegions ()
1083
652
                {
1084
 
                        Gdk.Rectangle pos, area;
 
653
                        Gdk.Rectangle pos, area, offset;
1085
654
                        window.GetPosition (out pos.X, out pos.Y);
1086
655
                        window.GetSize (out pos.Width, out pos.Height);
1087
656
                        
1088
 
                        int hideOffset = window.WindowHideOffset ();
 
657
                        window.WindowHideOffset (out offset.X, out offset.Y);
1089
658
                        // we use geo here instead of our position for the Y value because we know the parent window
1090
659
                        // may offset us when hidden. This is not desired...
1091
660
                        for (int i = 0; i < DockItems.Count; i++) {
1092
 
                                int x = PositionProvider.IconUnzoomedPosition (i);
1093
 
                                area = new Gdk.Rectangle (pos.X + (x - IconSize / 2),
1094
 
                                                          pos.Y + pos.Height - hideOffset - PositionProvider.VerticalBuffer - IconSize,
 
661
                                Gdk.Point position = PositionProvider.IconUnzoomedPosition (i);
 
662
                                area = new Gdk.Rectangle (pos.X + (position.X - IconSize / 2) - offset.X,
 
663
                                                          pos.Y + (position.Y - IconSize / 2) - offset.Y,
1095
664
                                                          IconSize,
1096
665
                                                          IconSize);
1097
666
                                DockItems [i].SetIconRegion (area);
1104
673
                                return;
1105
674
                        
1106
675
                        int offset;
1107
 
                        if (InputInterfaceVisible) {
1108
 
                                offset = Height;
 
676
                        if (PainterOverlayVisible) {
 
677
                                offset = 0;
1109
678
                        } else if (CursorIsOverDockArea) {
1110
 
                                offset = GetDockArea ().Height * 2 + 10;
 
679
                                offset = GetDockArea ().Height;
 
680
                                offset = offset * 2 + 10;
1111
681
                        } else {
1112
682
                                if (DockPreferences.AutoHide && !drag_resizing) {
1113
683
                                        // setting the offset to 2 will trigger the parent window to unhide us if we are hidden.
1114
 
                                        if (AnimationState ["UrgentAnimationNeeded"])
 
684
                                        if (AnimationState [Animations.UrgencyChanged])
1115
685
                                                offset = 2;
1116
686
                                        else
1117
687
                                                offset = 1;
1120
690
                                }
1121
691
                        }
1122
692
                        
1123
 
                        int width = (drag_resizing) ? Width : DockWidth;
1124
 
                        window.SetInputMask (new Gdk.Rectangle ((Width - width) / 2, Height - offset, width, offset));
1125
 
                }
1126
 
                
1127
 
                public void SetPaneContext (IUIContext context, Pane pane)
1128
 
                {
1129
 
                        State.SetContext (context, pane);
1130
 
                        AnimatedDraw (false);
1131
 
                }
1132
 
                
1133
 
                public void ShowInputInterface ()
1134
 
                {
1135
 
                        interface_change_time = DateTime.UtcNow;
1136
 
                        InputInterfaceVisible = true;
1137
 
                        
1138
 
                        SetParentInputMask ();
1139
 
                        AnimatedDraw (false);
1140
 
                }
1141
 
                
1142
 
                public void HideInputInterface ()
1143
 
                {
1144
 
                        interface_change_time = DateTime.UtcNow;
1145
 
                        InputInterfaceVisible = false;
1146
 
                        
1147
 
                        SetParentInputMask ();
1148
 
                        AnimatedDraw (false);
1149
 
                        
1150
 
                        GLib.Timeout.Add (500, () => { 
1151
 
                                item_provider.ForceUpdate (); 
1152
 
                                return false; 
1153
 
                        });
1154
 
                }
1155
 
                
1156
 
                public void Reset ()
1157
 
                {
1158
 
                        State.Clear ();
1159
 
                        AnimatedDraw (false);
1160
 
                }
1161
 
                
1162
 
                public void ClearPane (Pane pane)
1163
 
                {
1164
 
                        State.ClearPane (pane);
 
693
                        int dockSize = (drag_resizing) ? Width : MinimumDockArea.Width;
 
694
                        
 
695
                        switch (DockPreferences.Orientation) {
 
696
                        case DockOrientation.Bottom:
 
697
                                window.SetInputMask (new Gdk.Rectangle ((Width - dockSize) / 2, 
 
698
                                                                        Height - offset, 
 
699
                                                                        dockSize, 
 
700
                                                                        offset));
 
701
                                break;
 
702
                        case DockOrientation.Top:
 
703
                                window.SetInputMask (new Gdk.Rectangle ((Width - dockSize) / 2, 
 
704
                                                                        0, 
 
705
                                                                        dockSize, 
 
706
                                                                        offset));
 
707
                                break;
 
708
                        }
 
709
                }
 
710
 
 
711
                void InterruptPainter ()
 
712
                {
 
713
                        if (Painter == null || !Painter.Interruptable) return;
 
714
 
 
715
                        Painter.Interrupt ();
 
716
                        Painter = null;
 
717
                        PainterOverlayVisible = false;
 
718
                        interface_change_time = DateTime.UtcNow;
 
719
                        
 
720
                        RegisterGtkDragSource ();
 
721
                        window.UnpresentWindow ();
 
722
 
 
723
                        SetParentInputMask ();
 
724
                        AnimatedDraw ();
1165
725
                }
1166
726
                
1167
727
                public override void Dispose ()
1170
730
                        UnregisterEvents ();
1171
731
                        UnregisterGtkDragSource ();
1172
732
 
1173
 
                        SummonRenderer.Dispose ();
1174
 
                        SummonRenderer = null;
1175
 
                        
1176
 
                        item_provider.Dispose ();
1177
 
                        item_provider = null;
1178
 
 
1179
733
                        PositionProvider.Dispose ();
 
734
                        AnimationState.Dispose ();
 
735
                        PopupMenu.Destroy ();
 
736
 
1180
737
                        PositionProvider = null;
1181
 
 
1182
 
                        AnimationState.Dispose ();
1183
738
                        AnimationState = null;
1184
 
 
1185
 
                        PopupMenu.Destroy ();
1186
739
                        PopupMenu = null;
1187
740
 
1188
741
                        if (backbuffer != null)
1193
746
 
1194
747
                        if (dock_icon_buffer != null)
1195
748
                                dock_icon_buffer.Destroy ();
1196
 
 
 
749
                        
 
750
                        if (LastPainter != null) {
 
751
                                LastPainter.PaintNeeded -= HandlePaintNeeded;
 
752
                        }
 
753
                        
 
754
                        if (Painter != null) {
 
755
                                Painter.PaintNeeded -= HandlePaintNeeded;
 
756
                        }
 
757
                        
1197
758
                        window = null;
1198
759
                        
1199
760
                        if (cursor_timer > 0)