~and471/+junk/do-with-docky

« back to all changes in this revision

Viewing changes to Do.Interface.Linux.Docky/src/Docky.Interface/DockArea_Rendering.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_Rendering.cs
 
2
// 
 
3
// Copyright (C) 2009 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.Linq;
 
22
 
 
23
using Cairo;
 
24
using Gdk;
 
25
using Gtk;
 
26
using Wnck;
 
27
 
 
28
using Do.Interface;
 
29
using Do.Interface.CairoUtils;
 
30
using Do.Interface.Wink;
 
31
 
 
32
using Docky.Core;
 
33
using Docky.Utilities;
 
34
using Docky.Interface.Painters;
 
35
 
 
36
namespace Docky.Interface
 
37
{
 
38
        
 
39
        
 
40
        internal partial class DockArea
 
41
        {
 
42
                class PreviousRenderData {
 
43
                        public bool ForceFullRender { get; set; }
 
44
                        public Gdk.Point LastCursor { get; set; }
 
45
                        public double ZoomIn { get; set; }
 
46
                        public List<AbstractDockItem> RenderItems { get; private set; }
 
47
                        
 
48
                        public PreviousRenderData ()
 
49
                        {
 
50
                                RenderItems = new List<AbstractDockItem> ();
 
51
                        }
 
52
                }
 
53
                
 
54
                public static DateTime RenderTime { get; private set; }
 
55
                
 
56
                const int IndicatorSize = 9;
 
57
                const int UrgentIndicatorSize = 12;
 
58
                
 
59
                Dictionary<IDockPainter, Surface> painter_surfaces;
 
60
                bool next_fast_render, first_render_set, last_no_render, rendering;
 
61
                double? zoom_in_buffer;
 
62
                
 
63
                Surface backbuffer, input_area_buffer, dock_icon_buffer;
 
64
                Surface indicator, urgent_indicator;
 
65
                IDockPainter painter, last_painter;
 
66
                
 
67
                DateTime LastOverlapCheck { get; set; }
 
68
                
 
69
                DateTime ActiveIconChangeTime { get; set; }
 
70
                
 
71
                DateTime FirstRenderTime { get; set; }
 
72
                
 
73
                PreviousRenderData RenderData { get; set; }
 
74
 
 
75
                //// <value>
 
76
                /// Determines if the current rendering state allows for a fast render
 
77
                /// </value>
 
78
                bool CanFastRender {
 
79
                        get {
 
80
                                bool result = next_fast_render && !RenderData.ForceFullRender && RenderData.RenderItems.Count == 0;
 
81
                                next_fast_render = RenderData.ZoomIn == 1 && ZoomIn == 1 && !DnDTracker.DragResizing;
 
82
                                return result;
 
83
                        }
 
84
                }
 
85
                
 
86
                //// <value>
 
87
                /// Determines if the current rendering state allows for a "no" render
 
88
                /// </value>
 
89
                bool CanNoRender {
 
90
                        get {
 
91
                                bool result = DockPreferences.ZoomEnabled && 
 
92
                                            !RenderData.ForceFullRender &&
 
93
                                                RenderData.RenderItems.Count == 0 &&
 
94
                                            RenderData.ZoomIn == 0 &&
 
95
                                                !DnDTracker.GtkDragging &&
 
96
                                                !DnDTracker.DragResizing &&
 
97
                                                ZoomIn == 0;
 
98
                                bool tmp = last_no_render;
 
99
                                last_no_render = result;
 
100
                                return result && tmp;
 
101
                        }
 
102
                }
 
103
                
 
104
                //// <value>
 
105
                /// Determins if a single item only needs to be redrawn and updated (usually caused by an update request)
 
106
                /// </value>
 
107
                bool SingleItemRender {
 
108
                        get {
 
109
                                return !RenderData.ForceFullRender && 
 
110
                                            RenderData.ZoomIn == 0 && 
 
111
                                                ZoomIn == 0 && 
 
112
                                                RenderData.RenderItems.Count == 1;
 
113
                        }
 
114
                }
 
115
                
 
116
                bool AnimationRequiresRender {
 
117
                        get {
 
118
                                return AnimationState [Animations.IconInsert] ||
 
119
                                           AnimationState [Animations.UrgencyChanged] ||
 
120
                                           AnimationState [Animations.Bounce] ||
 
121
                                           AnimationState [Animations.InputModeChanged];
 
122
                        }
 
123
                }
 
124
                
 
125
                /// <value>
 
126
                /// Determins the opacity of the icons on the normal dock
 
127
                /// </value>
 
128
                double DockIconOpacity {
 
129
                        get {
 
130
                                if (SummonTime < RenderTime - interface_change_time) {
 
131
                                        if (PainterOverlayVisible)
 
132
                                                return 0;
 
133
                                        return 1;
 
134
                                }
 
135
 
 
136
                                double total_time = (RenderTime - interface_change_time).TotalMilliseconds;
 
137
                                if (PainterOverlayVisible) {
 
138
                                        return 1 - (total_time / SummonTime.TotalMilliseconds);
 
139
                                } else {
 
140
                                        return total_time / SummonTime.TotalMilliseconds;
 
141
                                }
 
142
                        }
 
143
                }
 
144
                
 
145
                //// <value>
 
146
                /// Get autohide state
 
147
                /// </value>
 
148
                bool IsHidden {
 
149
                        get {
 
150
                                bool hidden = false;
 
151
                                switch (DockPreferences.AutohideType) {
 
152
                                case AutohideType.Autohide:
 
153
                                        hidden = !CursorIsOverDockArea;
 
154
                                        break;
 
155
                                case AutohideType.Intellihide:
 
156
                                        hidden = !CursorIsOverDockArea && WindowIntersectingOther;
 
157
                                        break;
 
158
                                }
 
159
                                return hidden;
 
160
                        }
 
161
                }
 
162
                
 
163
                /// <value>
 
164
                /// Icon Size used for the dock
 
165
                /// </value>
 
166
                int IconSize { 
 
167
                        get { return DockPreferences.IconSize; } 
 
168
                }
 
169
                
 
170
                IDockPainter LastPainter { 
 
171
                        get {
 
172
                                return last_painter;
 
173
                        }
 
174
                        set {
 
175
                                if (last_painter == value)
 
176
                                        return;
 
177
                                if (last_painter != null)
 
178
                                        last_painter.PaintNeeded -= HandlePaintNeeded;
 
179
                                last_painter = value;
 
180
                        }
 
181
                }
 
182
                
 
183
                IDockPainter Painter { 
 
184
                        get {
 
185
                                return painter;
 
186
                        }
 
187
                        set {
 
188
                                if (painter == value)
 
189
                                        return;
 
190
                                LastPainter = painter;
 
191
                                painter = value;
 
192
                                if (painter != null)
 
193
                                        painter.PaintNeeded += HandlePaintNeeded;
 
194
                        }
 
195
                }
 
196
 
 
197
                /// <summary>
 
198
                /// The opacity of the painter surface
 
199
                /// </summary>
 
200
                double PainterOpacity {
 
201
                        get { return 1 - DockIconOpacity; }
 
202
                }
 
203
                
 
204
                //// <value>
 
205
                /// The overall offset of the dock as a whole
 
206
                /// </value>
 
207
                int VerticalOffset {
 
208
                        get {
 
209
                                double offset = 0;
 
210
                                // we never hide in these conditions
 
211
                                if (DockPreferences.AutohideType == AutohideType.None || DnDTracker.DragResizing || PainterOpacity == 1) {
 
212
                                        if ((RenderTime - FirstRenderTime) > SummonTime)
 
213
                                                return 0;
 
214
                                        offset = 1 - Math.Min (1, (DateTime.UtcNow - FirstRenderTime).TotalMilliseconds / SummonTime.TotalMilliseconds);
 
215
                                        return (int) (offset * PositionProvider.DockHeight * 1.5);
 
216
                                }
 
217
 
 
218
                                if (PainterOpacity > 0) {
 
219
                                        if (!IsHidden) {
 
220
                                                return 0;
 
221
                                        } else {
 
222
                                                offset = Math.Min (1, (RenderTime - showhide_time).TotalMilliseconds / 
 
223
                                                                   SummonTime.TotalMilliseconds);
 
224
                                                offset = Math.Min (offset, Math.Min (1, 
 
225
                                                                                     (RenderTime - interface_change_time)
 
226
                                                                                     .TotalMilliseconds / SummonTime.TotalMilliseconds));
 
227
                                        }
 
228
                                        
 
229
                                        if (PainterOverlayVisible)
 
230
                                                offset = 1 - offset;
 
231
                                } else {
 
232
                                        offset = Math.Min (1, (RenderTime - showhide_time).TotalMilliseconds / 
 
233
                                                           SummonTime.TotalMilliseconds);
 
234
                                        if (!IsHidden)
 
235
                                                offset = 1 - offset;
 
236
                                }
 
237
                                return (int) (offset * PositionProvider.DockHeight * 1.5);
 
238
                        }
 
239
                }
 
240
                
 
241
                /// <value>
 
242
                /// Returns the zoom in percentage (0 through 1)
 
243
                /// </value>
 
244
                double ZoomIn {
 
245
                        get {
 
246
                                if (DnDTracker.InternalDragActive)
 
247
                                        return 0;
 
248
                                
 
249
                                // we buffer this value during renders since it will be checked many times and we dont need to 
 
250
                                // recalculate it each time
 
251
                                if (zoom_in_buffer.HasValue && rendering) {
 
252
                                        return zoom_in_buffer.Value;
 
253
                                }
 
254
                                
 
255
                                double zoom = Math.Min (1, (RenderTime - enter_time).TotalMilliseconds / 
 
256
                                                         BaseAnimationTime.TotalMilliseconds);
 
257
                                if (CursorIsOverDockArea) {
 
258
                                        if (DockPreferences.AutohideType == AutohideType.Autohide || 
 
259
                                            (DockPreferences.AutohideType == AutohideType.Intellihide && WindowIntersectingOther))
 
260
                                                zoom = 1;
 
261
                                } else {
 
262
                                        zoom = 1 - zoom;
 
263
                                }
 
264
                                
 
265
                                if (PainterOverlayVisible)
 
266
                                        zoom = zoom * DockIconOpacity;
 
267
                                
 
268
                                if (rendering)
 
269
                                        zoom_in_buffer = zoom;
 
270
                                
 
271
                                return zoom;
 
272
                        }
 
273
                }
 
274
 
 
275
                void BuildRendering ()
 
276
                {
 
277
                        RenderData = new PreviousRenderData ();
 
278
                        painter_surfaces = new Dictionary<IDockPainter, Surface> ();
 
279
                }
 
280
                
 
281
                void HandleActiveWindowChanged (object o, ActiveWindowChangedArgs args)
 
282
                {
 
283
                        RequestFullRender ();
 
284
                        AnimatedDraw ();
 
285
                }
 
286
 
 
287
                void HandleIntersectionChanged (object sender, EventArgs e)
 
288
                {
 
289
                        if (DockPreferences.AutohideType == AutohideType.Intellihide && !CursorIsOverDockArea) {
 
290
                                showhide_time = UpdateTimeStamp (showhide_time, SummonTime);
 
291
                                AnimatedDraw ();
 
292
                        }
 
293
                }
 
294
                
 
295
                void DrawDock (Context cr)
 
296
                {
 
297
                        Gdk.Rectangle dockArea = GetDockArea ();
 
298
                        window.SetBackgroundBlur (dockArea);
 
299
                        
 
300
                        DockBackgroundRenderer.RenderDockBackground (cr, dockArea);
 
301
 
 
302
                        IDockPainter dpaint = (Painter == null) ? LastPainter : Painter;
 
303
                        
 
304
                        if (PainterOpacity > 0 && dpaint != null) {
 
305
                                Surface overlay_surface = GetOverlaySurface (cr);
 
306
                                
 
307
                                using (Context input_cr = new Context (overlay_surface)) {
 
308
                                        if (!dpaint.DoubleBuffer)
 
309
                                                input_cr.AlphaFill ();
 
310
                                        dpaint.Paint (input_cr, dockArea, Cursor);
 
311
                                }
 
312
 
 
313
                                cr.SetSource (overlay_surface);
 
314
                                cr.PaintWithAlpha (PainterOpacity);
 
315
                        }
 
316
                        
 
317
                        bool isNotSummonTransition = PainterOpacity == 0 || !IsHidden || !DockPreferences.AutoHide;
 
318
                        if (DockIconOpacity > 0 && isNotSummonTransition) {
 
319
                                if (dock_icon_buffer == null)
 
320
                                        dock_icon_buffer = cr.Target.CreateSimilar (cr.Target.Content, Width, Height);
 
321
                                
 
322
                                using (Context input_cr = new Context (dock_icon_buffer)) {
 
323
                                        DrawIcons (input_cr, dockArea);
 
324
                                }
 
325
 
 
326
                                int offset =  (int) (IconSize * (1 - DockIconOpacity));
 
327
                                Gdk.Point iconBufferLocation = new Gdk.Point (0, 0).RelativeMovePoint (offset, RelativeMove.Outward);
 
328
                                cr.SetSource (dock_icon_buffer, iconBufferLocation.X, iconBufferLocation.Y);
 
329
                                cr.PaintWithAlpha (DockIconOpacity);
 
330
                        }
 
331
                }
 
332
                
 
333
                void DrawIcons (Context cr, Gdk.Rectangle dockArea)
 
334
                {
 
335
                        bool animationRequired = AnimationRequiresRender;
 
336
                        int index = PositionProvider.IndexAtPosition (Cursor);
 
337
                        
 
338
                        if (CanFastRender && !animationRequired) {
 
339
                                // We are in a zoomed in state where we can render only those icons which are moving around
 
340
                                // on screen. This only happens when zoom is enabled
 
341
                                Gdk.Rectangle renderArea = Gdk.Rectangle.Zero;
 
342
                                
 
343
                                int startItemPosition;
 
344
                                startItemPosition = Math.Min (Cursor.X, RenderData.LastCursor.X) - 
 
345
                                        (DockPreferences.ZoomSize / 2 + DockPreferences.IconSize);
 
346
                                
 
347
                                int endItemPosition;
 
348
                                endItemPosition = Math.Max (Cursor.X, RenderData.LastCursor.X) + 
 
349
                                        (DockPreferences.ZoomSize / 2 + DockPreferences.IconSize);
 
350
                                
 
351
                                int startItem = PositionProvider.IndexAtPosition (startItemPosition, Cursor.Y);
 
352
                                int endItem = PositionProvider.IndexAtPosition (endItemPosition, Cursor.Y);
 
353
                                
 
354
                                int maxClamp = DockItems.Count - 1;
 
355
                                
 
356
                                startItem = startItem == -1 ? 0 : startItem;
 
357
                                endItem = endItem == -1 ? maxClamp : endItem;
 
358
                                
 
359
                                // these are special cases that we dont want to fall on edges (unless they are the clamps... clamps)
 
360
                                if (startItem > 0 && DockItems [startItem - 1].ContainsFocusedWindow)
 
361
                                        startItem = Math.Max (0, startItem - 1);
 
362
                                
 
363
                                if (DockItems [endItem].ContainsFocusedWindow)
 
364
                                        endItem = Math.Min (maxClamp, endItem + 1);
 
365
                                
 
366
                                PointD firstPosition, lastPosition;
 
367
                                double firstZoom, lastZoom;
 
368
                                
 
369
                                // set up our X value
 
370
                                if (startItem == 0) {
 
371
                                        renderArea.X = dockArea.X;
 
372
                                } else {
 
373
                                        IconZoomedPosition (startItem, out firstPosition, out firstZoom);
 
374
                                        renderArea.X = (int) (firstPosition.X - (DockItems [startItem].Width * firstZoom) / 2) - 2;
 
375
                                }
 
376
                                
 
377
                                if (endItem == maxClamp) {
 
378
                                        renderArea.Width = dockArea.Width - (renderArea.X - dockArea.X);
 
379
                                } else {
 
380
                                        IconZoomedPosition (endItem, out lastPosition, out lastZoom);
 
381
                                
 
382
                                        // Add/Sub 2 to provide a good "buffer" into the dead zone between icons
 
383
                                        renderArea.Width = (int) (lastPosition.X + (DockItems [endItem].Width * lastZoom) / 2) + 2 - renderArea.X;
 
384
                                }
 
385
                                
 
386
                                renderArea.Height = Height;
 
387
                                
 
388
                                cr.Rectangle (renderArea.X, renderArea.Y, renderArea.Width, renderArea.Height);
 
389
                                
 
390
                                // clear the areas outside the dock area
 
391
                                cr.Rectangle (0, dockArea.Y, dockArea.X, dockArea.Height);
 
392
                                cr.Rectangle (dockArea.X + dockArea.Width, dockArea.Y, Width - (dockArea.X + dockArea.Width), dockArea.Height);
 
393
                                switch (DockPreferences.Orientation) {
 
394
                                case DockOrientation.Bottom:
 
395
                                        cr.Rectangle (0, 0, Width, Height - dockArea.Height);
 
396
                                        break;
 
397
                                case DockOrientation.Top:
 
398
                                        cr.Rectangle (0, dockArea.Height, Width, Height - dockArea.Height);
 
399
                                        break;
 
400
                                }
 
401
                                cr.Operator = Operator.Clear;
 
402
                                cr.Fill ();
 
403
                                cr.Operator = Operator.Over;
 
404
                                
 
405
                                for (int i = startItem; i <= endItem; i++) {
 
406
                                        if (i == index)
 
407
                                                continue;
 
408
                                        DrawIcon (cr, i, false);
 
409
                                }
 
410
                                // draw hovered item last, for the sake of making sure its on top in certain animations
 
411
                                if (index >= startItem && index <= endItem)
 
412
                                        DrawIcon (cr, index, true);
 
413
                                
 
414
                        } else if (SingleItemRender && !animationRequired) {
 
415
                                // A single icon for some reason needs to be drawn again. This is more or less
 
416
                                // a special case of a fast render
 
417
                                Gdk.Rectangle renderArea = Gdk.Rectangle.Zero;
 
418
                                PointD firstPosition;
 
419
                                double firstZoom;
 
420
                                
 
421
                                AbstractDockItem single = RenderData.RenderItems [0];
 
422
                                int singleIndex = DockItems.IndexOf (single);
 
423
                                
 
424
                                // set up our X value
 
425
                                IconZoomedPosition (singleIndex, out firstPosition, out firstZoom);
 
426
                                renderArea.X = (int) (firstPosition.X - (single.Width * firstZoom) / 2) - 2;
 
427
                                renderArea.Width = (int) (firstPosition.X + (single.Width * firstZoom) / 2) + 2 - renderArea.X;
 
428
                                
 
429
                                renderArea.Height = Height;
 
430
                                
 
431
                                cr.Rectangle (renderArea.X, renderArea.Y, renderArea.Width, renderArea.Height);
 
432
                                
 
433
                                // clear the areas outside the dock area
 
434
                                cr.Rectangle (0, dockArea.Y, dockArea.X, dockArea.Height);
 
435
                                cr.Rectangle (dockArea.X + dockArea.Width, dockArea.Y, Width - (dockArea.X + dockArea.Width), dockArea.Height);
 
436
                                switch (DockPreferences.Orientation) {
 
437
                                case DockOrientation.Bottom:
 
438
                                        cr.Rectangle (0, 0, Width, Height - dockArea.Height);
 
439
                                        break;
 
440
                                case DockOrientation.Top:
 
441
                                        cr.Rectangle (0, dockArea.Height, Width, Height - dockArea.Height);
 
442
                                        break;
 
443
                                }
 
444
                                cr.Operator = Operator.Clear;
 
445
                                cr.Fill ();
 
446
                                cr.Operator = Operator.Over;
 
447
                                
 
448
                                DrawIcon (cr, singleIndex, index == singleIndex);
 
449
                        } else if (animationRequired || !CanNoRender) {
 
450
                                // we didn't fast render or single icon render, but we can't not render, so we have to do it the slow way
 
451
                                cr.AlphaFill ();
 
452
                                
 
453
                                for (int i = 0; i < DockItems.Count; i++) {
 
454
                                        if (i == index)
 
455
                                                continue;
 
456
                                        DrawIcon (cr, i, false);
 
457
                                }
 
458
                                // draw hovered item last, for the sake of making sure its on top in certain animations
 
459
                                if (index >= 0 && index < DockItems.Count)
 
460
                                        DrawIcon (cr, index, true);
 
461
                        }
 
462
                        
 
463
                        RenderData.LastCursor = Cursor;
 
464
                        RenderData.ZoomIn = ZoomIn;
 
465
                        RenderData.ForceFullRender = false;
 
466
                        RenderData.RenderItems.Clear ();
 
467
                }
 
468
                
 
469
                void DrawIcon (Context cr, int icon, bool hovered)
 
470
                {
 
471
                        // Don't draw the icon we are dragging around
 
472
                        if (DnDTracker.GtkDragging && !DnDTracker.DragState.IsFinished) {
 
473
                                int item = DockItems.IndexOf (DnDTracker.DragState.DragItem);
 
474
                                if (item == icon && DockServices.ItemsService.ItemCanBeMoved (item))
 
475
                                        return;
 
476
                        }
 
477
                        
 
478
                        AbstractDockItem dockItem = DockItems [icon];
 
479
                        if (dockItem == null) return; //happens?
 
480
                        
 
481
                        PointD center;
 
482
                        double zoom;
 
483
                        IconZoomedPosition (icon, out center, out zoom);
 
484
                        
 
485
                        // This gives the actual x,y coordinates of the icon
 
486
                        PointD iconPosition = new PointD (center.X - zoom * (dockItem.Width >> 1),
 
487
                                                          center.Y - zoom * (dockItem.Width >> 1));
 
488
                        
 
489
                        ClickAnimationType animationType = IconAnimation (icon);
 
490
                        
 
491
                        // we will set this flag now
 
492
                        if (animationType == ClickAnimationType.Bounce) {
 
493
                                // bounces twice
 
494
                                double delta = Math.Abs (LaunchBounceHeight * Math.Sin 
 
495
                                                         (dockItem.TimeSinceClick.TotalMilliseconds * Math.PI / 
 
496
                                                          (BounceTime.TotalMilliseconds / 2)));
 
497
                                
 
498
                                iconPosition = iconPosition.RelativeMovePoint (delta, RelativeMove.Inward);
 
499
                        } else {
 
500
                                if (RenderTime - dockItem.AttentionRequestStartTime < BounceTime) {
 
501
                                        double urgentMs = (RenderTime - dockItem.AttentionRequestStartTime)
 
502
                                                .TotalMilliseconds;
 
503
                                        
 
504
                                        double delta = UrgentBounceHeight * Math.Sin (urgentMs * Math.PI / (BounceTime.TotalMilliseconds));
 
505
                                        iconPosition = iconPosition.RelativeMovePoint (delta, RelativeMove.Inward);
 
506
                                }
 
507
                        }
 
508
                        
 
509
                        int size;
 
510
                        Surface iconSurface = dockItem.GetIconSurface (cr.Target, (int) (IconSize * zoom), out size);
 
511
                        
 
512
                        if (dockItem.ScalingType != ScalingType.None) {
 
513
                                double scale;
 
514
                                
 
515
                                if (size == DockPreferences.FullIconSize) {
 
516
                                        scale = zoom / DockPreferences.IconQuality;
 
517
                                } else if (size == DockPreferences.IconSize) {
 
518
                                        scale = zoom;
 
519
                                } else {
 
520
                                        Do.Platform.Log<DockArea>.Error ("Icon provided in unexpected size");
 
521
                                        return;
 
522
                                }
 
523
                                
 
524
                                if (dockItem.ContainsFocusedWindow) {
 
525
                                        double intenseS = 0.8;
 
526
                                        
 
527
                                        double xHigh = iconPosition.X - 1.5;
 
528
                                        double yHigh = MinimumDockArea.Y;
 
529
                                        double widthHigh = dockItem.Width * zoom + 3;
 
530
                                        cr.Rectangle (xHigh, yHigh, widthHigh, DockHeight);
 
531
                                        
 
532
                                        LinearGradient lg;
 
533
                                        if (DockPreferences.Orientation == DockOrientation.Bottom) {
 
534
                                                lg = new LinearGradient (0, yHigh + DockHeight, 0, yHigh);
 
535
                                        } else {
 
536
                                                lg = new LinearGradient (0, yHigh, 0, yHigh + DockHeight);
 
537
                                        }
 
538
                                        
 
539
                                        Cairo.Color average = dockItem.AverageColor ();
 
540
                                        lg.AddColorStop (0, new Cairo.Color (average.R, average.G, average.B, .3));
 
541
                                        lg.AddColorStop (1, new Cairo.Color (average.R, average.G, average.B, 0));
 
542
                                        cr.Pattern = lg;
 
543
                                        cr.Fill ();
 
544
                                        lg.Destroy ();
 
545
                                        
 
546
                                        if (DockPreferences.Orientation == DockOrientation.Bottom)
 
547
                                                cr.Translate (0, 2);
 
548
                                        
 
549
                                        cr.MoveTo (xHigh, yHigh);
 
550
                                        cr.LineTo (xHigh, yHigh + DockHeight - 2);
 
551
                                        cr.MoveTo (xHigh + widthHigh, yHigh);
 
552
                                        cr.LineTo (xHigh + widthHigh, yHigh + DockHeight - 2);
 
553
                                        
 
554
                                        if (DockPreferences.Orientation == DockOrientation.Bottom)
 
555
                                                cr.Translate (0, -2);
 
556
                                        
 
557
                                        cr.Color = new Cairo.Color (intenseS, intenseS, intenseS, .3);
 
558
                                        cr.LineWidth = 1;
 
559
                                        cr.Stroke ();
 
560
                                }
 
561
                                
 
562
                                if (scale != 1)
 
563
                                        cr.Scale (scale, scale);
 
564
                                // we need to multiply x and y by 1 / scale to undo the scaling of the context.  We only want to zoom
 
565
                                // the icon, not move it around.
 
566
                                
 
567
                                double fadeInOpacity = Math.Min (dockItem.TimeSinceAdd.TotalMilliseconds / 
 
568
                                                                 InsertAnimationTime.TotalMilliseconds, 1);
 
569
                                cr.SetSource (iconSurface, 
 
570
                                              iconPosition.X / scale, iconPosition.Y / scale);
 
571
                                cr.PaintWithAlpha (fadeInOpacity);
 
572
                                
 
573
                                bool shade_light = DnDTracker.GtkDragging && !DnDTracker.PreviewIsDesktopFile && CursorIsOverDockArea &&
 
574
                                        dockItem.IsAcceptingDrops && icon == PositionProvider.IndexAtPosition (Cursor);
 
575
                                
 
576
                                bool shade_dark = animationType == ClickAnimationType.Darken;
 
577
                                if (shade_dark || shade_light) {
 
578
                                        cr.Rectangle (iconPosition.X / scale, iconPosition.Y / scale, 
 
579
                                                      DockPreferences.FullIconSize, DockPreferences.FullIconSize);
 
580
                                        
 
581
                                        if (shade_light) {
 
582
                                                cr.Color = new Cairo.Color (.9, .95, 1, .5);
 
583
                                        } else {
 
584
                                                double opacity = (BounceTime - dockItem.TimeSinceClick).TotalMilliseconds / 
 
585
                                                        BounceTime.TotalMilliseconds - .7;
 
586
                                                
 
587
                                                cr.Color = new Cairo.Color (0, 0, 0, opacity);
 
588
                                        }
 
589
                                                
 
590
                                        cr.Operator = Operator.Atop;
 
591
                                        cr.Fill ();
 
592
                                        cr.Operator = Operator.Over;
 
593
                                }
 
594
                                
 
595
                                if (scale != 1)
 
596
                                        cr.IdentityMatrix ();
 
597
                        } else {
 
598
                                // since these dont scale, we have some extra work to do to keep them
 
599
                                // centered
 
600
                                cr.SetSource (iconSurface, 
 
601
                                              (int) iconPosition.X, (int) center.Y - (dockItem.Height >> 1));
 
602
                                cr.Paint ();
 
603
                        }
 
604
                        
 
605
                        if (0 < dockItem.WindowCount || dockItem.NeedsAttention) {
 
606
                                Gdk.Point location;
 
607
                                switch (DockPreferences.Orientation) {
 
608
                                case DockOrientation.Bottom:
 
609
                                        location = new Gdk.Point ((int) center.X, Height - 1);  
 
610
                                        break;
 
611
                                case DockOrientation.Top:
 
612
                                default:
 
613
                                        location = new Gdk.Point ((int) center.X, 1);
 
614
                                        break;
 
615
                                }
 
616
                                DrawGlowIndicator (cr, location, dockItem.NeedsAttention, dockItem.WindowCount);
 
617
                        }
 
618
                        
 
619
                        // we do a null check here to allow things like separator items to supply
 
620
                        // a null.  This allows us to draw nothing at all instead of rendering a
 
621
                        // blank surface (which is slow)
 
622
                        if (!PopupMenu.Visible && hovered &&
 
623
                            CursorIsOverDockArea && dockItem.GetTextSurface (cr.Target) != null && 
 
624
                            !DnDTracker.GtkDragging && !DnDTracker.DragResizing) {
 
625
 
 
626
                                Gdk.Point textPoint;
 
627
                                Surface textSurface = dockItem.GetTextSurface (cr.Target);
 
628
                                textPoint.X = PositionProvider.IconUnzoomedPosition (icon).X - (dockItem.TextSurfaceSize.Width >> 1);
 
629
                                textPoint.X = Math.Max (0, Math.Min (Width - dockItem.TextSurfaceSize.Width, textPoint.X));
 
630
                                
 
631
                                if (DockPreferences.Orientation == DockOrientation.Top)
 
632
                                        textPoint.Y = (int) (DockPreferences.ZoomPercent * IconSize) + 10;
 
633
                                else
 
634
                                        textPoint.Y = Height - (int) (DockPreferences.ZoomPercent * IconSize) - 38;
 
635
                                
 
636
                                textSurface.Show (cr, textPoint.X, textPoint.Y);
 
637
                        }
 
638
                }
 
639
                
 
640
                void DrawGlowIndicator (Context cr, Gdk.Point location, bool urgent, int numberOfWindows)
 
641
                {
 
642
                        if (DockPreferences.IndicateMultipleWindows && 1 < numberOfWindows) {
 
643
                                DrawSingleIndicator (cr, location.RelativeMovePoint (3, RelativeMove.RelativeLeft), urgent);
 
644
                                DrawSingleIndicator (cr, location.RelativeMovePoint (3, RelativeMove.RelativeRight), urgent);
 
645
                        } else if (0 < numberOfWindows || urgent) {
 
646
                                DrawSingleIndicator (cr, location, urgent);
 
647
                        }
 
648
                }
 
649
                
 
650
                void DrawSingleIndicator (Context cr, Gdk.Point location, bool urgent)
 
651
                {
 
652
                        if (urgent) {
 
653
                                cr.SetSource (GetUrgentIndicator (cr.Target), location.X - UrgentIndicatorSize, location.Y - UrgentIndicatorSize);
 
654
                        } else {
 
655
                                cr.SetSource (GetIndicator (cr.Target), location.X - IndicatorSize, location.Y - IndicatorSize);
 
656
                        }
 
657
 
 
658
                        cr.Paint ();
 
659
                }
 
660
 
 
661
                Gdk.Rectangle GetDockArea ()
 
662
                {
 
663
                        Gdk.Rectangle rect;
 
664
                        
 
665
                        // this method is more than somewhat slow on the complexity scale, we want to avoid doing it
 
666
                        // more than we have to.  Further, when we do call it, we should always check for this shortcut.
 
667
                        if (DockIconOpacity == 0 || ZoomIn == 0)
 
668
                                rect = MinimumDockArea;
 
669
                        else
 
670
                                rect = PositionProvider.DockArea (ZoomIn, Cursor);
 
671
 
 
672
                        int minWidth = 10 * rect.Height;
 
673
                        int maxWidth = LayoutUtils.MonitorGeometry ().Width;
 
674
                        int dockWidth = 0;
 
675
                                
 
676
                        if (PainterOverlayVisible && Painter != null) {
 
677
                                dockWidth = Math.Min (Painter.Width, maxWidth);
 
678
                        } else if (!PainterOverlayVisible && LastPainter != null) {
 
679
                                dockWidth = Math.Min (LastPainter.Width, maxWidth);
 
680
                        } else {
 
681
                                dockWidth = Math.Max (rect.Width, minWidth);
 
682
                        }
 
683
                        
 
684
                        if (rect.Width != dockWidth && DockIconOpacity < 1) {
 
685
                                int difference = dockWidth - rect.Width;
 
686
                                int alpha = (int) (difference * PainterOpacity);
 
687
                                rect.X -= alpha / 2;
 
688
                                rect.Width += alpha;
 
689
                        }
 
690
                        
 
691
                        return rect;
 
692
                }
 
693
                
 
694
                Surface GetIndicator (Surface similar)
 
695
                {
 
696
                        if (indicator == null) {
 
697
                                Style style = window.Style;
 
698
                                Gdk.Color color = style.Backgrounds [(int) StateType.Selected].SetMinimumValue (100);
 
699
 
 
700
                                indicator = similar.CreateSimilar (similar.Content, IndicatorSize * 2, IndicatorSize * 2);
 
701
                                Context cr = new Context (indicator);
 
702
 
 
703
                                double x = IndicatorSize;
 
704
                                double y = x;
 
705
                                
 
706
                                cr.MoveTo (x, y);
 
707
                                cr.Arc (x, y, IndicatorSize, 0, Math.PI * 2);
 
708
                                
 
709
                                RadialGradient rg = new RadialGradient (x, y, 0, x, y, IndicatorSize);
 
710
                                rg.AddColorStop (0, new Cairo.Color (1, 1, 1, 1));
 
711
                                rg.AddColorStop (.10, color.ConvertToCairo (1.0));
 
712
                                rg.AddColorStop (.20, color.ConvertToCairo (.60));
 
713
                                rg.AddColorStop (.25, color.ConvertToCairo (.25));
 
714
                                rg.AddColorStop (.50, color.ConvertToCairo (.15));
 
715
                                rg.AddColorStop (1.0, color.ConvertToCairo (0.0));
 
716
                                
 
717
                                cr.Pattern = rg;
 
718
                                cr.Fill ();
 
719
                                rg.Destroy ();
 
720
 
 
721
                                (cr as IDisposable).Dispose ();
 
722
                        }
 
723
                        return indicator;
 
724
                }
 
725
 
 
726
                Surface GetUrgentIndicator (Surface similar)
 
727
                {
 
728
                        if (urgent_indicator == null) {
 
729
                                Style style = Docky.Interface.DockWindow.Window.Style;
 
730
                                Gdk.Color color = style.Backgrounds [(int) StateType.Selected];
 
731
                                byte r, g, b; 
 
732
                                double h, s, v; 
 
733
 
 
734
                                r = (byte) ((color.Red)   >> 8);
 
735
                                g = (byte) ((color.Green) >> 8);
 
736
                                b = (byte) ((color.Blue)  >> 8);
 
737
                                Do.Interface.Util.Appearance.RGBToHSV (r, g, b, out h, out s, out v);
 
738
 
 
739
                                // see if the theme color is too close to red and if so use
 
740
                                // blue instead
 
741
                                if (h <= 45 || h >= 315)
 
742
                                        color = new Cairo.Color (0.5, 0.6, 1.0, 1.0).ConvertToGdk ();
 
743
                                else
 
744
                                        color = new Cairo.Color (1.0, 0.3, 0.3, 1.0).ConvertToGdk ();
 
745
 
 
746
                                urgent_indicator = similar.CreateSimilar (similar.Content, UrgentIndicatorSize * 2, UrgentIndicatorSize * 2);
 
747
                                Context cr = new Context (urgent_indicator);
 
748
 
 
749
                                double x = UrgentIndicatorSize;
 
750
                                double y = x;
 
751
                                
 
752
                                cr.MoveTo (x, y);
 
753
                                cr.Arc (x, y, UrgentIndicatorSize, 0, Math.PI * 2);
 
754
                                
 
755
                                RadialGradient rg = new RadialGradient (x, y, 0, x, y, UrgentIndicatorSize);
 
756
                                rg.AddColorStop (0, new Cairo.Color (1, 1, 1, 1));
 
757
                                rg.AddColorStop (.10, color.ConvertToCairo (1.0));
 
758
                                rg.AddColorStop (.20, color.ConvertToCairo (.60));
 
759
                                rg.AddColorStop (.35, color.ConvertToCairo (.35));
 
760
                                rg.AddColorStop (.50, color.ConvertToCairo (.25));
 
761
                                rg.AddColorStop (1.0, color.ConvertToCairo (0.0));
 
762
                                
 
763
                                cr.Pattern = rg;
 
764
                                cr.Fill ();
 
765
                                rg.Destroy ();
 
766
 
 
767
                                (cr as IDisposable).Dispose ();
 
768
                        }
 
769
                        return urgent_indicator;
 
770
                }
 
771
 
 
772
                ClickAnimationType IconAnimation (int icon)
 
773
                {
 
774
                        return (DockItems [icon].TimeSinceClick < BounceTime) ? 
 
775
                                DockItems [icon].AnimationType : ClickAnimationType.None;
 
776
                }
 
777
                
 
778
                void IconZoomedPosition (int icon, out PointD center, out double zoom)
 
779
                {
 
780
                        PositionProvider.IconZoomedPosition (icon, ZoomIn, Cursor, out center, out zoom);
 
781
                }
 
782
 
 
783
                Surface GetOverlaySurface (Context similar)
 
784
                {
 
785
                        if (Painter != null && Painter.DoubleBuffer) {
 
786
                                if (!painter_surfaces.ContainsKey (Painter))
 
787
                                        painter_surfaces [Painter] = similar.Target.CreateSimilar (similar.Target.Content, 
 
788
                                                                                                   Width, Height);
 
789
                                return painter_surfaces [Painter];
 
790
                        } else {
 
791
                                if (input_area_buffer == null)
 
792
                                        input_area_buffer = similar.Target.CreateSimilar (similar.Target.Content, 
 
793
                                                                                          Width, Height);
 
794
                                return input_area_buffer;
 
795
                        }
 
796
                }
 
797
 
 
798
                protected override bool OnExposeEvent(EventExpose evnt)
 
799
                {
 
800
                        if (!IsDrawable)
 
801
                                return false;
 
802
                        
 
803
                        rendering = true;
 
804
                        zoom_in_buffer = null;
 
805
                        RenderTime = DateTime.UtcNow;
 
806
                        Context cr;
 
807
                        if (backbuffer == null) {
 
808
                                cr = Gdk.CairoHelper.Create (GdkWindow);
 
809
                                backbuffer = cr.Target.CreateSimilar (cr.Target.Content, Width, Height);
 
810
                                
 
811
                                cr.Target.Destroy ();
 
812
                                (cr.Target as IDisposable).Dispose ();
 
813
                                (cr as IDisposable).Dispose ();
 
814
                        }
 
815
                        
 
816
                        cr = new Cairo.Context (backbuffer);
 
817
                        cr.AlphaFill ();
 
818
 
 
819
                        if (DockServices.ItemsService.UpdatesEnabled) {
 
820
                                if (!first_render_set) {
 
821
                                        FirstRenderTime = DateTime.UtcNow;
 
822
                                        first_render_set = true;
 
823
                                }
 
824
                                DrawDock (cr);
 
825
                        }
 
826
                        (cr as IDisposable).Dispose ();
 
827
                        
 
828
                        cr = Gdk.CairoHelper.Create (GdkWindow);
 
829
                        
 
830
                        int vert = VerticalOffset;
 
831
                        Gdk.Point finalTarget = new Gdk.Point (0, 0).RelativeMovePoint (vert, RelativeMove.Outward);
 
832
                        
 
833
                        cr.SetSource (backbuffer, finalTarget.X, finalTarget.Y);
 
834
                        
 
835
                        cr.Operator = Operator.Source;
 
836
                        cr.Paint ();
 
837
                        
 
838
                        cr.Target.Destroy ();
 
839
                        ((IDisposable)cr.Target).Dispose ();
 
840
                        ((IDisposable)cr).Dispose ();
 
841
                        
 
842
                        rendering = false;
 
843
                        return true;
 
844
                }
 
845
                
 
846
                protected override void OnStyleSet (Gtk.Style previous_style)
 
847
                {
 
848
                        if (indicator != null) {
 
849
                                indicator.Destroy ();
 
850
                                indicator = null;
 
851
                        }
 
852
                        
 
853
                        if (urgent_indicator != null) {
 
854
                                urgent_indicator.Destroy ();
 
855
                                urgent_indicator = null;
 
856
                        }
 
857
                        
 
858
                        RequestFullRender ();
 
859
                        
 
860
                        base.OnStyleSet (previous_style);
 
861
                }
 
862
                
 
863
                void RequestIconRender (AbstractDockItem item)
 
864
                {
 
865
                        if (RenderData != null) {
 
866
                                RenderData.RenderItems.Add (item);
 
867
                        }
 
868
                }
 
869
                
 
870
                void RequestFullRender ()
 
871
                {
 
872
                        if (RenderData != null) {
 
873
                                RenderData.ForceFullRender = true;
 
874
                        }
 
875
                }
 
876
                
 
877
                void ResetBuffers()
 
878
                {
 
879
                        if (backbuffer != null) {
 
880
                                backbuffer.Destroy ();
 
881
                                backbuffer = null;
 
882
                        }
 
883
                        
 
884
                        if (dock_icon_buffer != null) {
 
885
                                dock_icon_buffer.Destroy ();
 
886
                                dock_icon_buffer = null;
 
887
                        }
 
888
                        
 
889
                        if (input_area_buffer != null) {
 
890
                                input_area_buffer.Destroy ();
 
891
                                input_area_buffer = null;
 
892
                        }
 
893
                        
 
894
                        if (painter_surfaces != null) {
 
895
                                foreach (Surface sr in painter_surfaces.Values) {
 
896
                                        sr.Destroy ();
 
897
                                }
 
898
                                painter_surfaces.Clear ();
 
899
                        }
 
900
                        
 
901
                        RequestFullRender ();
 
902
                }
 
903
        }
 
904
}