20
20
using System.Collections.Generic;
21
using System.Collections.ObjectModel;
22
using System.Text.RegularExpressions;
24
using System.Diagnostics;
33
using Do.Interface.CairoUtils;
36
31
using Docky.Utilities;
37
using Docky.Interface.Renderers;
32
using Docky.Interface.Menus;
33
using Docky.Interface.Painters;
39
35
namespace Docky.Interface
43
public class DockArea : Gtk.DrawingArea
39
internal partial class DockArea : Gtk.DrawingArea
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);
54
const int WindowHeight = 300;
55
43
const uint OffDockWakeupTime = 250;
56
44
const uint OnDockWakeupTime = 20;
58
46
TimeSpan BounceTime = new TimeSpan (0, 0, 0, 0, 700);
59
47
TimeSpan InsertAnimationTime = new TimeSpan (0, 0, 0, 0, 150*5);
61
#region private variables
62
Gdk.Point cursor, drag_start_point;
64
Gdk.CursorType cursor_type = CursorType.LeftPtr;
66
DateTime enter_time = DateTime.UtcNow - new TimeSpan (0, 10, 0);
67
DateTime interface_change_time = DateTime.UtcNow - new TimeSpan (0, 10, 0);
70
bool gtk_drag_source_set;
71
bool previous_icon_animation_needed = true;
49
#region Private Variables
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);
74
int drag_start_icon_size;
75
int remove_drag_start_x;
76
int previous_item_count;
79
59
uint animation_timer;
87
DockItemProvider item_provider;
88
Surface backbuffer, input_area_buffer, dock_icon_buffer;
90
Matrix default_matrix;
93
#region public properties
94
public bool InputInterfaceVisible { get; set; }
66
#region Public Properties
97
69
/// The width of the docks window, but not the visible dock
116
86
/// The height of the visible dock
118
88
public int DockHeight {
119
get { return DockPreferences.AutoHide || DockPreferences.AllowOverlap ? 0 : MinimumDockArea.Height; }
89
get { return PositionProvider.DockHeight; }
122
public Pane CurrentPane {
92
public uint[] StrutRequest {
124
return State.CurrentPane;
127
State.CurrentPane = value;
128
AnimatedDraw (false);
132
public bool ThirdPaneVisible {
133
get { return State.ThirdPaneVisible; }
135
if (State.ThirdPaneVisible == value)
137
State.ThirdPaneVisible = value;
138
AnimatedDraw (false);
94
uint[] values = new uint[12];
95
Gdk.Rectangle geo = LayoutUtils.MonitorGemonetry ();
97
if (DockPreferences.AutoHide || DockPreferences.AllowOverlap)
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);
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);
143
public new DockState State { get; set; }
145
118
DockAnimationState AnimationState { get; set; }
147
120
ItemPositionProvider PositionProvider { get; set; }
149
122
new DockItemMenu PopupMenu { get; set; }
151
bool GtkDragging { get; set; }
153
bool FullRenderFlag { get; set; }
155
SummonModeRenderer SummonRenderer { get; set; }
157
List<BaseDockItem> DockItems {
158
get { return item_provider.DockItems; }
124
bool CursorIsOverDockArea { get; set; }
126
ModifierType CursorModifier { get; set; }
128
ReadOnlyCollection<AbstractDockItem> DockItems {
129
get { return DockServices.ItemsService.DockItems; }
161
BaseDockItem CurrentDockItem {
132
AbstractDockItem CurrentDockItem {
163
try { return DockItems [PositionProvider.IndexAtPosition (Cursor.X)]; }
134
try { return DockItems [PositionProvider.IndexAtPosition (Cursor)]; }
164
135
catch { return null; }
168
139
TimeSpan SummonTime {
170
return DockPreferences.SummonTime;
175
/// Returns the zoom in percentage (0 through 1)
179
if (drag_resizing && drag_start_point != Cursor)
182
double zoom = Math.Min (1, (DateTime.UtcNow - enter_time).TotalMilliseconds / BaseAnimationTime.TotalMilliseconds);
183
if (CursorIsOverDockArea) {
184
if (DockPreferences.AutoHide)
190
if (InputInterfaceVisible)
191
zoom = zoom * DockIconOpacity;
198
/// The overall offset of the dock as a whole
203
// we never hide in these conditions
204
if (!DockPreferences.AutoHide || drag_resizing || InputAreaOpacity == 1)
207
if (InputAreaOpacity > 0) {
208
if (CursorIsOverDockArea) {
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));
215
if (InputInterfaceVisible)
218
offset = Math.Min (1, (DateTime.UtcNow - enter_time).TotalMilliseconds / SummonTime.TotalMilliseconds);
219
if (CursorIsOverDockArea)
222
return (int) (offset * MinimumDockArea.Height * 1.5);
227
/// Determins the opacity of the icons on the normal dock
229
double DockIconOpacity {
231
if (SummonTime < DateTime.UtcNow - interface_change_time) {
232
if (InputInterfaceVisible)
237
double total_time = (DateTime.UtcNow - interface_change_time).TotalMilliseconds;
238
if (InputInterfaceVisible) {
239
return 1 - (total_time / SummonTime.TotalMilliseconds);
241
return total_time / SummonTime.TotalMilliseconds;
246
double InputAreaOpacity {
247
get { return 1 - DockIconOpacity; }
251
get { return DockPreferences.IconSize; }
140
get { return DockPreferences.SummonTime; }
262
151
bool cursorIsOverDockArea = CursorIsOverDockArea;
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 ();
161
dockRegion = MinimumDockArea;
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);
273
Gdk.Rectangle small = MinimumDockArea;
274
167
if (DockPreferences.AutoHide) {
275
small.Y += small.Height - 1;
168
switch (DockPreferences.Orientation) {
169
case DockOrientation.Bottom:
170
dockRegion.Y += dockRegion.Height - 1;
171
dockRegion.Height = 1;
173
case DockOrientation.Top:
174
dockRegion.Height = 1;
278
CursorIsOverDockArea = small.Contains (cursor);
178
CursorIsOverDockArea = dockRegion.Contains (cursor);
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);
296
bool CursorNearTopDraggableEdge {
298
return Cursor.Y > MinimumDockArea.Y && CursorIsOverDockArea && CurrentDockItem is SeparatorItem;
302
bool CursorNearLeftEdge {
304
return CursorIsOverDockArea && Math.Abs (Cursor.X - MinimumDockArea.X) < 8;
308
bool CursorNearRightEdge {
310
return CursorIsOverDockArea && Math.Abs (Cursor.X - (MinimumDockArea.X + MinimumDockArea.Width)) < 8;
314
bool CursorNearDraggableEdge {
316
return CursorNearTopDraggableEdge ||
317
CursorNearRightEdge ||
322
DragEdge CurrentDragEdge {
324
if (CursorNearTopDraggableEdge)
326
else if (CursorNearLeftEdge)
327
return DragEdge.Left;
328
else if (CursorNearRightEdge)
329
return DragEdge.Right;
330
return DragEdge.None;
334
#region Animation properties
335
bool CursorIsOverDockArea { get; set; }
337
bool IconAnimationNeeded {
339
return AnimationState ["BounceAnimationNeeded"] ||
340
AnimationState ["IconInsertAnimationNeeded"] ||
341
AnimationState ["UrgentAnimationNeeded"];
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 &&
361
198
public DockArea (DockWindow window) : base ()
363
default_matrix = new Matrix ();
364
200
this.window = window;
367
geo = LayoutUtils.MonitorGemonetry ();
370
SetSizeRequest (Width, Height);
372
item_provider = new DockItemProvider ();
373
State = new DockState ();
374
PositionProvider = new ItemPositionProvider (item_provider, new Gdk.Rectangle (0, 0, Width, Height));
204
PositionProvider = new ItemPositionProvider (this);
376
206
AnimationState = new DockAnimationState ();
377
207
BuildAnimationStateEngine ();
379
SummonRenderer = new SummonModeRenderer (this);
380
209
PopupMenu = new DockItemMenu ();
382
211
Cursor = new Gdk.Point (-1, -1);
384
213
this.SetCompositeColormap ();
386
AddEvents ((int) EventMask.PointerMotionMask |
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);
392
223
DoubleBuffered = false;
394
228
RegisterEvents ();
395
229
RegisterGtkDragDest ();
422
273
void UnregisterEvents ()
424
item_provider.DockItemsChanged -= OnDockItemsChanged;
425
item_provider.ItemNeedsUpdate -= HandleItemNeedsUpdate;
275
DockServices.ItemsService.DockItemsChanged -= OnDockItemsChanged;
276
DockServices.ItemsService.ItemNeedsUpdate -= HandleItemNeedsUpdate;
278
DockPreferences.MonitorChanged -= HandleMonitorChanged;
279
DockPreferences.IconSizeChanged -= HandleIconSizeChanged;
281
DockServices.PainterService.PainterShowRequest -= HandlePainterShowRequest;
282
DockServices.PainterService.PainterHideRequest -= HandlePainterHideRequest;
284
Screen.SizeChanged -= HandleSizeChanged;
427
286
PopupMenu.Hidden -= OnDockItemMenuHidden;
428
287
PopupMenu.Shown -= OnDockItemMenuShown;
430
289
Services.Core.UniverseInitialized -= HandleUniverseInitialized;
432
Wnck.Screen.Default.ViewportsChanged -= OnWnckViewportsChanged;
435
292
void BuildAnimationStateEngine ()
437
AnimationState.AddCondition ("IconInsertAnimationNeeded",
294
AnimationState.AddCondition (Animations.IconInsert,
438
295
() => DockItems.Any (di => di.TimeSinceAdd < InsertAnimationTime));
440
AnimationState.AddCondition ("PaneChangeAnimationNeeded",
441
() => (DateTime.UtcNow - State.CurrentPaneTime) < BaseAnimationTime);
443
AnimationState.AddCondition ("ZoomAnimationNeeded",
297
AnimationState.AddCondition (Animations.Zoom,
444
298
() => (CursorIsOverDockArea && ZoomIn != 1) || (!CursorIsOverDockArea && ZoomIn != 0));
446
AnimationState.AddCondition ("OpenAnimationNeeded",
300
AnimationState.AddCondition (Animations.Open,
447
301
() => DateTime.UtcNow - enter_time < SummonTime ||
448
302
DateTime.UtcNow - interface_change_time < SummonTime);
450
AnimationState.AddCondition ("BounceAnimationNeeded",
304
AnimationState.AddCondition (Animations.Bounce,
451
305
() => DockItems.Any (di => di.TimeSinceClick <= BounceTime));
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));
459
AnimationState.AddCondition ("UrgentRecentChange",
460
() => DockItems.Where (di => di is IDockAppItem)
461
.Cast<IDockAppItem> ()
462
.Any (dai => DateTime.UtcNow - dai.AttentionRequestStartTime < BounceTime));
464
AnimationState.AddCondition ("InputModeChangeAnimationNeeded",
307
AnimationState.AddCondition (Animations.UrgencyChanged,
308
() => DockItems.Any (di => DateTime.UtcNow - di.AttentionRequestStartTime < BounceTime));
310
AnimationState.AddCondition (Animations.InputModeChanged,
465
311
() => DateTime.UtcNow - interface_change_time < SummonTime);
467
AnimationState.AddCondition ("InputModeSlideAnimationNeeded",
468
() => DateTime.UtcNow - State.LastCursorChange < BaseAnimationTime);
470
AnimationState.AddCondition ("ThirdPaneVisibilityAnimationNeeded",
471
() => DateTime.UtcNow - State.ThirdChangeTime < BaseAnimationTime);
474
314
void HandleItemNeedsUpdate (object sender, UpdateRequestArgs args)
476
316
if (args.Type == UpdateRequestType.NeedsAttentionSet) {
477
317
SetParentInputMask ();
322
void HandleMonitorChanged()
327
void HandleSizeChanged(object sender, EventArgs e)
336
PositionProvider.ForceUpdate ();
337
SetParentInputMask ();
339
window.DelaySetStruts ();
482
342
void HandleUniverseInitialized(object sender, EventArgs e)
484
344
GLib.Timeout.Add (2000, delegate {
345
DockServices.ItemsService.ForceUpdate ();
485
346
SetIconRegions ();
490
void RegisterGtkDragSource ()
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);
497
void RegisterGtkDragDest ()
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);
503
void UnregisterGtkDragSource ()
505
gtk_drag_source_set = false;
506
Gtk.Drag.SourceUnset (this);
351
void HandleIconSizeChanged()
356
void HandlePaintNeeded (object sender, PaintNeededArgs args)
358
if (sender != Painter && sender != LastPainter) return;
361
if (AnimationState.Contains (Animations.Painter))
362
AnimationState.RemoveCondition (Animations.Painter);
363
TimeSpan span = args.AnimationLength;
365
DateTime current_time = DateTime.UtcNow;
366
AnimationState.AddCondition (Animations.Painter, () => DateTime.UtcNow - current_time < span);
371
void HandlePainterHideRequest(object sender, EventArgs e)
373
IDockPainter painter = sender as IDockPainter;
374
if (Painter != painter)
378
PainterOverlayVisible = false;
379
interface_change_time = DateTime.UtcNow;
381
SetParentInputMask ();
384
GLib.Timeout.Add (500, () => {
385
DockServices.ItemsService.ForceUpdate ();
389
window.UnpresentWindow ();
390
RegisterGtkDragSource ();
393
void HandlePainterShowRequest(object sender, EventArgs e)
395
IDockPainter painter = sender as IDockPainter;
396
if (Painter == painter)
399
if (Painter == null || Painter.Interruptable) {
401
Painter.Interrupt ();
403
PainterOverlayVisible = true;
404
interface_change_time = DateTime.UtcNow;
406
SetParentInputMask ();
409
painter.Interrupt ();
412
window.PresentWindow ();
413
UnregisterGtkDragSource ();
509
416
void ResetCursorTimer ()
558
void DrawDrock (Context cr)
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;
565
Gdk.Rectangle dockArea = GetDockArea ();
566
DockBackgroundRenderer.RenderDockBackground (cr, dockArea);
568
if (InputAreaOpacity > 0) {
569
if (input_area_buffer == null)
570
input_area_buffer = cr.Target.CreateSimilar (cr.Target.Content, Width, Height);
572
using (Context input_cr = new Context (input_area_buffer)) {
573
input_cr.AlphaFill ();
574
SummonRenderer.RenderSummonMode (input_cr, dockArea);
577
cr.SetSource (input_area_buffer);
578
cr.PaintWithAlpha (InputAreaOpacity);
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);
586
using (Context input_cr = new Context (dock_icon_buffer)) {
587
DrawIcons (input_cr);
590
cr.SetSource (dock_icon_buffer, 0, IconSize * (1 - DockIconOpacity));
591
cr.PaintWithAlpha (DockIconOpacity);
595
void DrawIcons (Context cr)
598
StoreFastRenderData ();
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"])
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);
612
rightItem = DockItems.Count - 1;
615
double leftZoom, rightZoom;
617
// calculates the actual x postions of the borders of the left and right most changing icons
621
IconZoomedPosition (leftItem, out leftX, out leftZoom);
622
leftX -= (int) (leftZoom * DockItems [leftItem].Width / 2) + DockPreferences.IconBorderWidth;
625
if (rightItem == DockItems.Count - 1) {
628
IconZoomedPosition (rightItem, out rightX, out rightZoom);
629
rightX += (int) (rightZoom * DockItems [rightItem].Width / 2) + DockPreferences.IconBorderWidth;
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;
639
cr.Operator = Operator.Over;
641
for (int i = leftItem; i <= rightItem; i++)
645
FullRenderFlag = false;
646
// less code, twice as slow...
648
for (int i = 0; i < DockItems.Count; i++)
653
void StoreFastRenderData ()
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;
663
void DrawIcon (Context cr, int icon)
665
// Don't draw the icon we are dragging around
667
int item = PositionProvider.IndexAtPosition (remove_drag_start_x);
668
if (item == icon && item_provider.ItemCanBeMoved (item))
674
IconZoomedPosition (icon, out center, out zoom);
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;
680
ClickAnimationType animationType = IconAnimation (icon);
682
// we will set this flag now
683
bool drawUrgency = false;
684
if (animationType == ClickAnimationType.Bounce) {
686
y -= Math.Abs (30 * Math.Sin (DockItems [icon].TimeSinceClick.TotalMilliseconds * Math.PI / (BounceTime.TotalMilliseconds / 2)));
688
IDockAppItem dai = DockItems [icon] as IDockAppItem;
689
if (dai != null && dai.NeedsAttention) {
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));
698
double scale = zoom/DockPreferences.IconQuality;
700
if (DockItems [icon].Scalable) {
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.
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);
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);
716
cr.Color = new Cairo.Color (.9, .95, 1, .5);
718
double opacity = (BounceTime - DockItems [icon].TimeSinceClick).TotalMilliseconds / BounceTime.TotalMilliseconds - .7;
719
cr.Color = new Cairo.Color (0, 0, 0, opacity);
722
cr.Operator = Operator.Atop;
724
cr.Operator = Operator.Over;
728
cr.Matrix = default_matrix;
730
// since these dont scale, we have some extra work to do to keep them
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);
738
if (0 < DockItems [icon].WindowCount) {
739
// draws a simple triangle indicator. Should be replaced by something
741
Util.DrawGlowIndicator (cr, center, Height - 1, drawUrgency, DockItems [icon].WindowCount);
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) {
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);
756
ClickAnimationType IconAnimation (int icon)
758
return (DockItems [icon].TimeSinceClick < BounceTime) ? DockItems [icon].AnimationType : ClickAnimationType.None;
761
void IconZoomedPosition (int icon, out int x, out double zoom)
763
PositionProvider.IconZoomedPosition (icon, ZoomIn, Cursor, out x, out zoom);
766
Gdk.Rectangle GetDockArea ()
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;
773
return PositionProvider.DockArea (ZoomIn, Cursor);
776
void OnDockItemsChanged (IEnumerable<BaseDockItem> items)
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 ();
485
void OnDockItemsChanged (IEnumerable<AbstractDockItem> items)
778
487
DockPreferences.MaxIconSize = (int) (((double) Width / MinimumDockArea.Width) * IconSize);
780
489
SetIconRegions ();
784
493
void OnDockItemMenuHidden (object o, System.EventArgs args)
828
552
bool cursorMoveWarrantsDraw = CursorIsOverDockArea && old_cursor_location.X != Cursor.X;
830
554
if (drag_resizing || cursorMoveWarrantsDraw)
831
AnimatedDraw (drag_resizing);
836
protected override bool OnDragMotion (Gdk.DragContext context, int x, int y, uint time)
839
AnimatedDraw (false);
840
return base.OnDragMotion (context, x, y, time);
843
protected override void OnDragDataReceived (Gdk.DragContext context, int x, int y, Gtk.SelectionData selectionData,
844
uint info, uint time)
846
if (!CursorIsOverDockArea) return;
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');
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)));
858
uriList.Where (uri => uri.StartsWith ("file://"))
859
.ForEach (uri => item_provider.AddCustomItem (uri.Substring ("file://".Length)));
862
base.OnDragDataReceived (context, x, y, selectionData, info, time);
865
protected override void OnDragBegin (Gdk.DragContext context)
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);
872
if (item == -1 || !item_provider.ItemCanBeMoved (item)) {
873
pbuf = IconProvider.PixbufFromIconName ("gtk-remove", DockPreferences.IconSize);
875
pbuf = DockItems [item].GetDragPixbuf ();
879
Gtk.Drag.SetIconPixbuf (context, pbuf, pbuf.Width / 2, pbuf.Height / 2);
880
base.OnDragBegin (context);
883
protected override void OnDragEnd (Gdk.DragContext context)
885
if (PositionProvider.IndexAtPosition (remove_drag_start_x) != -1) {
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);
896
remove_drag_start_x = -1;
897
base.OnDragEnd (context);
558
protected override bool OnMotionNotifyEvent (Gdk.EventMotion evnt)
561
SetupCursor ((int) evnt.X, (int) evnt.Y, evnt.State);
562
cursor_update = DateTime.UtcNow;
563
return base.OnMotionNotifyEvent (evnt);
902
566
protected override bool OnEnterNotifyEvent (Gdk.EventCrossing evnt)
904
569
ManualCursorUpdate ();
905
570
return base.OnEnterNotifyEvent (evnt);
908
protected override bool OnExposeEvent(EventExpose evnt)
910
bool ret_val = base.OnExposeEvent (evnt);
912
if (!IsDrawable || window.WindowHideOffset () == Height)
916
if (backbuffer == null) {
917
cr = Gdk.CairoHelper.Create (GdkWindow);
918
backbuffer = cr.Target.CreateSimilar (cr.Target.Content, Width, Height);
920
cr.Target.Destroy ();
921
(cr.Target as IDisposable).Dispose ();
922
(cr as IDisposable).Dispose ();
925
cr = new Cairo.Context (backbuffer);
927
cr.Operator = Operator.Over;
929
if (item_provider.UpdatesEnabled)
931
(cr as IDisposable).Dispose ();
933
Context cr2 = Gdk.CairoHelper.Create (GdkWindow);
934
cr2.SetSource (backbuffer, 0, VerticalOffset);
935
cr2.Operator = Operator.Source;
938
cr2.Target.Destroy ();
939
((IDisposable)cr2.Target).Dispose ();
940
((IDisposable)cr2).Dispose ();
945
protected override bool OnMotionNotifyEvent(EventMotion evnt)
948
return base.OnMotionNotifyEvent (evnt);
951
void ConfigureCursor ()
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 ();
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);
964
} else if (!gtk_drag_source_set && !drag_resizing && !CursorNearDraggableEdge) {
965
RegisterGtkDragSource ();
966
if (cursor_type != CursorType.LeftPtr)
967
SetCursor (CursorType.LeftPtr);
971
void SetCursor (Gdk.CursorType type)
974
Gdk.Cursor tmp_cursor = new Gdk.Cursor (type);
975
GdkWindow.Cursor = tmp_cursor;
976
tmp_cursor.Dispose ();
979
573
protected override bool OnButtonPressEvent (Gdk.EventButton evnt)
981
575
if (CursorNearDraggableEdge)
984
578
return base.OnButtonPressEvent (evnt);
581
public void ProxyButtonReleaseEvent (Gdk.EventButton evnt)
583
HandleButtonReleaseEvent (evnt);
987
586
protected override bool OnButtonReleaseEvent (Gdk.EventButton evnt)
989
bool ret_val = base.OnButtonPressEvent (evnt);
588
bool result = base.OnButtonPressEvent (evnt);
589
HandleButtonReleaseEvent (evnt);
594
private void HandleButtonReleaseEvent (Gdk.EventButton evnt)
991
596
// lets not do anything in this case
992
597
if (drag_resizing) {
997
if (InputInterfaceVisible) {
998
switch (SummonRenderer.GetClickEvent (GetDockArea ())) {
999
case SummonClickEvent.AddItemToDock:
1000
item_provider.AddCustomItem (State [State.CurrentPane]);
1001
window.RequestClickOff ();
1003
case SummonClickEvent.None:
602
if (PainterOverlayVisible) {
603
Painter.Clicked (GetDockArea (), Cursor);
604
if (PainterOverlayVisible && !GetDockArea ().Contains (Cursor)) {
1007
if (!CursorIsOverDockArea)
1008
window.RequestClickOff ();
1010
int item = PositionProvider.IndexAtPosition ((int) evnt.X); //sometimes clicking is not good!
1011
if (item < 0 || item >= DockItems.Count || !CursorIsOverDockArea || InputInterfaceVisible)
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)
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 ()) {
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);
615
PointD itemPosition_;
617
IconZoomedPosition (PositionProvider.IndexAtPosition (Cursor), out itemPosition_, out itemZoom);
619
Gdk.Point itemPosition = new Gdk.Point ((int) itemPosition_.X, (int) itemPosition_.Y);
621
itemPosition = itemPosition.RelativeMovePoint ((int) (IconSize * itemZoom * .9 * .5), RelativeMove.Inward);
622
itemPosition = itemPosition.RelativePointToRootPoint (window);
624
PopupMenu.PopUp (CurrentDockItem.Description,
625
(CurrentDockItem as IRightClickable).GetMenuItems (),
1028
632
//send off the clicks
1029
DockItems [item].Clicked (evnt.Button);
1030
AnimatedDraw (false);
1037
drag_start_point = Cursor;
1038
drag_start_icon_size = DockPreferences.IconSize;
1039
drag_resizing = true;
1040
drag_edge = CurrentDragEdge;
1045
drag_edge = DragEdge.None;
1046
drag_resizing = false;
1048
window.SetStruts ();
1050
AnimatedDraw (true);
1052
ResetCursorTimer ();
1055
void HandleDragMotion ()
1058
switch (drag_edge) {
1060
DockPreferences.IconSize = Math.Min (drag_start_icon_size + (drag_start_point.Y - Cursor.Y),
1061
DockPreferences.MaxIconSize);
1064
movement = drag_start_point.X - Cursor.X;
1066
case DragEdge.Right:
1067
movement = Cursor.X - drag_start_point.X;
633
Gdk.Point relative_point = Gdk.Point.Zero;
634
DockItems [item].Clicked (evnt.Button, evnt.State, relative_point);
1071
if (movement > IconSize / 2 + 2) {
1072
DockPreferences.AutomaticIcons++;
1073
} else if (movement < 0 - (IconSize / 2 + 2)) {
1074
DockPreferences.AutomaticIcons--;
641
protected override bool OnScrollEvent (Gdk.EventScroll evnt)
643
int item = PositionProvider.IndexAtPosition ((int) evnt.X, (int) evnt.Y);
1079
drag_start_point.X = Cursor.X;
647
DockItems [item].Scrolled (evnt.Direction);
648
return base.OnScrollEvent (evnt);
1082
651
void SetIconRegions ()
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);
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,
1097
666
DockItems [i].SetIconRegion (area);
1123
int width = (drag_resizing) ? Width : DockWidth;
1124
window.SetInputMask (new Gdk.Rectangle ((Width - width) / 2, Height - offset, width, offset));
1127
public void SetPaneContext (IUIContext context, Pane pane)
1129
State.SetContext (context, pane);
1130
AnimatedDraw (false);
1133
public void ShowInputInterface ()
1135
interface_change_time = DateTime.UtcNow;
1136
InputInterfaceVisible = true;
1138
SetParentInputMask ();
1139
AnimatedDraw (false);
1142
public void HideInputInterface ()
1144
interface_change_time = DateTime.UtcNow;
1145
InputInterfaceVisible = false;
1147
SetParentInputMask ();
1148
AnimatedDraw (false);
1150
GLib.Timeout.Add (500, () => {
1151
item_provider.ForceUpdate ();
1156
public void Reset ()
1159
AnimatedDraw (false);
1162
public void ClearPane (Pane pane)
1164
State.ClearPane (pane);
693
int dockSize = (drag_resizing) ? Width : MinimumDockArea.Width;
695
switch (DockPreferences.Orientation) {
696
case DockOrientation.Bottom:
697
window.SetInputMask (new Gdk.Rectangle ((Width - dockSize) / 2,
702
case DockOrientation.Top:
703
window.SetInputMask (new Gdk.Rectangle ((Width - dockSize) / 2,
711
void InterruptPainter ()
713
if (Painter == null || !Painter.Interruptable) return;
715
Painter.Interrupt ();
717
PainterOverlayVisible = false;
718
interface_change_time = DateTime.UtcNow;
720
RegisterGtkDragSource ();
721
window.UnpresentWindow ();
723
SetParentInputMask ();
1167
727
public override void Dispose ()