Do

Merge lp:~jassmith/do/glitch-free-docky into lp:do

Proposed by Jason Smith
Status: Merged
Merged at revision: not available
Proposed branch: lp:~jassmith/do/glitch-free-docky
Merge into: lp:do
Diff against target: None lines
To merge this branch: bzr merge lp:~jassmith/do/glitch-free-docky
Reviewer Review Type Date Requested Status
Alex Launi (community) Approve
Review via email: mp+5092@code.launchpad.net
To post a comment you must log in.
lp:~jassmith/do/glitch-free-docky updated
1135. By Jason Smith

remove debug

Revision history for this message
Alex Launi (alexlauni) wrote :

Can you combine HandleWindowClosed and Opened methods? They do exactly the same thing, you should be able to at the very least use EventArgs, but they probably both inherit from a higher level base class. Take a look.

Constify the delay in DelayedUpdate. Magic numbers are evil!

on diff line 182, i really dont like the variable name api, it's confusing since api has a meaning.

There are a bunch of WriteLines, clean them up. If you need them, make them into Log.Debugs

In UnregisterWindowEvents why do you need a try catch? Whats going to throw an exception adding and removing an event handler?

Diff line 960: Do you need to GetString? This should be done before you get passed the string.

removed the commented out line from ScreenUtils.cs

Again, constify the delay in WindowControl.cs, FocusWindows ()

Looks good otherwise! Fix those things then merge!

review: Approve
lp:~jassmith/do/glitch-free-docky updated
1136. By Jason Smith

Fix issues found in review

1137. By Jason Smith

merge trunk

1138. By Jason Smith

Implement tiling code

1139. By Jason Smith

Add show desktop command

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== removed file 'Do.Interface.Linux.Docky/Do.Interface.Linux.Docky.dll.config'
2--- Do.Interface.Linux.Docky/Do.Interface.Linux.Docky.dll.config 2009-01-11 20:30:50 +0000
3+++ Do.Interface.Linux.Docky/Do.Interface.Linux.Docky.dll.config 1970-01-01 00:00:00 +0000
4@@ -1,4 +0,0 @@
5-<configuration>
6- <dllmap dll="X11" target="libX11.so.6"/>
7- <dllmap dll="libgdk-x11" target="libgdk-x11-2.0.so.0"/>
8-</configuration>
9
10=== modified file 'Do.Interface.Linux.Docky/Do.Interface.Linux.Docky.mdp'
11--- Do.Interface.Linux.Docky/Do.Interface.Linux.Docky.mdp 2009-03-20 20:43:06 +0000
12+++ Do.Interface.Linux.Docky/Do.Interface.Linux.Docky.mdp 2009-03-31 03:39:44 +0000
13@@ -19,7 +19,6 @@
14 <File name="src" subtype="Directory" buildaction="Compile" />
15 <File name="Resources" subtype="Directory" buildaction="Compile" />
16 <File name="Resources/Do.Interface.Linux.Docky.addin.xml" subtype="Code" buildaction="EmbedAsResource" />
17- <File name="src/XLib" subtype="Directory" buildaction="Compile" />
18 <File name="src/Docky.Interface" subtype="Directory" buildaction="Compile" />
19 <File name="src/Docky.Utilities" subtype="Directory" buildaction="Compile" />
20 <File name="src/Docky.Interface/DockArea.cs" subtype="Code" buildaction="Compile" />
21@@ -32,8 +31,6 @@
22 <File name="src/Docky.Interface/Docky.Interface.Painters/SummonModeRenderer.cs" subtype="Code" buildaction="Compile" />
23 <File name="src/Docky.Utilities/DockPreferences.cs" subtype="Code" buildaction="Compile" />
24 <File name="src/Docky.Utilities/GtkUtils.cs" subtype="Code" buildaction="Compile" />
25- <File name="src/XLib/X11Atoms.cs" subtype="Code" buildaction="Compile" />
26- <File name="src/XLib/Xlib.cs" subtype="Code" buildaction="Compile" />
27 <File name="src/Docky.Interface/IRightClickable.cs" subtype="Code" buildaction="Compile" />
28 <File name="src/Docky.Interface/UpdateRequestArgs.cs" subtype="Code" buildaction="Compile" />
29 <File name="src/Docky.Interface/DockAnimationState.cs" subtype="Code" buildaction="Compile" />
30
31=== modified file 'Do.Interface.Linux.Docky/Makefile.am'
32--- Do.Interface.Linux.Docky/Makefile.am 2009-03-20 20:43:06 +0000
33+++ Do.Interface.Linux.Docky/Makefile.am 2009-03-31 16:33:58 +0000
34@@ -65,9 +65,7 @@
35 src/Docky.Interface/Util.cs \
36 src/Docky.Utilities/DockOrientation.cs \
37 src/Docky.Utilities/DockPreferences.cs \
38- src/Docky.Utilities/GtkUtils.cs \
39- src/XLib/X11Atoms.cs \
40- src/XLib/Xlib.cs
41+ src/Docky.Utilities/GtkUtils.cs
42
43 RESOURCES = \
44 Resources/Do.Interface.Linux.Docky.addin.xml \
45@@ -91,6 +89,3 @@
46 Do.Interface.Wink \
47 Do.Platform \
48 Do.Universe
49-
50-module_DATA += $(ASSEMBLY).dll.config
51-EXTRA_DIST += $(ASSEMBLY).dll.config
52
53=== modified file 'Do.Interface.Linux.Docky/src/Docky.Core/Docky.Core.Default/ItemsService.cs'
54--- Do.Interface.Linux.Docky/src/Docky.Core/Docky.Core.Default/ItemsService.cs 2009-03-20 20:43:06 +0000
55+++ Do.Interface.Linux.Docky/src/Docky.Core/Docky.Core.Default/ItemsService.cs 2009-04-01 01:08:07 +0000
56@@ -199,14 +199,15 @@
57
58 void HandleWindowOpened(object o, WindowOpenedArgs args)
59 {
60+ // we do a delayed update so that we allow a small gap for wnck to catch up
61 if (!args.Window.IsSkipTasklist)
62- UpdateItems ();
63+ DelayUpdateItems ();
64 }
65
66 void HandleWindowClosed(object o, WindowClosedArgs args)
67 {
68 if (!args.Window.IsSkipTasklist)
69- UpdateItems ();
70+ DelayUpdateItems ();
71 }
72
73 void HandleUniverseInitialized(object sender, EventArgs e)
74@@ -259,17 +260,25 @@
75 item.Position = i++;
76 }
77
78+ void DelayUpdateItems ()
79+ {
80+ GLib.Timeout.Add (20, delegate {
81+ UpdateItems ();
82+ return false;
83+ });
84+ }
85+
86 void UpdateItems ()
87 {
88 if (!UpdatesEnabled)
89 return;
90
91- UpdateStatItems ();
92-
93 if (!CustomItemsRead) {
94 foreach (string s in ReadCustomItems ())
95 InternalAddItemToDock (s, LastPosition + 1);
96
97+ UpdateStatItems ();
98+
99 Dictionary<string, int> sortDictionary = ReadSortDictionary ();
100 foreach (ItemDockItem item in OrderedItems.Where (di => di is ItemDockItem)) {
101 if (sortDictionary.ContainsKey (item.Element.UniqueId))
102@@ -277,6 +286,8 @@
103 }
104
105 CustomItemsRead = true;
106+ } else {
107+ UpdateStatItems ();
108 }
109
110 UpdateTaskItems ();
111@@ -329,24 +340,22 @@
112
113 void UpdateTaskItems ()
114 {
115- foreach (ItemDockItem item in OrderedItems.Where (di => di is ItemDockItem)) {
116+ foreach (ItemDockItem item in OrderedItems.Where (di => di is ItemDockItem))
117 item.UpdateApplication ();
118- }
119
120 List<ApplicationDockItem> out_items = new List<ApplicationDockItem> ();
121
122- IEnumerable<int> knownPids = OrderedItems
123+ IEnumerable<Window> knownWindows = OrderedItems
124 .Where (di => di is ItemDockItem)
125 .Cast<ItemDockItem> ()
126- .SelectMany (di => di.Pids);
127-
128- IEnumerable<Application> prunedApps = WindowUtils.GetApplications ()
129- .Where (app => app.Windows.Any (w => !w.IsSkipTasklist))
130- .Where (app => !knownPids.Contains (app.Pid) && app.Windows.Any ());
131-
132- foreach (IEnumerable<Wnck.Application> apps in prunedApps
133- .GroupBy (app => (app as Wnck.Application).Windows [0].ClassGroup.ResClass)) {
134- ApplicationDockItem api = new ApplicationDockItem (apps);
135+ .SelectMany (di => di.Windows);
136+
137+ var prunedWindows = WindowUtils.GetWindows ()
138+ .Where (w => !w.IsSkipTasklist && !knownWindows.Contains (w))
139+ .GroupBy (w => SafeResClass (w));
140+
141+ foreach (IEnumerable<Wnck.Window> windows in prunedWindows) {
142+ ApplicationDockItem api = new ApplicationDockItem (windows);
143
144 if (task_items.Any (di => di.Equals (api))) {
145 AbstractDockItem match = task_items.Where (di => di.Equals (api)).First ();
146@@ -374,6 +383,13 @@
147 task_items.AddRange (out_items.Cast<AbstractDockItem> ());
148 }
149
150+ string SafeResClass (Wnck.Window window)
151+ {
152+ if (window.ClassGroup != null && window.ClassGroup.ResClass != null)
153+ return window.ClassGroup.ResClass;
154+ return string.Empty;
155+ }
156+
157 void OnDockItemsChanged ()
158 {
159 output_items.Clear ();
160@@ -506,15 +522,6 @@
161 return DockItems.Contains (item) && 0 <= position && position < DockItems.Count;
162 }
163
164- int LastNonTaskItemPosition ()
165- {
166- if (!OrderedItems.Any (di => !(di is ApplicationDockItem)))
167- return 0;
168- return OrderedItems
169- .Where (di => !(di is ApplicationDockItem))
170- .Max ((Func<AbstractDockItem, int>) (di => di.Position));
171- }
172-
173 /// <summary>
174 /// Returns the most used items out of GNOME Do and does a tiny bit of filtering and sorting on them
175 /// This is mostly to encourage a better first run experience, but overall this can be improved
176@@ -616,19 +623,22 @@
177 continue;
178 }
179
180- if (item is ApplicationDockItem && position <= LastNonTaskItemPosition ()) {
181+ if (item is ApplicationDockItem) {
182 ApplicationDockItem api = item as ApplicationDockItem;
183- string desktop_file = api.DesktopFile;
184-
185- if (string.IsNullOrEmpty (desktop_file)) continue;
186-
187- AbstractDockItem newItem = MaybeCreateCustomItem (desktop_file);
188-
189- if (newItem == null) continue;
190+
191+ if (api.Launcher == null) continue;
192+
193+ Item launcher = api.Launcher as Item;
194+ if (launcher == null)
195+ continue;
196+
197+ AbstractDockItem newItem = new ItemDockItem (launcher);
198
199 newItem.Position = item.Position;
200 newItem.DockAddItem = item.DockAddItem;
201- custom_items [desktop_file] = newItem;
202+ custom_items [launcher.UniqueId] = newItem;
203+
204+ RegisterDockItem (newItem);
205 UpdateItems ();
206 WriteData ();
207 }
208
209=== modified file 'Do.Interface.Linux.Docky/src/Docky.Interface/DockArea.cs'
210--- Do.Interface.Linux.Docky/src/Docky.Interface/DockArea.cs 2009-03-15 17:41:40 +0000
211+++ Do.Interface.Linux.Docky/src/Docky.Interface/DockArea.cs 2009-04-01 01:08:07 +0000
212@@ -26,6 +26,7 @@
213 using Gtk;
214
215 using Do.Platform;
216+using Do.Interface.Xlib;
217
218 using Docky.Core;
219 using Docky.Utilities;
220@@ -99,14 +100,14 @@
221
222 switch (DockPreferences.Orientation) {
223 case DockOrientation.Bottom:
224- values [(int) XLib.Struts.Bottom] = (uint) (DockHeight + (Screen.Height - (geo.Y + geo.Height)));
225- values [(int) XLib.Struts.BottomStart] = (uint) geo.X;
226- values [(int) XLib.Struts.BottomEnd] = (uint) (geo.X + geo.Width - 1);
227+ values [(int) Struts.Bottom] = (uint) (DockHeight + (Screen.Height - (geo.Y + geo.Height)));
228+ values [(int) Struts.BottomStart] = (uint) geo.X;
229+ values [(int) Struts.BottomEnd] = (uint) (geo.X + geo.Width - 1);
230 break;
231 case DockOrientation.Top:
232- values [(int) XLib.Struts.Top] = (uint) (DockHeight + geo.Y);
233- values [(int) XLib.Struts.TopStart] = (uint) geo.X;
234- values [(int) XLib.Struts.TopEnd] = (uint) (geo.X + geo.Width - 1);
235+ values [(int) Struts.Top] = (uint) (DockHeight + geo.Y);
236+ values [(int) Struts.TopStart] = (uint) geo.X;
237+ values [(int) Struts.TopEnd] = (uint) (geo.X + geo.Width - 1);
238 break;
239 }
240 return values;
241@@ -175,8 +176,11 @@
242 break;
243 }
244 }
245+
246 CursorIsOverDockArea = dockRegion.Contains (cursor);
247 }
248+ Console.WriteLine (cursor);
249+ Console.WriteLine (dockRegion);
250
251 // When we change over this boundry, it will normally trigger an animation, we need to be sure to catch it
252 if (CursorIsOverDockArea != cursorIsOverDockArea) {
253
254=== modified file 'Do.Interface.Linux.Docky/src/Docky.Interface/DockArea_Rendering.cs'
255--- Do.Interface.Linux.Docky/src/Docky.Interface/DockArea_Rendering.cs 2009-03-11 16:29:55 +0000
256+++ Do.Interface.Linux.Docky/src/Docky.Interface/DockArea_Rendering.cs 2009-04-01 01:08:07 +0000
257@@ -207,6 +207,8 @@
258
259 void DrawDrock (Context cr)
260 {
261+ Console.WriteLine (VerticalOffset);
262+ Console.WriteLine (CursorIsOverDockArea);
263 Gdk.Rectangle dockArea = GetDockArea ();
264 DockBackgroundRenderer.RenderDockBackground (cr, dockArea);
265
266
267=== modified file 'Do.Interface.Linux.Docky/src/Docky.Interface/DockWindow.cs'
268--- Do.Interface.Linux.Docky/src/Docky.Interface/DockWindow.cs 2009-03-15 18:30:41 +0000
269+++ Do.Interface.Linux.Docky/src/Docky.Interface/DockWindow.cs 2009-04-01 01:09:29 +0000
270@@ -25,11 +25,11 @@
271 using Cairo;
272
273 using Docky.Utilities;
274-using Docky.XLib;
275
276 using Do.Universe;
277 using Do.Platform;
278 using Do.Interface;
279+using Do.Interface.Xlib;
280 using Do.Interface.CairoUtils;
281 using Do.Interface.AnimationBase;
282
283@@ -243,7 +243,9 @@
284 results_window.Move ((geo.X + geo.Width / 2) - res.Width / 2, geo.Y + dock_area.DockHeight);
285 break;
286 }
287- Display.Sync ();
288+
289+ if (Display != null)
290+ Display.Sync ();
291
292 is_repositioned_hidden = false;
293 }
294@@ -264,7 +266,8 @@
295 break;
296 }
297
298- Display.Sync ();
299+ if (Display != null)
300+ Display.Sync ();
301
302 is_repositioned_hidden = true;
303 }
304@@ -272,20 +275,21 @@
305 public void WindowHideOffset (out int x, out int y)
306 {
307 x = y = 0;
308-
309- if (!is_repositioned_hidden) {
310- return;
311- }
312-
313- Gdk.Rectangle main;
314- GetSize (out main.Width, out main.Height);
315+
316+ Gdk.Rectangle main, geo;
317+ main.Width = dock_area.Width;
318+ main.Height = dock_area.Height;
319+ GetBufferedPosition (out main.X, out main.Y);
320+ geo = LayoutUtils.MonitorGemonetry ();
321+
322+
323 switch (DockPreferences.Orientation) {
324 case DockOrientation.Bottom:
325- y = main.Height;
326- break;
327+ y = main.Y - ((geo.Y + geo.Height) - main.Height);
328+ return;
329 case DockOrientation.Top:
330- y = 0 - main.Height;
331- break;
332+ y = main.Y - geo.Y;
333+ return;
334 }
335 }
336
337@@ -308,7 +312,7 @@
338
339 public bool SetStruts ()
340 {
341- X11Atoms atoms = new X11Atoms (GdkWindow);
342+ X11Atoms atoms = X11Atoms.Instance;
343
344 uint [] struts = dock_area.StrutRequest;
345 uint [] first_struts = new [] { struts [0], struts [1], struts [2], struts [3] };
346@@ -318,10 +322,10 @@
347 if (!IsRealized)
348 return false;
349 Xlib.XChangeProperty (GdkWindow, atoms._NET_WM_STRUT_PARTIAL, atoms.XA_CARDINAL,
350- (int) XLib.PropertyMode.PropModeReplace, struts);
351+ (int) PropertyMode.PropModeReplace, struts);
352
353 Xlib.XChangeProperty (GdkWindow, atoms._NET_WM_STRUT, atoms.XA_CARDINAL,
354- (int) XLib.PropertyMode.PropModeReplace, first_struts);
355+ (int) PropertyMode.PropModeReplace, first_struts);
356
357 return false;
358 }
359
360=== modified file 'Do.Interface.Linux.Docky/src/Docky.Interface/Docky.Interface.Items/ApplicationDockItem.cs'
361--- Do.Interface.Linux.Docky/src/Docky.Interface/Docky.Interface.Items/ApplicationDockItem.cs 2009-03-20 20:43:06 +0000
362+++ Do.Interface.Linux.Docky/src/Docky.Interface/Docky.Interface.Items/ApplicationDockItem.cs 2009-04-01 02:13:22 +0000
363@@ -43,16 +43,6 @@
364 {
365 public event EventHandler RemoveClicked;
366
367- static readonly IEnumerable<string> DesktopFilesDirectories = new [] {
368- "~/.local/share/applications/wine",
369- "~/.local/share/applications",
370- "/usr/share/applications",
371- "/usr/share/applications/kde",
372- "/usr/share/applications/kde4",
373- "/usr/share/gdm/applications",
374- "/usr/local/share/applications",
375- };
376-
377 string MinimizeRestoreText = Catalog.GetString ("Minimize") + "/" + Catalog.GetString ("Restore");
378 string MaximizeText = Catalog.GetString ("Maximize");
379 string CloseText = Catalog.GetString ("Close All");
380@@ -77,33 +67,23 @@
381 Gdk.Rectangle icon_region;
382 Gdk.Pixbuf drag_pixbuf;
383
384- IEnumerable<Wnck.Application> applications;
385-
386- string desktop_file;
387- bool checked_desktop_file;
388-
389- public string DesktopFile {
390+ IEnumerable<Wnck.Window> windows;
391+
392+ IApplicationItem launcher;
393+
394+ public IApplicationItem Launcher {
395 get {
396- if (desktop_file == null && !checked_desktop_file) {
397- checked_desktop_file = true;
398- foreach (string s in GetIconGuesses ()) {
399- desktop_file = GetDesktopFile (s);
400- if (desktop_file != null)
401- break;
402- }
403+ if (launcher == null && Exec != null) {
404+ string command = WindowUtils.ProcessExecString (Exec);
405+ launcher = Services.UniverseFactory.MaybeApplicationItemFromCommand (command);
406 }
407- return desktop_file;
408+ return launcher;
409 }
410 }
411
412 string Exec {
413 get {
414 string exec;
415- foreach (Wnck.Application app in Applications) {
416- exec = MaybeGetExecStringForPID (app.Pid);
417- if (exec != null)
418- return exec;
419- }
420
421 foreach (Wnck.Window win in VisibleWindows) {
422 exec = MaybeGetExecStringForPID (win.Pid);
423@@ -130,34 +110,23 @@
424 protected override Gdk.Pixbuf GetSurfacePixbuf (int size)
425 {
426 Gdk.Pixbuf pbuf = null;
427- foreach (string guess in GetIconGuesses ()) {
428- if (pbuf != null) {
429+
430+ if (Launcher == null) {
431+ foreach (string guess in GetIconGuesses ()) {
432+ bool found = IconProvider.PixbufFromIconName (guess, size, out pbuf);
433+ if (found && (pbuf.Width == size || pbuf.Height == size))
434+ break;
435+
436 pbuf.Dispose ();
437 pbuf = null;
438 }
439-
440- bool found = IconProvider.PixbufFromIconName (guess, size, out pbuf);
441- if (found && (pbuf.Width == size || pbuf.Height == size))
442- break;
443-
444- pbuf.Dispose ();
445- pbuf = null;
446-
447- string desktopPath = GetDesktopFile (guess);
448- if (!string.IsNullOrEmpty (desktopPath)) {
449- try {
450- string icon = Services.UniverseFactory.NewApplicationItem (desktopPath).Icon;
451- pbuf = IconProvider.PixbufFromIconName (icon, size);
452- break;
453- } catch {
454- continue;
455- }
456- }
457+ } else {
458+ IconProvider.PixbufFromIconName (Launcher.Icon, size, out pbuf);
459 }
460
461 // we failed to find an icon, lets use an uggggly one
462 if (pbuf == null)
463- pbuf = Applications.First ().Icon;
464+ pbuf = Windows.First ().Icon;
465
466 if (pbuf.Height != size && pbuf.Width != size ) {
467 double scale = (double)size / Math.Max (pbuf.Width, pbuf.Height);
468@@ -170,14 +139,16 @@
469
470 string Name {
471 get {
472- foreach (Wnck.Application application in Applications) {
473- if (StringIsValidName (application.IconName))
474- return application.IconName;
475- else if (StringIsValidName (application.Name))
476- return application.Name;
477- }
478-
479+ if (NeedsAttention) {
480+ return VisibleWindows.Where (w => w.NeedsAttention ()).First ().Name;
481+ }
482+ if (VisibleWindows.Any () && VisibleWindows.Count () == 1) {
483+ return VisibleWindows.First ().Name;
484+ }
485+
486 foreach (Wnck.Window window in VisibleWindows) {
487+ if (StringIsValidName (window.ClassGroup.ResClass))
488+ return window.ClassGroup.ResClass;
489 if (StringIsValidName (window.IconName))
490 return window.IconName;
491 else if (StringIsValidName (window.Name))
492@@ -191,13 +162,13 @@
493 get { return windowCount; }
494 }
495
496- protected override IEnumerable<Wnck.Application> Applications {
497- get { return applications; }
498+ public override IEnumerable<Wnck.Window> Windows {
499+ get { return windows; }
500 }
501
502- public ApplicationDockItem (IEnumerable<Wnck.Application> applications) : base ()
503+ public ApplicationDockItem (IEnumerable<Wnck.Window> windows) : base ()
504 {
505- this.applications = applications;
506+ this.windows = windows;
507 windowCount = VisibleWindows.Count ();
508
509 foreach (Wnck.Window w in VisibleWindows) {
510@@ -227,41 +198,49 @@
511 if (VisibleWindows.Count () == 0)
512 Core.DockServices.ItemsService.ForceUpdate ();
513 }
514+
515+ SetText (Name);
516 }
517
518 IEnumerable<string> GetIconGuesses ()
519 {
520 List<string> guesses = new List<string> ();
521
522- if (!string.IsNullOrEmpty (Exec)) {
523- yield return Exec;
524- yield return Exec.Split ('-')[0];
525+ // open office hack...
526+ if (VisibleWindows.Any () &&
527+ VisibleWindows.First ().ClassGroup != null &&
528+ VisibleWindows.First ().ClassGroup.ResClass.ToLower ().Contains ("openoffice")) {
529+ yield return "openoffice";
530+ yield break;
531 }
532
533- foreach (Wnck.Application app in Applications) {
534- if (!guesses.Contains (PrepName (app.Name)))
535- guesses.Add (PrepName (app.Name));
536- if (!guesses.Contains (PrepName (app.IconName)))
537- guesses.Add (PrepName (app.IconName));
538+ string exec = Exec;
539+ if (!string.IsNullOrEmpty (exec)) {
540+ yield return exec;
541+ yield return exec.Split ('-')[0];
542+ yield return WindowUtils.ProcessExecString (exec);
543 }
544
545 foreach (Wnck.Window win in VisibleWindows) {
546 if (!guesses.Contains (PrepName (win.Name)))
547 guesses.Add (PrepName (win.Name));
548+
549 if (!guesses.Contains (PrepName (win.IconName)))
550 guesses.Add (PrepName (win.IconName));
551+
552+ if (win.ClassGroup == null)
553+ continue;
554+
555 if (!guesses.Contains (PrepName (win.ClassGroup.ResClass)))
556 guesses.Add (PrepName (win.ClassGroup.ResClass));
557+
558+ if (!guesses.Contains (PrepName (win.ClassGroup.Name)))
559+ guesses.Add (PrepName (win.ClassGroup.Name));
560 }
561
562- foreach (string s in guesses)
563+ foreach (string s in guesses) {
564 yield return s;
565-
566- foreach (string s in guesses)
567- yield return "gnome-" + s;
568-
569- if (Name.Length > 4 && Name.Contains (" "))
570- yield return Name.Split (' ') [0].ToLower ();
571+ }
572 }
573
574 string PrepName (string s)
575@@ -283,27 +262,14 @@
576 return exec;
577 }
578
579- string GetDesktopFile (string base_name)
580- {
581- foreach (string dir in DesktopFilesDirectories) {
582- try {
583- if (File.Exists (System.IO.Path.Combine (dir, base_name+".desktop")))
584- return System.IO.Path.Combine (dir, base_name+".desktop");
585- if (File.Exists (System.IO.Path.Combine (dir, "gnome-"+base_name+".desktop")))
586- return System.IO.Path.Combine (dir, "gnome-"+base_name+".desktop");
587- } catch { return null; }
588- }
589- return null;
590- }
591-
592 bool StringIsValidName (string s)
593 {
594 s = s.Trim ();
595 if (string.IsNullOrEmpty (s) || s == "<unknown>")
596 return false;
597
598- foreach (string prefix in WindowUtils.BadPrefixes) {
599- if (string.Compare (s, prefix, true) == 0)
600+ foreach (System.Text.RegularExpressions.Regex prefix in WindowUtils.BadPrefixes) {
601+ if (prefix.IsMatch (s))
602 return false;
603 }
604
605@@ -324,14 +290,15 @@
606 if (!(other is ApplicationDockItem))
607 return false;
608
609- return Applications.Any (app => (other as ApplicationDockItem).Applications.Contains (app));
610+ return Windows.Any (w => (other as ApplicationDockItem).Windows.Contains (w));
611 }
612
613 public IEnumerable<AbstractMenuArgs> GetMenuItems ()
614 {
615 yield return new SeparatorMenuButtonArgs ();
616
617- if (DesktopFile == null) {
618+ Item item = Launcher as Item;
619+ if (item == null) {
620 yield return new SimpleMenuButtonArgs (() => WindowControl.MinimizeRestoreWindows (VisibleWindows),
621 MinimizeRestoreText, MinimizeIcon).AsDark ();
622
623@@ -341,8 +308,6 @@
624 yield return new SimpleMenuButtonArgs (() => WindowControl.CloseWindows (VisibleWindows),
625 CloseText, CloseIcon).AsDark ();
626 } else {
627- Item item = Services.UniverseFactory.NewApplicationItem (DesktopFile) as Item;
628-
629 foreach (Act act in ActionsForItem (item))
630 yield return new LaunchMenuButtonArgs (act, item, act.Name, act.Icon).AsDark ();
631 }
632@@ -352,6 +317,12 @@
633 yield return new WindowMenuButtonArgs (window, window.Name, WindowIcon);
634 }
635 }
636+
637+ protected override void Launch ()
638+ {
639+ if (Launcher != null)
640+ Launcher.Run ();
641+ }
642
643 public override void Dispose ()
644 {
645
646=== modified file 'Do.Interface.Linux.Docky/src/Docky.Interface/Docky.Interface.Items/ItemDockItem.cs'
647--- Do.Interface.Linux.Docky/src/Docky.Interface/Docky.Interface.Items/ItemDockItem.cs 2009-03-20 20:43:06 +0000
648+++ Do.Interface.Linux.Docky/src/Docky.Interface/Docky.Interface.Items/ItemDockItem.cs 2009-03-25 03:40:59 +0000
649@@ -52,7 +52,7 @@
650 bool accepting_drops;
651 Gdk.Pixbuf drag_pixbuf;
652 Gdk.Rectangle icon_region;
653- List<Wnck.Application> apps;
654+ List<Wnck.Window> windows;
655
656 public event EventHandler RemoveClicked;
657
658@@ -64,16 +64,32 @@
659 get { return element.Icon; }
660 }
661
662+ string Name {
663+ get {
664+ if (NeedsAttention && AttentionWindows.Any ())
665+ return AttentionWindows.First ().Name;
666+
667+ if (VisibleWindows.Any () && WindowCount == 1)
668+ return VisibleWindows.First ().Name;
669+
670+ return Element.Name;
671+ }
672+ }
673+
674 public Item Element {
675 get { return element; }
676 }
677
678- protected override IEnumerable<Wnck.Application> Applications {
679- get { return apps; }
680+ public override IEnumerable<Wnck.Window> Windows {
681+ get { return windows; }
682+ }
683+
684+ IEnumerable<Wnck.Window> AttentionWindows {
685+ get { return VisibleWindows.Where (w => w.NeedsAttention ()); }
686 }
687
688 public IEnumerable<int> Pids {
689- get { return apps.Select (win => win.Pid).ToArray (); }
690+ get { return windows.Select (win => win.Pid).ToArray (); }
691 }
692
693 public override int WindowCount {
694@@ -84,9 +100,7 @@
695 {
696 Position = -1;
697 this.element = element;
698- apps = new List<Wnck.Application> ();
699-
700- SetText (element.Name);
701+ windows = new List<Wnck.Window> ();
702
703 UpdateApplication ();
704 NeedsAttention = DetermineUrgencyStatus ();
705@@ -95,6 +109,8 @@
706 accepting_drops = true;
707 else
708 accepting_drops = false;
709+
710+ SetText (Name);
711 }
712
713 public override bool ReceiveItem (string item)
714@@ -126,46 +142,49 @@
715
716 public void UpdateApplication ()
717 {
718- UnregisterStateChangeEvents ();
719+ UnregisterWindowEvents ();
720
721 if (element is IApplicationItem) {
722- apps = WindowUtils.GetApplicationList ((element as IApplicationItem).Exec);
723- window_count = Applications.SelectMany (a => a.Windows).Where (w => !w.IsSkipTasklist).Count ();
724+ windows = WindowUtils.WindowListForCmd ((element as IApplicationItem).Exec);
725+ window_count = windows.Where (w => !w.IsSkipTasklist).Count ();
726 }
727
728- RegisterStateChangeEvents ();
729- }
730-
731- void RegisterStateChangeEvents ()
732- {
733- foreach (Application app in Applications) {
734- foreach (Wnck.Window w in app.Windows) {
735- if (!w.IsSkipTasklist)
736- w.StateChanged += OnWindowStateChanged;
737- }
738- }
739- }
740-
741- void UnregisterStateChangeEvents ()
742- {
743- foreach (Application app in Applications) {
744- foreach (Wnck.Window w in app.Windows) {
745- try {
746- w.StateChanged -= OnWindowStateChanged;
747- } catch {}
748- }
749- }
750- }
751-
752- void OnWindowStateChanged (object o, StateChangedArgs args)
753+ RegisterWindowEvents ();
754+ SetText (Name);
755+ }
756+
757+ void RegisterWindowEvents ()
758+ {
759+ foreach (Wnck.Window w in VisibleWindows) {
760+ w.StateChanged += HandleStateChanged;
761+ w.NameChanged += HandleNameChanged;
762+ }
763+ }
764+
765+ void UnregisterWindowEvents ()
766+ {
767+ foreach (Wnck.Window w in Windows) {
768+ try {
769+ w.StateChanged -= HandleStateChanged;
770+ w.NameChanged += HandleNameChanged;
771+ } catch {}
772+ }
773+ }
774+
775+ void HandleStateChanged (object o, StateChangedArgs args)
776 {
777 if (handle_timer > 0) return;
778 // we do this delayed so that we dont get a flood of these events. Certain windows behave badly.
779 handle_timer = GLib.Timeout.Add (100, HandleUpdate);
780- window_count = Applications.SelectMany (a => a.Windows).Where (w => !w.IsSkipTasklist).Count ();
781+ window_count = VisibleWindows.Count ();
782 SetIconRegionFromCache ();
783 }
784
785+ void HandleNameChanged(object sender, EventArgs e)
786+ {
787+ SetText (Name);
788+ }
789+
790 bool HandleUpdate ()
791 {
792 bool needed_attention = NeedsAttention;
793@@ -180,6 +199,7 @@
794 OnUpdateNeeded (new UpdateRequestArgs (this, req));
795 }
796
797+ SetText (Name);
798 handle_timer = 0;
799 return false;
800 }
801@@ -250,9 +270,9 @@
802
803 public override void Dispose ()
804 {
805- UnregisterStateChangeEvents ();
806+ UnregisterWindowEvents ();
807 element = null;
808- apps.Clear ();
809+ windows.Clear ();
810
811 if (drag_pixbuf != null)
812 drag_pixbuf.Dispose ();
813
814=== modified file 'Do.Interface.Linux.Docky/src/Docky.Interface/Docky.Interface.Items/WnckDockItem.cs'
815--- Do.Interface.Linux.Docky/src/Docky.Interface/Docky.Interface.Items/WnckDockItem.cs 2009-03-20 20:43:06 +0000
816+++ Do.Interface.Linux.Docky/src/Docky.Interface/Docky.Interface.Items/WnckDockItem.cs 2009-04-01 01:08:07 +0000
817@@ -42,20 +42,26 @@
818
819 public abstract class WnckDockItem : AbstractDockItem
820 {
821+ // a bad hack, but it works
822+ static string [] blacklist = new [] {
823+ "CopyToClipboardAction",
824+ "WindowFocusAction",
825+ };
826+
827 int last_raised;
828
829 DateTime last_scroll = new DateTime (0);
830 TimeSpan scroll_rate = new TimeSpan (0, 0, 0, 0, 300);
831
832- protected abstract IEnumerable<Wnck.Application> Applications { get; }
833+ public abstract IEnumerable<Wnck.Window> Windows { get; }
834
835 protected IEnumerable<Wnck.Window> VisibleWindows {
836- get { return Applications.SelectMany (a => a.Windows).Where (w => !w.IsSkipTasklist); }
837+ get { return Windows.Where (w => !w.IsSkipTasklist); }
838 }
839
840 protected bool HasVisibleApps {
841 get {
842- if (Applications == null)
843+ if (Windows == null)
844 return false;
845 return VisibleWindows.Any ();
846 }
847@@ -69,7 +75,7 @@
848 protected IEnumerable<Act> ActionsForItem (Item item)
849 {
850 return Services.Core.GetActionsForItemOrderedByRelevance (item, false)
851- .Where (act => act.GetType ().Name != "CopyToClipboardAction")
852+ .Where (act => !blacklist.Contains (act.GetType ().Name))
853 .OrderByDescending (act => act.GetType ().Name != "WindowCloseAction")
854 .ThenByDescending (act => act.GetType ().Name != "WindowMaximizeAction")
855 .ThenByDescending (act => act.GetType ().Name != "WindowMinimizeAction")
856@@ -77,10 +83,7 @@
857 .ThenBy (act => act.Name);
858 }
859
860- protected virtual void Launch ()
861- {
862- return;
863- }
864+ protected abstract void Launch ();
865
866 public override void Scrolled (Gdk.ScrollDirection direction)
867 {
868@@ -115,12 +118,12 @@
869
870 public override void Clicked (uint button, Gdk.ModifierType state, Gdk.Point position)
871 {
872- if (!Applications.Any () || !HasVisibleApps || button == 2) {
873+ if (!Windows.Any () || !HasVisibleApps || button == 2) {
874 AnimationType = ClickAnimationType.Bounce;
875 Launch ();
876 } else if (button == 1) {
877 AnimationType = ClickAnimationType.Darken;
878- WindowUtils.PerformLogicalClick (Applications);
879+ WindowUtils.PerformLogicalClick (Windows);
880 } else {
881 AnimationType = ClickAnimationType.None;
882 }
883
884=== modified file 'Do.Interface.Linux.Docky/src/Docky.Interface/Docky.Interface.Menus/AbstractMenuButtonArgs.cs'
885--- Do.Interface.Linux.Docky/src/Docky.Interface/Docky.Interface.Menus/AbstractMenuButtonArgs.cs 2009-03-07 22:50:28 +0000
886+++ Do.Interface.Linux.Docky/src/Docky.Interface/Docky.Interface.Menus/AbstractMenuButtonArgs.cs 2009-03-26 14:42:21 +0000
887@@ -39,7 +39,8 @@
888 const int Height = 22;
889
890 Gtk.Widget widget;
891- bool hovered;
892+ bool hovered, tooltip;
893+ string description, icon;
894
895 public bool Dark { get; set; }
896
897@@ -47,33 +48,60 @@
898 get { return 1; }
899 }
900
901- public override Gtk.Widget Widget {
902- get {
903- if (widget == null)
904- widget = BuildWidget ();
905- return widget;
906- }
907- }
908-
909- protected virtual string Description { get; set; }
910-
911- protected virtual string Icon { get; set; }
912-
913- protected virtual bool UseTooltip { get; set; }
914+ public override Gtk.Widget Widget {
915+ get { return widget; }
916+ }
917+
918+ private Gdk.Pixbuf Pixbuf { get; set; }
919+
920+ protected string Description {
921+ get {
922+ return description;
923+ }
924+ set {
925+ description = value;
926+ BuildWidget ();
927+ }
928+ }
929+
930+ protected string Icon {
931+ get {
932+ return icon;
933+ }
934+ set {
935+ icon = value;
936+ BuildWidget ();
937+ }
938+ }
939+
940+ protected bool UseTooltip {
941+ get {
942+ return tooltip;
943+ }
944+ set {
945+
946+ tooltip = value;
947+ BuildWidget ();
948+ }
949+ }
950
951 public AbstractMenuButtonArgs ()
952 {
953-
954 }
955
956 public AbstractMenuButtonArgs (string description, string icon)
957 {
958- Description = GLib.Markup.EscapeText (Catalog.GetString (description));
959- Icon = icon;
960+ this.description = GLib.Markup.EscapeText (Catalog.GetString (description));
961+ this.icon = icon;
962+
963+ BuildWidget ();
964 }
965
966- Widget BuildWidget ()
967+ void BuildWidget ()
968 {
969+ if (widget != null)
970+ widget.Destroy ();
971+
972 DrawingArea button = new DrawingArea ();
973
974 button.ExposeEvent += HandleExposeEvent;
975@@ -88,7 +116,12 @@
976 if (UseTooltip)
977 button.TooltipText = Description;
978
979- return button;
980+ widget = button;
981+
982+ if (Pixbuf != null)
983+ Pixbuf.Dispose ();
984+
985+ Pixbuf = GetPixbuf (Height - 8);
986 }
987
988 void HandleButtonReleaseEvent(object o, ButtonReleaseEventArgs args)
989@@ -135,27 +168,31 @@
990
991 int width = area.Width - WidthBuffer * 2 - 25;
992
993- TextRenderContext renderContext = new TextRenderContext (cr, string.Format (FormatString, Description), width);
994-
995- renderContext.LeftCenteredPoint = new Gdk.Point (area.X + WidthBuffer + 25, area.Y + area.Height / 2);
996- renderContext.Alignment = Pango.Alignment.Left;
997- renderContext.EllipsizeMode = Pango.EllipsizeMode.End;
998-
999- DockServices.DrawingService.TextPathAtPoint (renderContext);
1000-
1001- cr.Color = new Cairo.Color (1, 1, 1);
1002- cr.Fill ();
1003-
1004- Gdk.Pixbuf pbuf = GetPixbuf (Height - 8);
1005- CairoHelper.SetSourcePixbuf (cr, pbuf, WidthBuffer, (Height - pbuf.Height) / 2);
1006- cr.PaintWithAlpha (IconOpacity);
1007- pbuf.Dispose ();
1008+ if (!string.IsNullOrEmpty (Description)) {
1009+ TextRenderContext renderContext = new TextRenderContext (cr, string.Format (FormatString, Description), width);
1010+
1011+ renderContext.LeftCenteredPoint = new Gdk.Point (area.X + WidthBuffer + 25, area.Y + area.Height / 2);
1012+ renderContext.Alignment = Pango.Alignment.Left;
1013+ renderContext.EllipsizeMode = Pango.EllipsizeMode.End;
1014+
1015+ DockServices.DrawingService.TextPathAtPoint (renderContext);
1016+
1017+ cr.Color = new Cairo.Color (1, 1, 1);
1018+ cr.Fill ();
1019+ }
1020+
1021+ if (Pixbuf != null) {
1022+ CairoHelper.SetSourcePixbuf (cr, Pixbuf, WidthBuffer, (Height - Pixbuf.Height) / 2);
1023+ cr.PaintWithAlpha (IconOpacity);
1024+ }
1025 }
1026 }
1027
1028 protected virtual Gdk.Pixbuf GetPixbuf (int size)
1029 {
1030- return IconProvider.PixbufFromIconName (Icon, size);
1031+ if (!string.IsNullOrEmpty (Icon))
1032+ return IconProvider.PixbufFromIconName (Icon, size);
1033+ return null;
1034 }
1035
1036 public abstract void Action ();
1037@@ -169,6 +206,7 @@
1038 public override void Dispose ()
1039 {
1040 Widget.Destroy ();
1041+ Pixbuf.Dispose ();
1042 base.Dispose ();
1043 }
1044
1045
1046=== modified file 'Do.Interface.Linux.Docky/src/Docky.Interface/Docky.Interface.Menus/WindowMenuButtonArgs.cs'
1047--- Do.Interface.Linux.Docky/src/Docky.Interface/Docky.Interface.Menus/WindowMenuButtonArgs.cs 2009-03-20 20:43:06 +0000
1048+++ Do.Interface.Linux.Docky/src/Docky.Interface/Docky.Interface.Menus/WindowMenuButtonArgs.cs 2009-03-26 04:33:12 +0000
1049@@ -38,7 +38,6 @@
1050 return (window.IsMinimized) ? .5 : base.IconOpacity;
1051 }
1052 }
1053-
1054
1055 public WindowMenuButtonArgs (Wnck.Window window, string description, string icon) : base (description, icon)
1056 {
1057
1058=== modified file 'Do.Interface.Linux.Docky/src/Docky.Interface/Util.cs'
1059--- Do.Interface.Linux.Docky/src/Docky.Interface/Util.cs 2009-03-20 20:43:06 +0000
1060+++ Do.Interface.Linux.Docky/src/Docky.Interface/Util.cs 2009-03-24 16:08:07 +0000
1061@@ -78,7 +78,8 @@
1062 DockOrientation orientation)
1063 {
1064 Surface sr;
1065- sr = similar.CreateSimilar (similar.Content, maxWidth, Height);
1066+ // we are going to give ourselves a bit of a buffer due to pango weirdness
1067+ sr = similar.CreateSimilar (similar.Content, maxWidth + 5, Height);
1068
1069 Context cr = new Context (sr);
1070
1071@@ -89,7 +90,7 @@
1072 cr.NewPath ();
1073
1074 int localHeight = textArea.Height;
1075- cr.SetRoundedRectanglePath (textArea.X + .5, .5, textArea.Width + 20 - 1, localHeight + 10 - 1, 5);
1076+ cr.SetRoundedRectanglePath (textArea.X + .5, .5, textArea.Width + 20 - 1, localHeight + 10 - 1, 5);
1077
1078 cr.Color = new Cairo.Color (0.1, 0.1, 0.1, .75);
1079 cr.FillPreserve ();
1080
1081=== modified file 'Do.Interface.Wink/Do.Interface.Wink.mdp'
1082--- Do.Interface.Wink/Do.Interface.Wink.mdp 2009-03-20 20:43:06 +0000
1083+++ Do.Interface.Wink/Do.Interface.Wink.mdp 2009-03-31 03:39:44 +0000
1084@@ -20,11 +20,20 @@
1085 <File name="src/AssemblyInfo.cs" subtype="Code" buildaction="Compile" />
1086 <File name="src/Do.Interface.Wink/WindowControl.cs" subtype="Code" buildaction="Compile" />
1087 <File name="src/Do.Interface.Wink/WindowUtils.cs" subtype="Code" buildaction="Compile" />
1088+ <File name="src/Do.Interface.Wink/ClickAction.cs" subtype="Code" buildaction="Compile" />
1089+ <File name="src/Do.Interface.Wink/ScreenUtils.cs" subtype="Code" buildaction="Compile" />
1090+ <File name="src/Do.Interface.Wink/Viewport.cs" subtype="Code" buildaction="Compile" />
1091+ <File name="src/Do.Interface.Xlib" subtype="Directory" buildaction="Compile" />
1092+ <File name="src/Do.Interface.Xlib/X11Atoms.cs" subtype="Code" buildaction="Compile" />
1093+ <File name="src/Do.Interface.Xlib/Xlib.cs" subtype="Code" buildaction="Compile" />
1094 </Contents>
1095 <References>
1096 <ProjectReference type="Gac" localcopy="True" refto="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
1097 <ProjectReference type="Gac" localcopy="True" refto="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
1098 <ProjectReference type="Gac" localcopy="True" refto="wnck-sharp, Version=2.20.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
1099 <ProjectReference type="Project" localcopy="True" refto="Do.Platform" />
1100+ <ProjectReference type="Gac" localcopy="True" refto="gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
1101+ <ProjectReference type="Gac" localcopy="True" refto="gdk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
1102+ <ProjectReference type="Gac" localcopy="True" refto="Mono.Posix, Version=2.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756" />
1103 </References>
1104 </Project>
1105\ No newline at end of file
1106
1107=== modified file 'Do.Interface.Wink/Makefile.am'
1108--- Do.Interface.Wink/Makefile.am 2009-03-20 23:06:10 +0000
1109+++ Do.Interface.Wink/Makefile.am 2009-03-31 16:23:23 +0000
1110@@ -8,8 +8,13 @@
1111
1112 FILES = \
1113 src/AssemblyInfo.cs \
1114+ src/Do.Interface.Xlib/Xlib.cs \
1115+ src/Do.Interface.Xlib/X11Atoms.cs \
1116+ src/Do.Interface.Wink/ClickAction.cs \
1117 src/Do.Interface.Wink/WindowControl.cs \
1118- src/Do.Interface.Wink/WindowUtils.cs
1119+ src/Do.Interface.Wink/WindowUtils.cs \
1120+ src/Do.Interface.Wink/ScreenUtils.cs \
1121+ src/Do.Interface.Wink/Viewport.cs
1122
1123 #RESOURCES = \
1124 # Resources/Do.Interface.Wnck.addin.xml
1125@@ -17,11 +22,12 @@
1126 REFERENCES = \
1127 System \
1128 System.Core \
1129+ Mono.Posix \
1130 $(GTK_SHARP_20_LIBS) \
1131 $(WNCK_SHARP_10_LIBS)
1132
1133 PROJECT_REFERENCES = \
1134 Do.Platform
1135
1136-#module_DATA += $(ASSEMBLY).dll.config
1137-#EXTRA_DIST += $(ASSEMBLY).dll.config
1138+module_DATA += $(ASSEMBLY).dll.config
1139+EXTRA_DIST += $(ASSEMBLY).dll.config
1140
1141=== added file 'Do.Interface.Wink/src/Do.Interface.Wink/ClickAction.cs'
1142--- Do.Interface.Wink/src/Do.Interface.Wink/ClickAction.cs 1970-01-01 00:00:00 +0000
1143+++ Do.Interface.Wink/src/Do.Interface.Wink/ClickAction.cs 2009-03-25 19:49:42 +0000
1144@@ -0,0 +1,31 @@
1145+//
1146+// Copyright (C) 2009 GNOME Do
1147+//
1148+// This program is free software: you can redistribute it and/or modify
1149+// it under the terms of the GNU General Public License as published by
1150+// the Free Software Foundation, either version 3 of the License, or
1151+// (at your option) any later version.
1152+//
1153+// This program is distributed in the hope that it will be useful,
1154+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1155+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1156+// GNU General Public License for more details.
1157+//
1158+// You should have received a copy of the GNU General Public License
1159+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1160+//
1161+
1162+using System;
1163+
1164+namespace Do.Interface.Wink
1165+{
1166+
1167+
1168+ public enum ClickAction
1169+ {
1170+ Focus,
1171+ Minimize,
1172+ Restore,
1173+ None,
1174+ }
1175+}
1176
1177=== added file 'Do.Interface.Wink/src/Do.Interface.Wink/ScreenUtils.cs'
1178--- Do.Interface.Wink/src/Do.Interface.Wink/ScreenUtils.cs 1970-01-01 00:00:00 +0000
1179+++ Do.Interface.Wink/src/Do.Interface.Wink/ScreenUtils.cs 2009-04-01 01:08:07 +0000
1180@@ -0,0 +1,138 @@
1181+//
1182+// Copyright (C) 2009 GNOME Do
1183+//
1184+// This program is free software: you can redistribute it and/or modify
1185+// it under the terms of the GNU General Public License as published by
1186+// the Free Software Foundation, either version 3 of the License, or
1187+// (at your option) any later version.
1188+//
1189+// This program is distributed in the hope that it will be useful,
1190+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1191+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1192+// GNU General Public License for more details.
1193+//
1194+// You should have received a copy of the GNU General Public License
1195+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1196+//
1197+
1198+using System;
1199+using System.Collections.Generic;
1200+using System.Linq;
1201+
1202+using Mono.Unix;
1203+
1204+using Wnck;
1205+
1206+namespace Do.Interface.Wink
1207+{
1208+
1209+
1210+ public static class ScreenUtils
1211+ {
1212+ static string ViewportFormatString = Catalog.GetString ("Desktop") + " {0}";
1213+ static List<Viewport> viewports;
1214+
1215+ public static Viewport ActiveViewport {
1216+ get {
1217+ Workspace wsp = Wnck.Screen.Default.ActiveWorkspace;
1218+ Gdk.Rectangle geo = new Gdk.Rectangle (wsp.ViewportX, wsp.ViewportY, wsp.Screen.Width, wsp.Screen.Height);
1219+ if (viewports.Any (vp => vp.Area == geo))
1220+ return viewports.First (vp => vp.Area == geo);
1221+ return null;
1222+ }
1223+ }
1224+
1225+ public static IEnumerable<Viewport> Viewports {
1226+ get { return viewports.AsEnumerable (); }
1227+ }
1228+
1229+ static ScreenUtils ()
1230+ {
1231+ Wnck.Screen.Default.ViewportsChanged += HandleViewportsChanged;
1232+ Wnck.Screen.Default.WorkspaceCreated += HandleWorkspaceCreated;
1233+ Wnck.Screen.Default.WorkspaceDestroyed += HandleWorkspaceDestroyed;
1234+
1235+// Wnck.Screen.Default.ForceUpdate ();
1236+ UpdateViewports ();
1237+ }
1238+
1239+ static void HandleWorkspaceDestroyed(object o, WorkspaceDestroyedArgs args)
1240+ {
1241+ UpdateViewports ();
1242+ }
1243+
1244+ static void HandleWorkspaceCreated(object o, WorkspaceCreatedArgs args)
1245+ {
1246+ UpdateViewports ();
1247+ }
1248+
1249+ static void HandleViewportsChanged(object sender, EventArgs e)
1250+ {
1251+ UpdateViewports ();
1252+ }
1253+
1254+ public static bool DesktopShow (Screen screen)
1255+ {
1256+ return screen.ShowingDesktop;
1257+ }
1258+
1259+ public static void ShowDesktop (Screen screen)
1260+ {
1261+ if (!screen.ShowingDesktop)
1262+ screen.ToggleShowingDesktop (true);
1263+ }
1264+
1265+ public static void UnshowDesktop (Screen screen)
1266+ {
1267+ if (screen.ShowingDesktop)
1268+ screen.ToggleShowingDesktop (false);
1269+ }
1270+
1271+ public static IEnumerable<Window> ViewportWindows (Viewport viewport)
1272+ {
1273+ var windows = WindowUtils.GetWindows ()
1274+ .Where (w => w.WindowType != WindowType.Dock && !w.IsSkipTasklist);
1275+
1276+ foreach (Window window in windows) {
1277+ if (viewport.WindowCenterInViewport (window))
1278+ yield return window;
1279+ }
1280+ }
1281+
1282+ static void UpdateViewports ()
1283+ {
1284+ viewports = new List<Viewport> ();
1285+ int currentViewport = 1;
1286+ foreach (Wnck.Workspace workspace in Wnck.Screen.Default.Workspaces) {
1287+ if (workspace.IsVirtual) {
1288+ int viewportWidth;
1289+ int viewportHeight;
1290+ viewportWidth = workspace.Screen.Width;
1291+ viewportHeight = workspace.Screen.Height;
1292+
1293+ int rows = workspace.Height / viewportHeight;
1294+ int columns = workspace.Width / viewportWidth;
1295+
1296+ for (int i = 0; i < rows; i++) {
1297+ for (int j = 0; j < columns; j++) {
1298+ Gdk.Rectangle area = new Gdk.Rectangle (j * viewportWidth,
1299+ i * viewportHeight,
1300+ viewportWidth,
1301+ viewportHeight);
1302+ viewports.Add (new Viewport (string.Format (ViewportFormatString, currentViewport),
1303+ area,
1304+ workspace));
1305+ currentViewport++;
1306+ }
1307+ }
1308+ } else {
1309+ Viewport viewport = new Viewport (string.Format (ViewportFormatString, currentViewport),
1310+ new Gdk.Rectangle (0, 0, workspace.Width, workspace.Height),
1311+ workspace);
1312+ viewports.Add (viewport);
1313+ currentViewport++;
1314+ }
1315+ }
1316+ }
1317+ }
1318+}
1319
1320=== added file 'Do.Interface.Wink/src/Do.Interface.Wink/Viewport.cs'
1321--- Do.Interface.Wink/src/Do.Interface.Wink/Viewport.cs 1970-01-01 00:00:00 +0000
1322+++ Do.Interface.Wink/src/Do.Interface.Wink/Viewport.cs 2009-03-31 16:23:23 +0000
1323@@ -0,0 +1,142 @@
1324+//
1325+// Copyright (C) 2009 GNOME Do
1326+//
1327+// This program is free software: you can redistribute it and/or modify
1328+// it under the terms of the GNU General Public License as published by
1329+// the Free Software Foundation, either version 3 of the License, or
1330+// (at your option) any later version.
1331+//
1332+// This program is distributed in the hope that it will be useful,
1333+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1334+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1335+// GNU General Public License for more details.
1336+//
1337+// You should have received a copy of the GNU General Public License
1338+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1339+//
1340+
1341+using System;
1342+using System.Collections.Generic;
1343+using System.Runtime.InteropServices;
1344+
1345+
1346+using Gdk;
1347+using Wnck;
1348+
1349+using Do.Platform;
1350+using Do.Interface.Xlib;
1351+
1352+namespace Do.Interface.Wink
1353+{
1354+
1355+
1356+ public class Viewport
1357+ {
1358+ Workspace parent;
1359+ Rectangle area;
1360+
1361+ public string Name { get; private set; }
1362+
1363+ internal Rectangle Area {
1364+ get { return area; }
1365+ }
1366+
1367+ internal Viewport(string name, Rectangle area, Workspace parent)
1368+ {
1369+ this.area = area;
1370+ this.parent = parent;
1371+ Name = name;
1372+ }
1373+
1374+ public void MoveWindowInto (Wnck.Window window)
1375+ {
1376+ if (parent.IsVirtual) {
1377+ Rectangle geo;
1378+ window.GetGeometry (out geo.X, out geo.Y, out geo.Width, out geo.Height);
1379+
1380+ geo.X += window.Workspace.ViewportX;
1381+ geo.Y += window.Workspace.ViewportY;
1382+
1383+ int x = area.X + (geo.X % area.Width);
1384+ int y = area.Y + (geo.Y % area.Height);
1385+
1386+ x -= window.Workspace.ViewportX;
1387+ y -= window.Workspace.ViewportY;
1388+
1389+ if (string.Compare (window.Screen.WindowManagerName, "compiz", true) == 0) {
1390+ // This is a compiz-ism. Don't know when they will fix it. You must subtract the top and left
1391+ // frame extents from a move operation to get the window to actually show in the right spot.
1392+ // Save for maybe kwin, I think only compiz uses Viewports anyhow, so this is ok.
1393+ int [] extents = GetWindowFrameExtents (window);
1394+ int left_extent = extents [0];
1395+ int top_extent = extents [2];
1396+
1397+ x -= left_extent;
1398+ y -= top_extent;
1399+ }
1400+
1401+ WindowMoveResizeMask mask = WindowMoveResizeMask.X | WindowMoveResizeMask.Y;
1402+ window.SetGeometry (WindowGravity.Current, mask, x, y, 0, 0);
1403+ } else {
1404+ window.MoveToWorkspace (parent);
1405+ }
1406+ }
1407+
1408+ int[] GetWindowFrameExtents (Wnck.Window window)
1409+ {
1410+ X11Atoms atoms = X11Atoms.Instance;
1411+
1412+ IntPtr display;
1413+ IntPtr type;
1414+ int format;
1415+ IntPtr prop_return;
1416+ IntPtr nitems, bytes_after;
1417+ int result;
1418+ int [] extents = new int[4];
1419+
1420+ IntPtr window_handle = (IntPtr) window.Xid;
1421+
1422+ display = Xlib.Xlib.GdkDisplayXDisplay (Gdk.Screen.Default.Display);
1423+ type = IntPtr.Zero;
1424+
1425+ result = Xlib.Xlib.XGetWindowProperty (display, window_handle, atoms._NET_FRAME_EXTENTS, (IntPtr) 0,
1426+ (IntPtr) System.Int32.MaxValue, false, atoms.XA_CARDINAL, out type, out format,
1427+ out nitems, out bytes_after, out prop_return);
1428+
1429+ if (type == atoms.XA_CARDINAL && format == 32) {
1430+ extents = new int [(int) nitems];
1431+ for (int i = 0; i < (int) nitems; i++) {
1432+ extents [i] = Marshal.ReadInt32 (prop_return, i * 4);
1433+ }
1434+ }
1435+
1436+ return extents;
1437+ }
1438+
1439+ public bool WindowVisibleInVeiwport (Wnck.Window window)
1440+ {
1441+ Rectangle geo;
1442+ window.GetGeometry (out geo.X, out geo.Y, out geo.Width, out geo.Height);
1443+ geo.X += parent.ViewportX;
1444+ geo.Y += parent.ViewportY;
1445+
1446+ return area.IntersectsWith (geo);
1447+ }
1448+
1449+ public bool WindowCenterInViewport (Wnck.Window window)
1450+ {
1451+ Rectangle geo;
1452+ window.GetGeometry (out geo.X, out geo.Y, out geo.Width, out geo.Height);
1453+ geo.X += parent.ViewportX;
1454+ geo.Y += parent.ViewportY;
1455+
1456+ Point center = new Point (geo.X + geo.Width / 2, geo.Y + geo.Height / 2);
1457+ return Contains (center);
1458+ }
1459+
1460+ public bool Contains (Gdk.Point point)
1461+ {
1462+ return area.Contains (point);
1463+ }
1464+ }
1465+}
1466
1467=== modified file 'Do.Interface.Wink/src/Do.Interface.Wink/WindowControl.cs'
1468--- Do.Interface.Wink/src/Do.Interface.Wink/WindowControl.cs 2009-03-20 20:43:06 +0000
1469+++ Do.Interface.Wink/src/Do.Interface.Wink/WindowControl.cs 2009-03-31 03:39:44 +0000
1470@@ -88,11 +88,18 @@
1471
1472 public static void FocusWindows (IEnumerable<Window> windows)
1473 {
1474- foreach (Window window in windows.Reverse ()) {
1475- if (window.IsInViewport (window.Screen.ActiveWorkspace) && !window.IsMinimized) {
1476- window.CenterAndFocusWindow ();
1477- System.Threading.Thread.Sleep (SleepTime);
1478+ if (!windows.Any ())
1479+ return;
1480+
1481+ if (windows.Any (w => w.IsInViewport (w.Screen.ActiveWorkspace))) {
1482+ foreach (Window window in windows.Reverse ()) {
1483+ if (window.IsInViewport (window.Screen.ActiveWorkspace) && !window.IsMinimized) {
1484+ window.CenterAndFocusWindow ();
1485+ System.Threading.Thread.Sleep (SleepTime);
1486+ }
1487 }
1488+ } else {
1489+ windows.First ().CenterAndFocusWindow ();
1490 }
1491
1492 if (windows.Count () <= 1)
1493@@ -102,7 +109,9 @@
1494 // sometimes compiz plays badly. This hacks around it
1495 uint time = Gtk.Global.CurrentEventTime + 200;
1496 GLib.Timeout.Add (200, delegate {
1497- windows.Where (w => w.IsInViewport (w.Screen.ActiveWorkspace) && !w.IsMinimized).First ().Activate (time);
1498+ try { //unimportant if this fails, its just "nice"
1499+ windows.Where (w => w.IsInViewport (w.Screen.ActiveWorkspace) && !w.IsMinimized).First ().Activate (time);
1500+ } catch { }
1501 return false;
1502 });
1503 }
1504@@ -187,6 +196,17 @@
1505 window.Maximize ();
1506 }
1507
1508+ public static void MoveToWorkspace (Window window, Workspace workspace)
1509+ {
1510+ MoveToWorkspace (new [] {window}, workspace);
1511+ }
1512+
1513+ public static void MoveToWorkspace (IEnumerable<Window> windows, Workspace workspace)
1514+ {
1515+ foreach (Window window in windows.Where (w => w.Workspace != workspace))
1516+ window.MoveToWorkspace (workspace);
1517+ }
1518+
1519 /// <summary>
1520 /// Moves the current viewport to the selected window and then raises it
1521 /// </summary>
1522
1523=== modified file 'Do.Interface.Wink/src/Do.Interface.Wink/WindowUtils.cs'
1524--- Do.Interface.Wink/src/Do.Interface.Wink/WindowUtils.cs 2009-03-21 02:35:05 +0000
1525+++ Do.Interface.Wink/src/Do.Interface.Wink/WindowUtils.cs 2009-04-01 01:08:07 +0000
1526@@ -29,12 +29,6 @@
1527
1528 namespace Do.Interface.Wink
1529 {
1530- public enum ClickAction {
1531- Focus,
1532- Minimize,
1533- Restore,
1534- None,
1535- }
1536
1537 public static class WindowUtils
1538 {
1539@@ -42,7 +36,7 @@
1540 get { return Path.Combine (Services.Paths.UserDataDirectory, "RemapFile"); }
1541 }
1542
1543- public static IEnumerable<string> BadPrefixes {
1544+ static IEnumerable<string> PrefixStrings {
1545 get {
1546 yield return "gksu";
1547 yield return "sudo";
1548@@ -55,35 +49,46 @@
1549 }
1550 }
1551
1552+ public static IEnumerable<Regex> BadPrefixes { get; private set; }
1553+
1554 static Dictionary<string, string> RemapDictionary { get; set; }
1555
1556- static List<Application> application_list;
1557- static bool application_list_update_needed;
1558+ static List<Window> window_list;
1559+ static bool window_list_update_needed;
1560
1561 static Dictionary<int, string> exec_lines = new Dictionary<int, string> ();
1562 static DateTime last_update = new DateTime (0);
1563
1564+ #region ctor
1565 static WindowUtils ()
1566 {
1567+ List<Regex> regex = new List<Regex> ();
1568+ foreach (string s in PrefixStrings) {
1569+ regex.Add (new Regex (string.Format ("^{0}$", s), RegexOptions.IgnoreCase));
1570+ }
1571+ BadPrefixes = regex.AsEnumerable ();
1572+
1573 Wnck.Screen.Default.WindowClosed += delegate {
1574- application_list_update_needed = true;
1575+ window_list_update_needed = true;
1576 };
1577
1578 Wnck.Screen.Default.WindowOpened += delegate {
1579- application_list_update_needed = true;
1580+ window_list_update_needed = true;
1581 };
1582
1583 Wnck.Screen.Default.ApplicationOpened += delegate {
1584- application_list_update_needed = true;
1585+ window_list_update_needed = true;
1586 };
1587
1588 Wnck.Screen.Default.ApplicationClosed += delegate {
1589- application_list_update_needed = true;
1590+ window_list_update_needed = true;
1591 };
1592
1593 BuildRemapDictionary ();
1594 }
1595+ #endregion
1596
1597+ #region Private Methods
1598 static void BuildRemapDictionary ()
1599 {
1600 if (!File.Exists (RemapFile)) {
1601@@ -151,117 +156,39 @@
1602 return remapDict;
1603 }
1604
1605- /// <summary>
1606- /// Returns a list of all applications on the default screen
1607- /// </summary>
1608- /// <returns>
1609- /// A <see cref="Application"/> array
1610- /// </returns>
1611- public static List<Application> GetApplications ()
1612- {
1613- if (application_list == null || application_list_update_needed) {
1614- application_list = new List<Application> ();
1615- foreach (Window w in Wnck.Screen.Default.Windows) {
1616- if (!application_list.Contains (w.Application))
1617- application_list.Add (w.Application);
1618- }
1619- }
1620- return application_list;
1621- }
1622-
1623- /// <summary>
1624- /// Gets the command line excec string for a PID
1625- /// </summary>
1626- /// <param name="pid">
1627- /// A <see cref="System.Int32"/>
1628- /// </param>
1629- /// <returns>
1630- /// A <see cref="System.String"/>
1631- /// </returns>
1632- public static string CmdLineForPid (int pid)
1633- {
1634- StreamReader reader;
1635- string cmdline = null;
1636-
1637- try {
1638- string procPath = new [] { "/proc", pid.ToString (), "cmdline" }.Aggregate (Path.Combine);
1639- reader = new StreamReader (procPath);
1640- cmdline = reader.ReadLine ().Replace (Convert.ToChar (0x0), ' ');
1641- reader.Close ();
1642- reader.Dispose ();
1643- } catch { }
1644-
1645- return cmdline;
1646- }
1647-
1648- /// <summary>
1649- /// Returns a list of applications that match an exec string
1650- /// </summary>
1651- /// <param name="exec">
1652- /// A <see cref="System.String"/>
1653- /// </param>
1654- /// <returns>
1655- /// A <see cref="List"/>
1656- /// </returns>
1657- public static List<Application> GetApplicationList (string exec)
1658- {
1659- List<Application> apps = new List<Application> ();
1660- if (string.IsNullOrEmpty (exec))
1661- return apps;
1662-
1663- exec = ProcessExecString (exec);
1664- if (string.IsNullOrEmpty (exec))
1665- return apps;
1666-
1667- UpdateExecList ();
1668-
1669- foreach (KeyValuePair<int, string> kvp in exec_lines) {
1670- if (kvp.Value != null && kvp.Value.Contains (exec)) {
1671- foreach (Application app in GetApplications ()) {
1672- if (app == null)
1673- continue;
1674-
1675- if (app.Pid == kvp.Key || app.Windows.Any (w => w.Pid == kvp.Key)) {
1676- if (app.Windows.Any (win => !win.IsSkipTasklist))
1677- apps.Add (app);
1678- break;
1679- }
1680- }
1681- }
1682- }
1683- return apps;
1684- }
1685-
1686 static void UpdateExecList ()
1687 {
1688 if ((DateTime.UtcNow - last_update).TotalMilliseconds < 200) return;
1689
1690- exec_lines.Clear ();
1691+ Dictionary<int, string> old = exec_lines;
1692+
1693+ exec_lines = new Dictionary<int, string> ();
1694
1695 foreach (string dir in Directory.GetDirectories ("/proc")) {
1696 int pid;
1697 try { pid = Convert.ToInt32 (Path.GetFileName (dir)); }
1698 catch { continue; }
1699
1700+ if (old.ContainsKey (pid)) {
1701+ exec_lines [pid] = old [pid];
1702+ continue;
1703+ }
1704+
1705 string exec_line = CmdLineForPid (pid);
1706 if (string.IsNullOrEmpty (exec_line))
1707 continue;
1708
1709 if (exec_line.Contains ("java") && exec_line.Contains ("jar")) {
1710- foreach (Application app in GetApplications ()) {
1711- if (app == null)
1712+ foreach (Window window in GetWindows ()) {
1713+ if (window == null)
1714 continue;
1715
1716- if (app.Pid == pid || app.Windows.Any (w => w.Pid == pid)) {
1717- foreach (Wnck.Window window in app.Windows.Where (win => !win.IsSkipTasklist)) {
1718- exec_line = window.ClassGroup.ResClass;
1719+ if (window.Pid == pid || window.Application.Pid == pid) {
1720+ exec_line = window.ClassGroup.ResClass;
1721
1722- // Vuze is retarded
1723- if (exec_line == "SWT")
1724- exec_line = window.Name;
1725- Console.WriteLine (exec_line);
1726- break;
1727- }
1728+ // Vuze is retarded
1729+ if (exec_line == "SWT")
1730+ exec_line = window.Name;
1731 }
1732 }
1733 }
1734@@ -273,16 +200,126 @@
1735
1736 last_update = DateTime.UtcNow;
1737 }
1738-
1739+
1740+ static ClickAction GetClickAction (IEnumerable<Window> windows)
1741+ {
1742+ if (!windows.Any ())
1743+ return ClickAction.None;
1744+
1745+ if (windows.Any (w => w.IsMinimized && w.IsInViewport (Wnck.Screen.Default.ActiveWorkspace)))
1746+ return ClickAction.Restore;
1747+
1748+ if (windows.Any (w => w.IsActive && w.IsInViewport (Wnck.Screen.Default.ActiveWorkspace)))
1749+ return ClickAction.Minimize;
1750+
1751+ return ClickAction.Focus;
1752+ }
1753+ #endregion
1754+
1755+ #region Public Methods
1756+ /// <summary>
1757+ /// Returns a list of all windows on the default screen
1758+ /// </summary>
1759+ /// <returns>
1760+ /// A <see cref="List"/>
1761+ /// </returns>
1762+ public static List<Window> GetWindows ()
1763+ {
1764+ if (window_list == null || window_list_update_needed)
1765+ window_list = new List<Window> (Wnck.Screen.Default.WindowsStacked);
1766+
1767+ return window_list;
1768+ }
1769+
1770+ /// <summary>
1771+ /// Gets the command line excec string for a PID
1772+ /// </summary>
1773+ /// <param name="pid">
1774+ /// A <see cref="System.Int32"/>
1775+ /// </param>
1776+ /// <returns>
1777+ /// A <see cref="System.String"/>
1778+ /// </returns>
1779+ public static string CmdLineForPid (int pid)
1780+ {
1781+ string cmdline = null;
1782+
1783+ try {
1784+ string procPath = new [] { "/proc", pid.ToString (), "cmdline" }.Aggregate (Path.Combine);
1785+ using (StreamReader reader = new StreamReader (procPath)) {
1786+ cmdline = reader.ReadLine ();
1787+ reader.Close ();
1788+ }
1789+ } catch { }
1790+
1791+ return cmdline;
1792+ }
1793+
1794+ public static List<Window> WindowListForCmd (string exec)
1795+ {
1796+ List<Window> windows = new List<Window> ();
1797+ if (string.IsNullOrEmpty (exec))
1798+ return windows;
1799+
1800+ exec = ProcessExecString (exec);
1801+ if (string.IsNullOrEmpty (exec))
1802+ return windows;
1803+
1804+ UpdateExecList ();
1805+
1806+ foreach (KeyValuePair<int, string> kvp in exec_lines) {
1807+ if (!string.IsNullOrEmpty (kvp.Value) && kvp.Value.Contains (exec)) {
1808+ // we have a matching exec, now we just find every window whose PID matches this exec
1809+ foreach (Window window in GetWindows ()) {
1810+ if (window == null)
1811+ continue;
1812+
1813+ // this window matches the right PID and exec string, we can match it.
1814+ bool pidMatch = window.Pid == kvp.Key ||
1815+ (window.Application != null && window.Application.Pid == kvp.Key);
1816+
1817+ if (pidMatch && !windows.Contains (window))
1818+ windows.Add (window);
1819+ }
1820+ }
1821+ }
1822+
1823+ return windows;
1824+ }
1825+
1826+ /// <summary>
1827+ /// This method takes in an "execution string" from proc and applies a heureustic to try
1828+ /// to magic out the name of the actual executing application. The executing binary is not
1829+ /// the desired target all the time.
1830+ /// </summary>
1831+ /// <param name="exec">
1832+ /// A <see cref="System.String"/>
1833+ /// </param>
1834+ /// <returns>
1835+ /// A <see cref="System.String"/>
1836+ /// </returns>
1837 public static string ProcessExecString (string exec)
1838 {
1839+ if (string.IsNullOrEmpty (exec))
1840+ return exec;
1841+
1842+ // lower it and trim off white space so we can abuse whitespace a bit
1843 exec = exec.ToLower ().Trim ();
1844
1845+ // if the user has specified a specific mapping, we can use that here
1846 if (RemapDictionary.ContainsKey (exec))
1847 return RemapDictionary [exec];
1848
1849+ // this is the "split" character or the argument separator. If the string contains a null
1850+ // it was fetched from /proc/PID/cmdline and will be nicely split up. Otherwise things get a bit
1851+ // nasty, and it likely came from a .desktop file.
1852+ char splitChar = Convert.ToChar (0x0);
1853+ splitChar = exec.Contains (splitChar) ? splitChar : ' ';
1854+
1855+ // this part is here soley for the remap file so that users may specify to remap based on just the name
1856+ // without the full path. If no remap file match is found, the net effect of this is nothing.
1857 if (exec.StartsWith ("/")) {
1858- string first_part = exec.Split (' ') [0];
1859+ string first_part = exec.Split (splitChar) [0];
1860 int length = first_part.Length;
1861 first_part = first_part.Split ('/').Last ();
1862
1863@@ -294,25 +331,38 @@
1864 }
1865 }
1866
1867- string [] parts = exec.Split (' ');
1868+ string [] parts = exec.Split (splitChar);
1869 for (int i = 0; i < parts.Length; i++) {
1870- if (parts [i].StartsWith ("-"))
1871+ // we're going to use this a lot
1872+ string out_val = parts [i];
1873+
1874+ // arguments are useless
1875+ if (out_val.StartsWith ("-"))
1876 continue;
1877
1878- if (parts [i].Contains ("/"))
1879- parts [i] = parts [i].Split ('/').Last ();
1880-
1881- Regex regex;
1882- foreach (string prefix in BadPrefixes) {
1883- regex = new Regex (string.Format ("^{0}$", prefix), RegexOptions.IgnoreCase);
1884- if (regex.IsMatch (parts [i])) {
1885- parts [i] = null;
1886+ // we want the end of paths
1887+ if (out_val.Contains ("/"))
1888+ out_val = out_val.Split ('/').Last ();
1889+
1890+ // wine apps can do it backwards... who knew?
1891+ if (out_val.Contains ("\\"))
1892+ out_val = out_val.Split ('\\').Last ();
1893+
1894+ // null out our part if is a bad prefix
1895+ foreach (Regex regex in BadPrefixes) {
1896+ if (regex.IsMatch (out_val)) {
1897+ out_val = null;
1898 break;
1899 }
1900 }
1901
1902- if (!string.IsNullOrEmpty (parts [i])) {
1903- string out_val = parts [i];
1904+ // check if it was a bad prefix...
1905+ if (!string.IsNullOrEmpty (out_val)) {
1906+ // sometimes we hide things with shell scripts. This is the most common method of doing it.
1907+ if (out_val.EndsWith (".real"))
1908+ out_val = out_val.Substring (0, out_val.Length - ".real".Length);
1909+
1910+ // give the remap dictionary one last shot at this
1911 if (RemapDictionary.ContainsKey (out_val))
1912 out_val = RemapDictionary [out_val];
1913 return out_val;
1914@@ -327,12 +377,10 @@
1915 /// <param name="apps">
1916 /// A <see cref="IEnumerable"/>
1917 /// </param>
1918- public static void PerformLogicalClick (IEnumerable<Application> apps)
1919+ public static void PerformLogicalClick (IEnumerable<Window> windows)
1920 {
1921 List<Window> stack = new List<Window> (Wnck.Screen.Default.WindowsStacked);
1922- IEnumerable<Window> windows = apps
1923- .SelectMany (app => app.Windows)
1924- .OrderByDescending (w => stack.IndexOf (w));
1925+ windows = windows.OrderByDescending (w => stack.IndexOf (w));
1926
1927 bool not_in_viewport = !windows.Any (w => !w.IsSkipTasklist && w.IsInViewport (w.Screen.ActiveWorkspace));
1928 bool urgent = windows.Any (w => w.NeedsAttention ());
1929@@ -348,7 +396,7 @@
1930 }
1931 }
1932
1933- switch (GetClickAction (apps)) {
1934+ switch (GetClickAction (windows)) {
1935 case ClickAction.Focus:
1936 WindowControl.FocusWindows (windows);
1937 break;
1938@@ -361,26 +409,6 @@
1939 }
1940 }
1941
1942- static ClickAction GetClickAction (IEnumerable<Application> apps)
1943- {
1944- if (!apps.Any ())
1945- return ClickAction.None;
1946-
1947- foreach (Wnck.Application app in apps) {
1948- foreach (Wnck.Window window in app.Windows) {
1949- if (window.IsMinimized && window.IsInViewport (Wnck.Screen.Default.ActiveWorkspace))
1950- return ClickAction.Restore;
1951- }
1952- }
1953-
1954- foreach (Wnck.Application app in apps) {
1955- foreach (Wnck.Window window in app.Windows) {
1956- if (window.IsActive && window.IsInViewport (Wnck.Screen.Default.ActiveWorkspace))
1957- return ClickAction.Minimize;
1958- }
1959- }
1960-
1961- return ClickAction.Focus;
1962- }
1963+ #endregion
1964 }
1965 }
1966
1967=== added directory 'Do.Interface.Wink/src/Do.Interface.Xlib'
1968=== renamed file 'Do.Interface.Linux.Docky/src/XLib/X11Atoms.cs' => 'Do.Interface.Wink/src/Do.Interface.Xlib/X11Atoms.cs'
1969--- Do.Interface.Linux.Docky/src/XLib/X11Atoms.cs 2009-02-23 04:01:36 +0000
1970+++ Do.Interface.Wink/src/Do.Interface.Xlib/X11Atoms.cs 2009-03-31 16:23:23 +0000
1971@@ -23,9 +23,18 @@
1972
1973 using System;
1974
1975-namespace Docky.XLib {
1976+namespace Do.Interface.Xlib {
1977
1978- internal class X11Atoms {
1979+ public class X11Atoms {
1980+
1981+ static X11Atoms instance;
1982+ public static X11Atoms Instance {
1983+ get {
1984+ if (instance == null)
1985+ instance = new X11Atoms (Gdk.Screen.Default.Display);
1986+ return instance;
1987+ }
1988+ }
1989
1990 // Our atoms
1991 public readonly IntPtr AnyPropertyType = (IntPtr)0;
1992@@ -169,8 +178,8 @@
1993 public readonly IntPtr AsyncAtom;
1994
1995
1996- public X11Atoms (Gdk.Window window) {
1997- IntPtr display = XLib.Xlib.GdkDrawableXDisplay (window);
1998+ X11Atoms (Gdk.Display dsp) {
1999+ IntPtr display = Xlib.GdkDisplayXDisplay (dsp);
2000 // make sure this array stays in sync with the statements below
2001 string [] atom_names = new string[] {
2002 "WM_PROTOCOLS",
2003
2004=== renamed file 'Do.Interface.Linux.Docky/src/XLib/Xlib.cs' => 'Do.Interface.Wink/src/Do.Interface.Xlib/Xlib.cs'
2005--- Do.Interface.Linux.Docky/src/XLib/Xlib.cs 2009-01-12 20:15:41 +0000
2006+++ Do.Interface.Wink/src/Do.Interface.Xlib/Xlib.cs 2009-03-31 16:23:23 +0000
2007@@ -27,7 +27,7 @@
2008 using System.Collections.Generic;
2009 using System.Linq;
2010
2011-namespace Docky.XLib {
2012+namespace Do.Interface.Xlib {
2013
2014 public enum PropertyMode
2015 {
2016@@ -52,7 +52,7 @@
2017 BottomEnd = 11
2018 }
2019
2020- internal class Xlib {
2021+ public static class Xlib {
2022 const string libX11 = "X11";
2023 const string libGdkX11 = "libgdk-x11";
2024
2025@@ -61,7 +61,24 @@
2026
2027 [DllImport (libGdkX11)]
2028 static extern IntPtr gdk_x11_drawable_get_xdisplay (IntPtr handle);
2029+
2030+ [DllImport (libGdkX11)]
2031+ static extern IntPtr gdk_x11_display_get_xdisplay (IntPtr display);
2032
2033+ [DllImport (libX11)]
2034+ public extern static IntPtr XOpenDisplay (IntPtr display);
2035+
2036+ [DllImport (libX11)]
2037+ public extern static int XInternAtoms (IntPtr display, string[] atom_names, int atom_count, bool only_if_exists, IntPtr[] atoms);
2038+
2039+ [DllImport (libX11)]
2040+ extern static int XChangeProperty (IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, int mode, IntPtr[] data, int nelements);
2041+
2042+ [DllImport (libX11)]
2043+ public extern static int XGetWindowProperty (IntPtr display, IntPtr window, IntPtr atom, IntPtr long_offset,
2044+ IntPtr long_length, bool delete, IntPtr req_type, out IntPtr actual_type,
2045+ out int actual_format, out IntPtr nitems, out IntPtr bytes_after, out IntPtr prop);
2046+
2047 public static IntPtr GdkWindowX11Xid (Gdk.Window window)
2048 {
2049 return gdk_x11_drawable_get_xid (window.Handle);
2050@@ -72,19 +89,16 @@
2051 return gdk_x11_drawable_get_xdisplay (window.Handle);
2052 }
2053
2054- [DllImport (libX11)]
2055- public extern static IntPtr XOpenDisplay (IntPtr display);
2056-
2057- [DllImport (libX11)]
2058- public extern static int XInternAtoms (IntPtr display, string[] atom_names, int atom_count, bool only_if_exists, IntPtr[] atoms);
2059-
2060- [DllImport (libX11)]
2061- extern static int XChangeProperty (IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, int mode, IntPtr[] data, int nelements);
2062-
2063+ public static IntPtr GdkDisplayXDisplay (Gdk.Display display)
2064+ {
2065+ return gdk_x11_display_get_xdisplay (display.Handle);
2066+ }
2067+
2068 public static int XChangeProperty (Gdk.Window window, IntPtr property, IntPtr type, int mode, uint[] data)
2069 {
2070 IntPtr [] dataArray = data.Select (i => (IntPtr) i).ToArray ();
2071 return XChangeProperty (GdkDrawableXDisplay (window), GdkWindowX11Xid (window), property, type, 32, mode, dataArray, data.Length);
2072 }
2073+
2074 }
2075 }
2076
2077=== modified file 'Do.Platform.Linux/src/Do.Platform/Do.Platform.Linux/UniverseFactoryService.cs'
2078--- Do.Platform.Linux/src/Do.Platform/Do.Platform.Linux/UniverseFactoryService.cs 2009-01-21 23:44:40 +0000
2079+++ Do.Platform.Linux/src/Do.Platform/Do.Platform.Linux/UniverseFactoryService.cs 2009-03-24 15:04:23 +0000
2080@@ -18,6 +18,8 @@
2081 //
2082
2083 using System;
2084+using System.Collections.Generic;
2085+using System.Linq;
2086
2087 using Do.Universe;
2088 using Do.Universe.Linux;
2089@@ -28,7 +30,6 @@
2090
2091 public class UniverseFactoryService : IUniverseFactoryService
2092 {
2093-
2094 public IFileItem NewFileItem (string path)
2095 {
2096 return new FileItem (path);
2097@@ -41,5 +42,10 @@
2098 IApplicationItem maybe = ApplicationItem.MaybeCreateFromDesktopItem (path);
2099 return maybe ?? new NullApplicationItem (path);
2100 }
2101+
2102+ public IApplicationItem MaybeApplicationItemFromCommand (string cmd)
2103+ {
2104+ return ApplicationItem.MaybeCreateFromCmd (cmd);
2105+ }
2106 }
2107 }
2108
2109=== modified file 'Do.Platform.Linux/src/Do.Universe/ApplicationItem.cs'
2110--- Do.Platform.Linux/src/Do.Universe/ApplicationItem.cs 2009-01-23 23:01:37 +0000
2111+++ Do.Platform.Linux/src/Do.Universe/ApplicationItem.cs 2009-03-29 17:52:17 +0000
2112@@ -22,6 +22,7 @@
2113 using System.Linq;
2114 using System.Collections.Generic;
2115 using System.Runtime.InteropServices;
2116+using System.Text.RegularExpressions;
2117
2118 using Gnome;
2119 using Mono.Unix;
2120@@ -68,6 +69,34 @@
2121 }
2122 return appItem;
2123 }
2124+
2125+ public static ApplicationItem MaybeCreateFromCmd (string cmd)
2126+ {
2127+ ApplicationItem appItem = null;
2128+
2129+ if (string.IsNullOrEmpty (cmd))
2130+ return appItem;
2131+
2132+ cmd = Regex.Escape (cmd);
2133+ Regex regex = new Regex (string .Format ("(^| ){0}( |)", cmd));
2134+ foreach (ApplicationItem item in Instances.Values) {
2135+ string path = item.Location;
2136+ try {
2137+ if (path.StartsWith ("file://"))
2138+ path = path.Substring ("file://".Length);
2139+
2140+ path = Path.GetFileName (path);
2141+ } catch { continue; }
2142+
2143+ if (regex.IsMatch (path) || regex.IsMatch (item.Exec)) {
2144+ appItem = item;
2145+ if (item.IsAppropriateForCurrentDesktop && !item.Hidden)
2146+ break;
2147+ }
2148+ }
2149+
2150+ return appItem;
2151+ }
2152
2153 protected DesktopItem item;
2154 string name, description, icon, mimetype;
2155@@ -115,6 +144,10 @@
2156 public string Exec {
2157 get { return item.GetString ("Exec"); }
2158 }
2159+
2160+ protected string Location {
2161+ get { return item.Location; }
2162+ }
2163
2164 public bool Hidden {
2165 get { return item.GetBoolean ("NoDisplay"); }
2166
2167=== modified file 'Do.Platform/src/Do.Platform/Do.Platform.Default/UniverseFactoryService.cs'
2168--- Do.Platform/src/Do.Platform/Do.Platform.Default/UniverseFactoryService.cs 2008-12-12 01:41:51 +0000
2169+++ Do.Platform/src/Do.Platform/Do.Platform.Default/UniverseFactoryService.cs 2009-03-24 15:04:23 +0000
2170@@ -41,6 +41,12 @@
2171 Log.Debug ("Default IUniverseFactoryService cannot return a useful IApplicationItem.");
2172 return new EmptyApplicationItem ();
2173 }
2174+
2175+ public IApplicationItem MaybeApplicationItemFromCommand (string cmd)
2176+ {
2177+ Log.Debug ("Default IUniverseFactoryService cannot return a useful IApplicationItem.");
2178+ return null;
2179+ }
2180
2181 class EmptyFileItem : EmptyItem, IFileItem
2182 {
2183
2184=== modified file 'Do.Platform/src/Do.Platform/IUniverseFactoryService.cs'
2185--- Do.Platform/src/Do.Platform/IUniverseFactoryService.cs 2008-12-22 00:36:53 +0000
2186+++ Do.Platform/src/Do.Platform/IUniverseFactoryService.cs 2009-03-24 15:04:23 +0000
2187@@ -31,5 +31,6 @@
2188 {
2189 IFileItem NewFileItem (string path);
2190 IApplicationItem NewApplicationItem (string path);
2191+ IApplicationItem MaybeApplicationItemFromCommand (string cmd);
2192 }
2193 }
2194
2195=== modified file 'Do.mds'
2196--- Do.mds 2009-03-28 15:34:37 +0000
2197+++ Do.mds 2009-03-31 17:48:02 +0000
2198@@ -64,4 +64,4 @@
2199 <Entry filename="Do.Interface.Linux.HUD/Do.Interface.Linux.HUD.mdp" />
2200 <Entry filename="Do.Interface.Wink/Do.Interface.Wink.mdp" />
2201 </Entries>
2202-</Combine>
2203+</Combine>
2204\ No newline at end of file
2205
2206=== modified file 'Do/gnome-do.in'
2207--- Do/gnome-do.in 2008-10-27 07:23:04 +0000
2208+++ Do/gnome-do.in 2009-03-24 15:04:23 +0000
2209@@ -18,8 +18,8 @@
2210
2211 # If Do is not running, run it.
2212 if pgrep -u "`id -un`" '^gnome-do$' >/dev/null; then
2213- mono "$GNOME_DO_EXE" "$@"
2214+ mono --debug "$GNOME_DO_EXE" "$@" > ~/do.trace 2>&1
2215 fi
2216 while [ "$?" -eq "20" ]; do
2217- mono "$GNOME_DO_EXE" "$@"
2218+ mono --debug "$GNOME_DO_EXE" "$@" > ~/do.trace 2>&1
2219 done