1
// ApplicationDockItem.cs
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;
29
using Do.Interface.CairoUtils;
34
using Docky.Utilities;
36
namespace Docky.Interface
40
public class ApplicationDockItem : BaseDockItem, IRightClickable, IDockAppItem
42
public event EventHandler RemoveClicked;
44
static IEnumerable<String> DesktopFilesDirectories {
47
"~/.local/share/applications/wine",
48
"~/.local/share/applications",
49
"/usr/share/applications",
50
"/usr/share/applications/kde",
51
"/usr/share/applications/kde4",
52
"/usr/share/gdm/applications",
53
"/usr/local/share/applications",
58
string MinimizeRestoreText = Catalog.GetString ("Minimize") + "/" + Catalog.GetString ("Restore");
59
string CloseText = Catalog.GetString ("Close All");
61
const int MenuItemMaxCharacters = 50;
62
const string WindowIcon = "forward";
63
const string MinimizeIcon = "down";
68
Gdk.Rectangle icon_region;
69
Gdk.Pixbuf drag_pixbuf;
74
foreach (Wnck.Application app in Applications) {
75
exec = MaybeGetExecStringForPID (app.Pid);
80
foreach (Wnck.Window win in VisibleWindows) {
81
exec = MaybeGetExecStringForPID (win.Pid);
89
#region IDockItem implementation
91
public override Pixbuf GetDragPixbuf ()
93
if (drag_pixbuf == null)
94
drag_pixbuf = GetSurfacePixbuf ();
99
/// Returns a Pixbuf suitable for usage in the dock.
102
/// A <see cref="Gdk.Pixbuf"/>
104
protected override Gdk.Pixbuf GetSurfacePixbuf ()
106
Gdk.Pixbuf pbuf = null;
107
foreach (string guess in GetIconGuesses ()) {
113
bool found = IconProvider.PixbufFromIconName (guess, DockPreferences.FullIconSize, out pbuf);
114
if (found && (pbuf.Width == DockPreferences.FullIconSize || pbuf.Height == DockPreferences.FullIconSize))
120
string desktopPath = GetDesktopFile (guess);
121
if (!string.IsNullOrEmpty (desktopPath)) {
123
string icon = Services.UniverseFactory.NewApplicationItem (desktopPath).Icon;
124
pbuf = IconProvider.PixbufFromIconName (icon, DockPreferences.FullIconSize);
132
// we failed to find an icon, lets use an uggggly one
134
pbuf = Applications.First ().Icon;
136
if (pbuf.Height != DockPreferences.FullIconSize && pbuf.Width != DockPreferences.FullIconSize) {
137
double scale = (double)DockPreferences.FullIconSize / Math.Max (pbuf.Width, pbuf.Height);
138
Gdk.Pixbuf temp = pbuf.ScaleSimple ((int) (pbuf.Width * scale), (int) (pbuf.Height * scale), Gdk.InterpType.Hyper);
145
public override string Description {
147
foreach (Wnck.Application application in Applications) {
148
if (StringIsValidName (application.IconName))
149
return application.IconName;
150
else if (StringIsValidName (application.Name))
151
return application.Name;
154
foreach (Wnck.Window window in VisibleWindows) {
155
if (StringIsValidName (window.IconName))
156
return window.IconName;
157
else if (StringIsValidName (window.Name))
164
public override int WindowCount {
165
get { return windowCount; }
168
IEnumerable<Wnck.Application> Applications { get; set; }
170
IEnumerable<Wnck.Window> VisibleWindows {
171
get { return Applications.SelectMany (a => a.Windows).Where (w => !w.IsSkipTasklist); }
176
public ApplicationDockItem (IEnumerable<Wnck.Application> applications) : base ()
178
Applications = applications;
179
windowCount = VisibleWindows.Count ();
180
AttentionRequestStartTime = DateTime.UtcNow - new TimeSpan (0, 10, 0);
182
foreach (Wnck.Window w in VisibleWindows) {
183
w.StateChanged += HandleStateChanged;
187
void HandleStateChanged(object o, Wnck.StateChangedArgs args)
190
urgent = DetermineUrgencyStatus ();
192
UpdateRequestType req = (urgent) ? UpdateRequestType.NeedsAttentionSet : UpdateRequestType.NeedsAttentionUnset;
194
AttentionRequestStartTime = DateTime.UtcNow;
195
if (UpdateNeeded != null)
196
UpdateNeeded (this, new UpdateRequestArgs (this, req));
200
IEnumerable<string> GetIconGuesses ()
202
List<string> guesses = new List<string> ();
203
foreach (Wnck.Application app in Applications) {
204
if (!guesses.Contains (PrepName (app.Name)))
205
guesses.Add (PrepName (app.Name));
206
if (!guesses.Contains (PrepName (app.IconName)))
207
guesses.Add (PrepName (app.IconName));
210
foreach (Wnck.Window win in VisibleWindows) {
211
if (!guesses.Contains (PrepName (win.Name)))
212
guesses.Add (PrepName (win.Name));
213
if (!guesses.Contains (PrepName (win.IconName)))
214
guesses.Add (PrepName (win.IconName));
215
if (!guesses.Contains (PrepName (win.ClassGroup.ResClass)))
216
guesses.Add (PrepName (win.ClassGroup.ResClass));
219
foreach (string s in guesses)
222
foreach (string s in guesses)
223
yield return "gnome-" + s;
225
if (Description.Length > 4 && Description.Contains (" "))
226
yield return Description.Split (' ') [0].ToLower ();
228
if (!string.IsNullOrEmpty (Exec)) {
230
yield return Exec.Split ('-')[0];
234
string PrepName (string s)
236
return s.ToLower ().Replace (' ', '-');
239
string MaybeGetExecStringForPID (int pid)
243
// this fails on mono pre 2.0
244
exec = System.Diagnostics.Process.GetProcessById (pid).ProcessName.Split (' ')[0];
245
} catch { exec = null; }
247
if (string.IsNullOrEmpty (exec)) {
249
// this works on all versions of mono but is less reliable (because I wrote it)
250
exec = WindowUtils.CmdLineForPid (pid).Split (' ')[0];
259
string GetDesktopFile (string base_name)
261
foreach (string dir in DesktopFilesDirectories) {
263
if (File.Exists (System.IO.Path.Combine (dir, base_name+".desktop")))
264
return System.IO.Path.Combine (dir, base_name+".desktop");
265
if (File.Exists (System.IO.Path.Combine (dir, "gnome-"+base_name+".desktop")))
266
return System.IO.Path.Combine (dir, "gnome-"+base_name+".desktop");
267
} catch { return null; }
272
bool StringIsValidName (string s)
274
return (!string.IsNullOrEmpty (s.Trim ()) && s != "<unknown>");
277
public override void Clicked (uint button)
280
WindowUtils.PerformLogicalClick (Applications);
281
AnimationType = ClickAnimationType.Darken;
283
AnimationType = ClickAnimationType.None;
286
base.Clicked (button);
289
public override void SetIconRegion (Gdk.Rectangle region)
291
if (icon_region == region)
293
icon_region = region;
295
VisibleWindows.ForEach (w => w.SetIconGeometry (region.X, region.Y, region.Width, region.Height));
298
public override bool Equals (BaseDockItem other)
300
if (!(other is ApplicationDockItem))
303
return Applications.Any (app => (other as ApplicationDockItem).Applications.Contains (app));
306
public IEnumerable<AbstractMenuButtonArgs> GetMenuItems ()
308
foreach (Wnck.Window window in VisibleWindows)
309
yield return new WindowMenuButtonArgs (window, window.Name, WindowIcon);
311
yield return new SeparatorMenuButtonArgs ();
313
yield return new SimpleMenuButtonArgs (() => WindowControl.MinimizeRestoreWindows (VisibleWindows),
314
MinimizeRestoreText, MinimizeIcon);
316
yield return new SimpleMenuButtonArgs (() => WindowControl.CloseWindows (VisibleWindows),
317
CloseText, Gtk.Stock.Quit);
320
#region IDockAppItem implementation
322
public event UpdateRequestHandler UpdateNeeded;
324
public bool NeedsAttention {
325
get { return urgent; }
328
public DateTime AttentionRequestStartTime {
334
bool DetermineUrgencyStatus ()
336
return VisibleWindows.Any (w => !w.IsSkipTasklist && w.NeedsAttention ());
339
public override void Dispose ()
341
foreach (Wnck.Window w in VisibleWindows)
342
w.StateChanged -= HandleStateChanged;