3
// Copyright (C) 2008 GNOME Do
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.
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.
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/>.
20
using System.Collections.Generic;
21
using System.Threading;
28
using Do.Interface.CairoUtils;
29
using Do.Interface.Wink;
32
using Docky.Utilities;
34
namespace Docky.Interface
38
public abstract class AbstractDockItem : IDisposable, IEquatable<AbstractDockItem>
40
public event UpdateRequestHandler UpdateNeeded;
42
Surface text_surface, resize_buffer;
43
DockOrientation current_orientation;
44
uint size_changed_timer, redraw_timer;
47
bool time_since_click_overdue;
49
Cairo.Color? average_color;
51
protected int current_size;
53
protected virtual Surface IconSurface { get; set; }
55
Surface SecondaryIconSurface { get; set; }
57
public string Description { get; private set; }
59
public bool Disposed { get; private set; }
61
public Gdk.Rectangle TextSurfaceSize { get; private set; }
64
/// The currently requested animation type
66
public virtual ClickAnimationType AnimationType { get; protected set; }
69
/// The time at which the NeedsAttention flag was set true
71
public virtual DateTime AttentionRequestStartTime { get; protected set; }
74
/// When this item was added to the Dock
76
public virtual DateTime DockAddItem { get; set; }
79
/// The last time this icon was "clicked" that required an animation
81
public virtual DateTime LastClick { get; private set; }
83
public int Position { get; set; }
85
public virtual bool ContainsFocusedWindow {
89
public virtual bool ContainsMinimizedWindow {
94
/// Determines if drop actions will be passed on to the icon
96
public virtual bool IsAcceptingDrops {
101
/// Determines the type of indicator drawn under the item
103
public virtual bool NeedsAttention {
105
return needs_attention;
108
if (value == needs_attention)
110
needs_attention = value;
112
AttentionRequestStartTime = DateTime.UtcNow;
117
/// The Widget of the icon.
119
public virtual int Width {
120
get { return DockPreferences.IconSize; }
124
/// The Height of the icon.
126
public virtual int Height {
127
get { return DockPreferences.IconSize; }
130
public virtual ScalingType ScalingType {
131
get { return ScalingType.Downscaled; }
134
protected virtual string Icon {
139
/// Whether or not to draw an application present indicator
141
public virtual int WindowCount {
145
public TimeSpan TimeSinceClick {
147
if (time_since_click_overdue)
148
return new TimeSpan (1, 0, 0);
150
TimeSpan result = DockArea.RenderTime - LastClick;
152
if (result.TotalMilliseconds > 1000)
153
time_since_click_overdue = true;
159
public TimeSpan TimeSinceAdd {
160
get { return DockArea.RenderTime - DockAddItem; }
163
public AbstractDockItem ()
165
NeedsAttention = false;
167
AttentionRequestStartTime = LastClick = new DateTime (0);
169
DockPreferences.IconSizeChanged += OnIconSizeChanged;
170
DockWindow.Window.StyleSet += HandleStyleSet;
173
void HandleStyleSet(object o, StyleSetArgs args)
178
public Cairo.Color AverageColor ()
180
if (IconSurface == null)
181
return new Cairo.Color (1, 1, 1, 1);
183
if (average_color.HasValue)
184
return average_color.Value;
186
ImageSurface sr = new ImageSurface (Format.ARGB32, current_size, current_size);
187
using (Context cr = new Context (sr)) {
188
cr.Operator = Operator.Source;
189
IconSurface.Show (cr, 0, 0);
198
return new Cairo.Color (1, 1, 1, 1);
206
for (int i=0; i < data.Length - 3; i += 4) {
211
byte max = Math.Max (r, Math.Max (g, b));
212
byte min = Math.Min (r, Math.Min (g, b));
213
double delta = max - min;
221
double score = .2 + .8 * sat;
227
double pixelCount = current_size * current_size * byte.MaxValue;
229
r = (byte) (byte.MaxValue * (rTotal / pixelCount));
230
g = (byte) (byte.MaxValue * (gTotal / pixelCount));
231
b = (byte) (byte.MaxValue * (bTotal / pixelCount));
234
Do.Interface.Util.Appearance.RGBToHSV (r, g, b, out h, out s, out v);
236
s = Math.Min (100, s * 1.3);
237
Do.Interface.Util.Appearance.HSVToRGB (h, s, v, out r, out g, out b);
239
Cairo.Color color = new Cairo.Color ((double) r / byte.MaxValue, (double) g / byte.MaxValue, (double) b / byte.MaxValue);
243
average_color = color;
244
return average_color.Value;
247
protected virtual Pixbuf GetSurfacePixbuf (int size)
252
Gdk.Pixbuf pbuf = IconProvider.PixbufFromIconName (Icon, size);
253
if (pbuf.Height != size && pbuf.Width != size) {
254
double scale = (double)DockPreferences.FullIconSize / Math.Max (pbuf.Width, pbuf.Height);
255
Gdk.Pixbuf temp = pbuf.ScaleSimple ((int) (pbuf.Width * scale), (int) (pbuf.Height * scale), InterpType.Bilinear);
264
/// Called whenever the icon receives a click event
266
/// <param name="button">
267
/// A <see cref="System.UInt32"/>
269
/// <param name="controller">
270
/// A <see cref="IDoController"/>
272
public virtual void Clicked (uint button, ModifierType state, PointD position)
277
protected void SetLastClick ()
279
LastClick = DateTime.UtcNow;
280
time_since_click_overdue = false;
283
public virtual void Scrolled (Gdk.ScrollDirection direction)
287
Surface CopySurface (Surface source, int width, int height)
289
Surface sr = source.CreateSimilar (Cairo.Content.ColorAlpha, width, height);
290
using (Context cr = new Context (sr)) {
291
source.Show (cr, 0, 0);
296
public virtual Pixbuf GetDragPixbuf ()
298
Gdk.Pixbuf pbuf = null;
300
pbuf = GetSurfacePixbuf (DockPreferences.FullIconSize);
304
if (pbuf == null && IconSurface != null) {
305
// now we do something stupid
306
string tmp = System.IO.Path.GetTempFileName ();
307
IconSurface.WriteToPng (tmp);
308
pbuf = new Pixbuf (tmp);
309
System.IO.File.Delete (tmp);
315
public virtual Surface GetIconSurface (Surface similar, int targetSize, out int actualSize)
319
switch (ScalingType) {
320
case ScalingType.HighLow:
321
if (targetSize == DockPreferences.IconSize) {
322
actualSize = DockPreferences.IconSize;
323
if (SecondaryIconSurface == null) {
324
SecondaryIconSurface = MakeIconSurface (similar, actualSize);
325
current_size = actualSize;
327
sr = SecondaryIconSurface;
330
actualSize = DockPreferences.FullIconSize;
332
case ScalingType.Downscaled:
333
actualSize = DockPreferences.FullIconSize;
335
case ScalingType.Upscaled:
336
case ScalingType.None:
338
actualSize = DockPreferences.IconSize;
341
if (IconSurface == null) {
342
IconSurface = MakeIconSurface (similar, actualSize);
343
current_size = actualSize;
352
/// Gets a surface that is useful for display by the Dock based on the Description
354
/// <param name="similar">
355
/// A <see cref="Surface"/>
358
/// A <see cref="Surface"/>
360
public virtual Surface GetTextSurface (Surface similar)
362
if (string.IsNullOrEmpty (Description))
365
if (text_surface == null || DockPreferences.Orientation != current_orientation) {
366
if (text_surface != null)
367
text_surface.Destroy ();
369
current_orientation = DockPreferences.Orientation;
371
text_surface = Util.GetBorderedTextSurface (GLib.Markup.EscapeText (Description),
372
DockPreferences.TextWidth,
376
TextSurfaceSize = rect;
381
protected virtual Surface MakeIconSurface (Surface similar, int size)
384
Surface tmp_surface = similar.CreateSimilar (Cairo.Content.ColorAlpha, size, size);
385
Context cr = new Context (tmp_surface);
387
Gdk.Pixbuf pbuf = GetSurfacePixbuf (size);
389
if (pbuf.Width != size || pbuf.Height != size) {
390
double scale = (double)size / Math.Max (pbuf.Width, pbuf.Height);
391
Gdk.Pixbuf temp = pbuf.ScaleSimple ((int) (pbuf.Width * scale), (int) (pbuf.Height * scale), Gdk.InterpType.Bilinear);
396
Gdk.CairoHelper.SetSourcePixbuf (cr,
398
(size - pbuf.Width) / 2,
399
(size - pbuf.Height) / 2);
404
(cr as IDisposable).Dispose ();
409
void OnIconSizeChanged ()
411
if (size_changed_timer > 0)
412
GLib.Source.Remove (size_changed_timer);
414
if (ScalingType == ScalingType.HighLow) {
416
} else if (IconSurface != null) {
417
if (resize_buffer == null)
418
resize_buffer = CopySurface (IconSurface, current_size, current_size);
420
Surface new_surface = resize_buffer.CreateSimilar (Cairo.Content.ColorAlpha,
421
DockPreferences.FullIconSize,
422
DockPreferences.FullIconSize);
423
using (Context cr = new Context (new_surface)) {
425
if (ScalingType == ScalingType.Downscaled)
426
scale = (double) DockPreferences.FullIconSize / (double) current_size;
428
scale = (double) DockPreferences.IconSize / (double) current_size;
429
cr.Scale (scale, scale);
430
resize_buffer.Show (cr, 0, 0);
432
IconSurface.Destroy ();
433
IconSurface = new_surface;
436
size_changed_timer = GLib.Timeout.Add (150, delegate {
438
size_changed_timer = 0;
443
protected void OnUpdateNeeded (UpdateRequestArgs args)
445
if (UpdateNeeded != null)
446
UpdateNeeded (this, args);
449
public virtual bool ReceiveItem (string item)
454
protected void RedrawIcon ()
456
if (size_changed_timer > 0 || redraw_timer > 0)
458
if (IconSurface != null) {
459
redraw_timer = GLib.Idle.Add (delegate {
460
Surface similar = IconSurface;
461
Surface second = SecondaryIconSurface;
463
SecondaryIconSurface = null;
465
if (similar != null && ((similar.Status & Cairo.Status.SurfaceFinished) != Cairo.Status.SurfaceFinished)) {
466
switch (ScalingType) {
467
case ScalingType.HighLow:
468
IconSurface = MakeIconSurface (similar, DockPreferences.FullIconSize);
469
SecondaryIconSurface = MakeIconSurface (similar, DockPreferences.IconSize);
471
case ScalingType.Downscaled:
472
IconSurface = MakeIconSurface (similar, DockPreferences.FullIconSize);
474
case ScalingType.Upscaled:
475
case ScalingType.None:
477
IconSurface = MakeIconSurface (similar, DockPreferences.IconSize);
487
OnUpdateNeeded (new UpdateRequestArgs (this, UpdateRequestType.IconChanged));
493
OnUpdateNeeded (new UpdateRequestArgs (this, UpdateRequestType.IconChanged));
497
void ResetBufferSurface ()
499
if (resize_buffer != null) {
500
resize_buffer.Destroy ();
501
resize_buffer = null;
505
void ResetIconSurface ()
507
if (IconSurface != null) {
508
IconSurface.Destroy ();
512
if (SecondaryIconSurface != null) {
513
SecondaryIconSurface.Destroy ();
514
SecondaryIconSurface = null;
518
protected virtual void ResetSurfaces ()
521
ResetBufferSurface ();
523
average_color = null;
526
void ResetTextSurface ()
528
if (text_surface != null) {
529
text_surface.Destroy ();
534
public virtual void HotSeatRequested ()
539
/// Called whenever an icon get repositioned, so it can update its child applications icon regions
541
public virtual void SetIconRegion (Gdk.Rectangle region)
545
protected void SetText (string text)
551
#region IDisposable implementation
553
public virtual void Dispose ()
556
DockPreferences.IconSizeChanged -= OnIconSizeChanged;
557
if (DockWindow.Window != null)
558
DockWindow.Window.StyleSet -= HandleStyleSet;
564
public virtual bool Equals (AbstractDockItem other)
566
return other == this;