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;
31
using Do.Universe.Common;
32
using Do.Interface.CairoUtils;
34
using Docky.Utilities;
38
namespace Docky.Interface
42
public class DockItem : BaseDockItem, IRightClickable, IDockAppItem
45
List<Wnck.Application> apps;
46
Gdk.Rectangle icon_region;
47
Gdk.Pixbuf drag_pixbuf;
48
bool needs_attention, accepting_drops;
52
public event EventHandler RemoveClicked;
54
public event UpdateRequestHandler UpdateNeeded;
56
public DateTime AttentionRequestStartTime { get; private set; }
58
public int Position { get; set; }
60
public override bool IsAcceptingDrops {
61
get { return accepting_drops; }
65
get { return element.Icon; }
68
public override string Description {
69
get { return element.Name; }
73
get { return element; }
76
public Wnck.Application [] Applications {
77
get { return apps.ToArray (); }
80
public IEnumerable<int> Pids {
81
get { return apps.Select (win => win.Pid).ToArray (); }
84
public override int WindowCount {
85
get { return window_count; }
88
public bool NeedsAttention {
90
return needs_attention;
94
if (needs_attention == value)
96
needs_attention = value;
97
AttentionRequestStartTime = DateTime.UtcNow;
101
public IEnumerable<Act> ActionsForItem {
103
IEnumerable<Act> actions = Services.Core.GetActionsForItemOrderedByRelevance (element, false);
104
// we want to keep the window operations stable, so we are going to special case them out now.
105
// This has a degree of an abstraction break to it however, but it is important to get right
106
// until a better solution is found.
107
foreach (Act act in actions
108
.OrderByDescending (act => act.GetType ().Name != "WindowCloseAction")
109
.ThenByDescending (act => act.GetType ().Name != "WindowMinimizeAction")
110
.ThenByDescending (act => act.GetType ().Name != "WindowMaximizeAction")
111
.ThenByDescending (act => act.Relevance))
117
bool HasVisibleApps {
121
return apps.SelectMany (app => app.Windows).Any (win => !win.IsSkipTasklist);
125
public DockItem (Item element) : base ()
128
apps = new List<Wnck.Application> ();
129
this.element = element;
131
AttentionRequestStartTime = DateTime.UtcNow;
132
UpdateApplication ();
133
NeedsAttention = DetermineAttentionStatus ();
135
if (element is IFileItem && System.IO.Directory.Exists ((element as IFileItem).Path))
136
accepting_drops = true;
138
accepting_drops = false;
141
public override bool ReceiveItem (string item)
143
if (!IsAcceptingDrops)
146
if (item.StartsWith ("file://"))
147
item = item.Substring ("file://".Length);
149
if (File.Exists (item)) {
151
File.Move (item, System.IO.Path.Combine ((Element as IFileItem).Path, System.IO.Path.GetFileName (item)));
152
} catch { return false; }
154
} else if (Directory.Exists (item)) {
156
Directory.Move (item, System.IO.Path.Combine ((Element as IFileItem).Path, System.IO.Path.GetFileName (item)));
157
} catch { return false; }
163
public void UpdateApplication ()
165
UnregisterStateChangeEvents ();
167
if (element is IApplicationItem) {
168
apps = WindowUtils.GetApplicationList ((element as IApplicationItem).Exec);
169
window_count = Applications.SelectMany (a => a.Windows).Where (w => !w.IsSkipTasklist).Count ();
172
RegisterStateChangeEvents ();
175
void RegisterStateChangeEvents ()
177
foreach (Application app in Applications) {
178
foreach (Wnck.Window w in app.Windows) {
179
if (!w.IsSkipTasklist)
180
w.StateChanged += OnWindowStateChanged;
185
void UnregisterStateChangeEvents ()
187
foreach (Application app in Applications) {
188
foreach (Wnck.Window w in app.Windows) {
190
w.StateChanged -= OnWindowStateChanged;
196
void OnWindowStateChanged (object o, StateChangedArgs args)
198
if (handle_timer > 0)
200
// we do this delayed so that we dont get a flood of these events. Certain windows behave badly.
201
handle_timer = GLib.Timeout.Add (100, HandleUpdate);
202
window_count = Applications.SelectMany (a => a.Windows).Where (w => !w.IsSkipTasklist).Count ();
203
SetIconRegionFromCache ();
208
bool needed_attention = NeedsAttention;
209
NeedsAttention = DetermineAttentionStatus ();
211
if (NeedsAttention != needed_attention) {
212
UpdateRequestType req;
214
req = UpdateRequestType.NeedsAttentionSet;
216
req = UpdateRequestType.NeedsAttentionUnset;
217
if (UpdateNeeded != null)
218
UpdateNeeded (this, new UpdateRequestArgs (this, req));
225
bool DetermineAttentionStatus ()
227
foreach (Application app in Applications) {
228
if (app.Windows.Any (w => !w.IsSkipTasklist && w.NeedsAttention ()))
234
protected override Gdk.Pixbuf GetSurfacePixbuf ()
236
Gdk.Pixbuf pbuf = IconProvider.PixbufFromIconName (Icon, DockPreferences.FullIconSize);
237
if (pbuf.Height != DockPreferences.FullIconSize && pbuf.Width != DockPreferences.FullIconSize) {
238
double scale = (double)DockPreferences.FullIconSize / Math.Max (pbuf.Width, pbuf.Height);
239
Gdk.Pixbuf temp = pbuf.ScaleSimple ((int) (pbuf.Width * scale), (int) (pbuf.Height * scale), InterpType.Bilinear);
247
public override Pixbuf GetDragPixbuf ()
249
if (drag_pixbuf == null)
250
drag_pixbuf = IconProvider.PixbufFromIconName (Icon, DockPreferences.FullIconSize);
254
public override void Clicked (uint button)
256
if (!apps.Any () || !HasVisibleApps || button == 2) {
257
AnimationType = ClickAnimationType.Bounce;
259
} else if (button == 1) {
260
AnimationType = ClickAnimationType.Darken;
261
WindowUtils.PerformLogicalClick (apps);
264
base.Clicked (button);
269
if (Element is IFileItem)
270
Services.Core.PerformDefaultAction (Element as Item, new [] { typeof (OpenAction), });
272
Services.Core.PerformDefaultAction (Element as Item, Type.EmptyTypes);
275
public override void SetIconRegion (Gdk.Rectangle region)
277
if (icon_region == region)
279
icon_region = region;
281
SetIconRegionFromCache ();
284
void SetIconRegionFromCache ()
286
Applications.ForEach (app => app.Windows.Where (w => !w.IsSkipTasklist)
287
.ForEach (w => w.SetIconGeometry (icon_region.X, icon_region.Y, icon_region.Width, icon_region.Height)));
290
public override bool Equals (BaseDockItem other)
292
DockItem di = other as DockItem;
293
return di != null && di.Element.UniqueId == Element.UniqueId;
296
#region IDisposable implementation
298
public override void Dispose ()
300
UnregisterStateChangeEvents ();
304
if (drag_pixbuf != null)
305
drag_pixbuf.Dispose ();
310
#region IRightClickable implementation
312
public IEnumerable<AbstractMenuButtonArgs> GetMenuItems ()
314
bool hasApps = HasVisibleApps;
317
foreach (Wnck.Window window in Applications.SelectMany (app => app.Windows).Where (w => !w.IsSkipTasklist))
318
yield return new WindowMenuButtonArgs (window, window.Name, Icon);
319
yield return new SeparatorMenuButtonArgs ();
322
foreach (Act act in ActionsForItem)
323
yield return new LaunchMenuButtonArgs (act, element, act.Name, act.Icon);
325
yield return new SimpleMenuButtonArgs (OnRemoveClicked, Catalog.GetString ("Remove from Dock"), Gtk.Stock.Remove);
331
void OnRemoveClicked ()
333
if (RemoveClicked != null)
334
RemoveClicked (this, new EventArgs ());