~ubuntu-branches/ubuntu/wily/gnome-do/wily

« back to all changes in this revision

Viewing changes to Do.Interface.Linux.Docky/src/Docky.Utilities/WindowUtils.cs

  • Committer: Bazaar Package Importer
  • Author(s): Christopher James Halse Rogers
  • Date: 2009-06-27 10:40:45 UTC
  • mfrom: (1.1.8 upstream) (0.1.5 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090627104045-7st10y1cqr6dpz37
Tags: 0.8.2+dfsg-1
* New upstream release
  + No longer uses a plugin repository.  Fixes many plugin-
    related issues. (LP: #343096, LP: #330025, LP #345001)
  + No longer blocks on "About Do" (LP: #361679)
  + Reacts correctly when a Composite manager is enabled/
    disabled at runtime. (LP: #346347, LP: #390150)
  + Fixes for space reserved by Docky blocking drag and 
    drop operations. (LP: #354729, LP: #347052, LP: #382843)
  + Properly sets "Hidden" key on autostart files in response to 
    "Start on login" option.  (Closes: #526023) (LP: #369988)
* debian/patches/10_application_search_path:
  + Drop; included upstream
* debian/patches/10_sk_translation_update:
  + Import sk translation update from Debian BTS.
    (Closes: #531779)
* debian/patches/11_fix_autostart_when_directory_does_not_exist:
  + Patch from upstream.  Fixes the "Start on login" option when the 
    ~/.config/autostart directory does not exist. (LP: #393729)
* debian/control:
  + Update standards version to 3.8.2; no changes required.
  + Add libtool to Build-Depends; required for autoreconf.
  + Add Recommends: on new gnome-do-docklets package.
* debian/gnome-do.1
  + Fix spelling: GNOME-Do => GNOME Do.
  + Miscelaneous lintian fixes; NAME section, escaping minus signs with \-
* debian/copyright:
  + Update for new copyright holders.
  + Minor update to DEP-5 format

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// WindowUtils.cs
2
 
// 
3
 
// Copyright (C) 2008 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.Diagnostics;
22
 
using System.IO;
23
 
using System.Linq;
24
 
using System.Text.RegularExpressions;
25
 
 
26
 
using Do.Interface;
27
 
using Do.Universe;
28
 
using Do.Platform;
29
 
 
30
 
using Docky.Interface;
31
 
 
32
 
using Wnck;
33
 
 
34
 
namespace Docky.Utilities
35
 
{
36
 
        
37
 
        
38
 
        public static class WindowUtils
39
 
        {
40
 
                static string RemapFile {
41
 
                        get { return Path.Combine (Services.Paths.UserDataDirectory, "RemapFile"); }
42
 
                }
43
 
                
44
 
                public static IEnumerable<string> BadPrefixes {
45
 
                        get {
46
 
                                yield return "gksu";
47
 
                                yield return "sudo";
48
 
                                yield return "java";
49
 
                                yield return "mono";
50
 
                                yield return "ruby";
51
 
                                yield return "padsp";
52
 
                                yield return "aoss";
53
 
                                yield return "python(\\d.\\d)?";
54
 
                        }
55
 
                }
56
 
                
57
 
                static Dictionary<string, string> RemapDictionary { get; set; }
58
 
                
59
 
                static List<Application> application_list;
60
 
                static bool application_list_update_needed;
61
 
                
62
 
                static Dictionary<int, string> exec_lines = new Dictionary<int, string> ();
63
 
                static DateTime last_update = new DateTime (0);
64
 
                
65
 
                static WindowUtils ()
66
 
                {
67
 
                        Wnck.Screen.Default.WindowClosed += delegate {
68
 
                                application_list_update_needed = true;
69
 
                        };
70
 
                        
71
 
                        Wnck.Screen.Default.WindowOpened += delegate {
72
 
                                application_list_update_needed = true;
73
 
                        };
74
 
                        
75
 
                        Wnck.Screen.Default.ApplicationOpened += delegate {
76
 
                                application_list_update_needed = true;
77
 
                        };
78
 
                        
79
 
                        Wnck.Screen.Default.ApplicationClosed += delegate {
80
 
                                application_list_update_needed = true;
81
 
                        };
82
 
                        
83
 
                        BuildRemapDictionary ();
84
 
                }
85
 
                
86
 
                static void BuildRemapDictionary ()
87
 
                {
88
 
                        if (!File.Exists (RemapFile)) {
89
 
                                RemapDictionary = BuildDefaultRemapDictionary ();
90
 
                                
91
 
                                StreamWriter writer = null;
92
 
                                try {
93
 
                                        writer = new StreamWriter (RemapFile);
94
 
                                        writer.WriteLine ("# Docky Remap File");
95
 
                                        writer.WriteLine ("# Add key value pairs following dictionary syntax");
96
 
                                        writer.WriteLine ("# key, value");
97
 
                                        writer.WriteLine ("# key, altKey, value");
98
 
                                        writer.WriteLine ("# Lines starting with # are comments, otherwise # is a valid character");
99
 
                                        
100
 
                                        foreach (KeyValuePair<string, string> kvp in RemapDictionary) {
101
 
                                                writer.WriteLine ("{0}, {1}", kvp.Key, kvp.Value);
102
 
                                        }
103
 
                                        writer.Close ();
104
 
                                } finally {
105
 
                                        if (writer != null)
106
 
                                                writer.Dispose ();
107
 
                                }
108
 
                        } else {
109
 
                                RemapDictionary = new Dictionary<string, string> ();
110
 
                                
111
 
                                StreamReader reader = null;
112
 
                                try {
113
 
                                        reader = new StreamReader (RemapFile);
114
 
                                        
115
 
                                        string line;
116
 
                                        while (!reader.EndOfStream) {
117
 
                                                line = reader.ReadLine ();
118
 
                                                if (line.StartsWith ("#") || !line.Contains (","))
119
 
                                                        continue;
120
 
                                                string [] array = line.Split (',');
121
 
                                                if (array.Length < 2 || array [0].Length == 0)
122
 
                                                        continue;
123
 
                                                
124
 
                                                string val = array [array.Length - 1].Trim ().ToLower ();
125
 
                                                if (string.IsNullOrEmpty (val))
126
 
                                                        continue;
127
 
                                                
128
 
                                                for (int i=0; i < array.Length - 1; i++) {
129
 
                                                        string key = array [i].Trim ().ToLower ();
130
 
                                                        if (string.IsNullOrEmpty (key))
131
 
                                                                continue;
132
 
                                                        RemapDictionary [key] = val;
133
 
                                                }
134
 
                                        }
135
 
                                        
136
 
                                        reader.Close ();
137
 
                                } catch {
138
 
                                        Log.Error ("Could not read remap file");
139
 
                                        RemapDictionary = BuildDefaultRemapDictionary ();
140
 
                                } finally {
141
 
                                        if (reader != null)
142
 
                                                reader.Dispose ();
143
 
                                }
144
 
                        }
145
 
                }
146
 
                
147
 
                static Dictionary<string, string> BuildDefaultRemapDictionary ()
148
 
                {
149
 
                        Dictionary<string, string> remapDict = new Dictionary<string, string> ();
150
 
                        remapDict ["banshee.exe"] = "banshee";
151
 
                        remapDict ["banshee-1"] = "banshee";
152
 
                        remapDict ["azureus"] = "vuze";
153
 
                        remapDict ["thunderbird-3.0"] = "thunderbird";
154
 
                        remapDict ["thunderbird-bin"] = "thunderbird";
155
 
                        
156
 
                        return remapDict;
157
 
                }
158
 
                
159
 
                /// <summary>
160
 
                /// Returns a list of all applications on the default screen
161
 
                /// </summary>
162
 
                /// <returns>
163
 
                /// A <see cref="Application"/> array
164
 
                /// </returns>
165
 
                public static List<Application> GetApplications ()
166
 
                {
167
 
                        if (application_list == null || application_list_update_needed) {
168
 
                                application_list = new List<Application> ();
169
 
                                foreach (Window w in Wnck.Screen.Default.Windows) {
170
 
                                        if (!application_list.Contains (w.Application))
171
 
                                                application_list.Add (w.Application);
172
 
                                }
173
 
                        }
174
 
                        return application_list;
175
 
                }
176
 
                
177
 
                /// <summary>
178
 
                /// Gets the command line excec string for a PID
179
 
                /// </summary>
180
 
                /// <param name="pid">
181
 
                /// A <see cref="System.Int32"/>
182
 
                /// </param>
183
 
                /// <returns>
184
 
                /// A <see cref="System.String"/>
185
 
                /// </returns>
186
 
                public static string CmdLineForPid (int pid)
187
 
                {
188
 
                        StreamReader reader;
189
 
                        string cmdline = null;
190
 
                        
191
 
                        try {
192
 
                                string procPath = new [] { "/proc", pid.ToString (), "cmdline" }.Aggregate (Path.Combine);
193
 
                                reader = new StreamReader (procPath);
194
 
                                cmdline = reader.ReadLine ().Replace (Convert.ToChar (0x0), ' ');
195
 
                                reader.Close ();
196
 
                                reader.Dispose ();
197
 
                        } catch { }
198
 
                        
199
 
                        return cmdline;
200
 
                }
201
 
                
202
 
                /// <summary>
203
 
                /// Returns a list of applications that match an exec string
204
 
                /// </summary>
205
 
                /// <param name="exec">
206
 
                /// A <see cref="System.String"/>
207
 
                /// </param>
208
 
                /// <returns>
209
 
                /// A <see cref="List"/>
210
 
                /// </returns>
211
 
                public static List<Application> GetApplicationList (string exec)
212
 
                {
213
 
                        List<Application> apps = new List<Application> ();
214
 
                        if (string.IsNullOrEmpty (exec))
215
 
                                return apps;
216
 
                        
217
 
                        exec = ProcessExecString (exec);
218
 
                        if (string.IsNullOrEmpty (exec))
219
 
                                return apps;
220
 
                        
221
 
                        UpdateExecList ();
222
 
 
223
 
                        foreach (KeyValuePair<int, string> kvp in exec_lines) {
224
 
                                if (kvp.Value != null && kvp.Value.Contains (exec)) {
225
 
                                        foreach (Application app in GetApplications ()) {
226
 
                                                if (app == null)
227
 
                                                        continue;
228
 
                                                
229
 
                                                if (app.Pid == kvp.Key || app.Windows.Any (w => w.Pid == kvp.Key)) {
230
 
                                                        if (app.Windows.Any (win => !win.IsSkipTasklist))
231
 
                                                                apps.Add (app);
232
 
                                                        break;
233
 
                                                }
234
 
                                        }
235
 
                                }
236
 
                        }
237
 
                        return apps;
238
 
                }
239
 
                
240
 
                static void UpdateExecList ()
241
 
                {
242
 
                        if ((DateTime.UtcNow - last_update).TotalMilliseconds < 200) return;
243
 
                        
244
 
                        exec_lines.Clear ();
245
 
                        
246
 
                        foreach (string dir in Directory.GetDirectories ("/proc")) {
247
 
                                int pid;
248
 
                                try { pid = Convert.ToInt32 (Path.GetFileName (dir)); } 
249
 
                                catch { continue; }
250
 
                                
251
 
                                string exec_line = CmdLineForPid (pid);
252
 
                                if (string.IsNullOrEmpty (exec_line))
253
 
                                        continue;
254
 
                                
255
 
                                if (exec_line.Contains ("java") && exec_line.Contains ("jar")) {
256
 
                                        foreach (Application app in GetApplications ()) {
257
 
                                                if (app == null)
258
 
                                                        continue;
259
 
                                                
260
 
                                                if (app.Pid == pid || app.Windows.Any (w => w.Pid == pid)) {
261
 
                                                        foreach (Wnck.Window window in app.Windows.Where (win => !win.IsSkipTasklist)) {
262
 
                                                                exec_line = window.ClassGroup.ResClass;
263
 
                                                                
264
 
                                                                // Vuze is retarded
265
 
                                                                if (exec_line == "SWT")
266
 
                                                                        exec_line = window.Name;
267
 
                                                                Console.WriteLine (exec_line);
268
 
                                                                break;
269
 
                                                        }
270
 
                                                }
271
 
                                        }
272
 
                                }       
273
 
                                
274
 
                                exec_line = ProcessExecString (exec_line);
275
 
                                        
276
 
                                exec_lines [pid] = exec_line;
277
 
                        }
278
 
                        
279
 
                        last_update = DateTime.UtcNow;
280
 
                }
281
 
 
282
 
                public static string ProcessExecString (string exec)
283
 
                {
284
 
                        exec = exec.ToLower ().Trim ();
285
 
                        
286
 
                        if (RemapDictionary.ContainsKey (exec))
287
 
                                return RemapDictionary [exec];
288
 
                        
289
 
                        if (exec.StartsWith ("/")) {
290
 
                                string first_part = exec.Split (' ') [0];
291
 
                                int length = first_part.Length;
292
 
                                first_part = first_part.Split ('/').Last ();
293
 
                                
294
 
                                if (length < exec.Length)
295
 
                                         first_part = first_part + " " + exec.Substring (length + 1);
296
 
                                                
297
 
                                if (RemapDictionary.ContainsKey (first_part)) {
298
 
                                        return RemapDictionary [first_part];
299
 
                                }
300
 
                        }
301
 
                        
302
 
                        string [] parts = exec.Split (' ');
303
 
                        for (int i = 0; i < parts.Length; i++) {
304
 
                                if (parts [i].StartsWith ("-"))
305
 
                                        continue;
306
 
                                
307
 
                                if (parts [i].Contains ("/"))
308
 
                                        parts [i] = parts [i].Split ('/').Last ();
309
 
                                
310
 
                                Regex regex;
311
 
                                foreach (string prefix in BadPrefixes) {
312
 
                                        regex = new Regex (string.Format ("^{0}$", prefix), RegexOptions.IgnoreCase);
313
 
                                        if (regex.IsMatch (parts [i])) {
314
 
                                                parts [i] = null;
315
 
                                                break;
316
 
                                        }
317
 
                                }
318
 
                                
319
 
                                if (!string.IsNullOrEmpty (parts [i])) {
320
 
                                        string out_val = parts [i];
321
 
                                        if (RemapDictionary.ContainsKey (out_val))
322
 
                                                out_val = RemapDictionary [out_val];
323
 
                                        return out_val;
324
 
                                }
325
 
                        }
326
 
                        return null;
327
 
                }
328
 
                
329
 
                /// <summary>
330
 
                /// Performs the "logical" click action on an entire group of applications
331
 
                /// </summary>
332
 
                /// <param name="apps">
333
 
                /// A <see cref="IEnumerable"/>
334
 
                /// </param>
335
 
                public static void PerformLogicalClick (IEnumerable<Application> apps)
336
 
                {
337
 
                        List<Window> stack = new List<Window> (Wnck.Screen.Default.WindowsStacked);
338
 
                        IEnumerable<Window> windows = apps
339
 
                                .SelectMany (app => app.Windows)
340
 
                                .OrderByDescending (w => stack.IndexOf (w));
341
 
                        
342
 
                        bool not_in_viewport = !windows.Any (w => !w.IsSkipTasklist && w.IsInViewport (w.Screen.ActiveWorkspace));
343
 
                        bool urgent = windows.Any (w => w.NeedsAttention ());
344
 
                        
345
 
                        if (not_in_viewport || urgent) {
346
 
                                foreach (Wnck.Window window in windows) {
347
 
                                        if (urgent && !window.NeedsAttention ())
348
 
                                                continue;
349
 
                                        if (!window.IsSkipTasklist) {
350
 
                                                WindowControl.IntelligentFocusOffViewportWindow (window, windows);
351
 
                                                return;
352
 
                                        }
353
 
                                }
354
 
                        }
355
 
                        
356
 
                        switch (GetClickAction (apps)) {
357
 
                        case ClickAction.Focus:
358
 
                                WindowControl.FocusWindows (windows);
359
 
                                break;
360
 
                        case ClickAction.Minimize:
361
 
                                WindowControl.MinimizeWindows (windows);
362
 
                                break;
363
 
                        case ClickAction.Restore:
364
 
                                WindowControl.RestoreWindows (windows);
365
 
                                break;
366
 
                        }
367
 
                }
368
 
                
369
 
                static ClickAction GetClickAction (IEnumerable<Application> apps)
370
 
                {
371
 
                        if (!apps.Any ())
372
 
                                return ClickAction.None;
373
 
                        
374
 
                        foreach (Wnck.Application app in apps) {
375
 
                                foreach (Wnck.Window window in app.Windows) {
376
 
                                        if (window.IsMinimized && window.IsInViewport (Wnck.Screen.Default.ActiveWorkspace))
377
 
                                                return ClickAction.Restore;
378
 
                                }
379
 
                        }
380
 
                        
381
 
                        foreach (Wnck.Application app in apps) {
382
 
                                foreach (Wnck.Window window in app.Windows) {
383
 
                                        if (window.IsActive && window.IsInViewport (Wnck.Screen.Default.ActiveWorkspace))
384
 
                                                return ClickAction.Minimize;
385
 
                                }
386
 
                        }
387
 
                        
388
 
                        return ClickAction.Focus;
389
 
                }
390
 
        }
391
 
}