2
// Copyright (C) 2009 Jason Smith
4
// This program is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
9
// This program is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
// GNU General Public License for more details.
14
// You should have received a copy of the GNU General Public License
15
// along with this program. If not, see <http://www.gnu.org/licenses/>.
19
using System.Collections.Generic;
20
using System.ComponentModel;
31
namespace Docky.Interface
35
public class AutohideManager : IDisposable
37
public event EventHandler HiddenChanged;
38
public event EventHandler DockHoveredChanged;
40
Gdk.Rectangle cursor_area, intersect_area, last_known_geo;
42
CursorTracker tracker;
46
bool WindowIntersectingOther { get; set; }
49
public bool DockHovered {
50
get { return dockHoverd; }
52
if (dockHoverd == value)
56
OnDockHoveredChanged ();
62
get { return hidden; }
72
AutohideType behavior;
73
public AutohideType Behavior {
74
get { return behavior; }
76
if (behavior == value)
80
if (behavior == AutohideType.None) {
86
internal AutohideManager (Gdk.Screen screen)
88
pid = System.Diagnostics.Process.GetCurrentProcess ().Id;
90
tracker = CursorTracker.ForDisplay (screen.Display);
91
this.screen = Wnck.Screen.Get (screen.Number);
93
tracker.CursorPositionChanged += HandleCursorPositionChanged;
94
this.screen.ActiveWindowChanged += HandleActiveWindowChanged;
95
this.screen.WindowOpened += HandleWindowOpened;
96
this.screen.WindowClosed += HandleWindowClosed;
99
public void SetCursorArea (Gdk.Rectangle area)
101
if (cursor_area == area)
104
DockHovered = cursor_area.Contains (tracker.Cursor)
105
&& (screen.ActiveWindow == null || (screen.ActiveWindow != null && !screen.ActiveWindow.IsFullscreen));
110
public void SetIntersectArea (Gdk.Rectangle area)
112
if (intersect_area == area)
115
intersect_area = area;
116
UpdateWindowIntersect ();
119
void HandleCursorPositionChanged (object sender, CursorPostionChangedArgs args)
121
DockHovered = cursor_area.Contains (tracker.Cursor)
122
&& (screen.ActiveWindow == null || (screen.ActiveWindow != null && !screen.ActiveWindow.IsFullscreen));
126
void HandleActiveWindowChanged (object o, ActiveWindowChangedArgs args)
128
if (args.PreviousWindow != null)
129
args.PreviousWindow.GeometryChanged -= HandleGeometryChanged;
132
GLib.Source.Remove (timer);
134
timer = GLib.Timeout.Add (200, delegate {
135
SetupActiveWindow ();
136
UpdateWindowIntersect ();
142
void HandleWindowOpened (object sender, WindowOpenedArgs args)
144
UpdateWindowIntersect ();
147
void HandleWindowClosed (object sender, WindowClosedArgs args)
149
UpdateWindowIntersect ();
152
void SetupActiveWindow ()
154
Wnck.Window active = screen.ActiveWindow;
155
if (active != null) {
156
active.GeometryChanged += HandleGeometryChanged;
157
last_known_geo = active.EasyGeometry ();
161
void HandleGeometryChanged (object sender, EventArgs e)
163
Wnck.Window window = sender as Wnck.Window;
168
Gdk.Rectangle geo = window.EasyGeometry ();
170
if (geo == last_known_geo)
173
last_known_geo = geo;
176
GLib.Source.Remove (timer);
178
timer = GLib.Timeout.Add (200, delegate {
179
UpdateWindowIntersect ();
185
bool IsIntersectableWindow (Wnck.Window window)
187
return window != null &&
188
!window.IsMinimized &&
190
window.WindowType != Wnck.WindowType.Desktop &&
191
window.WindowType != Wnck.WindowType.Dock &&
192
window.WindowType != Wnck.WindowType.Splashscreen &&
193
window.WindowType != Wnck.WindowType.Menu &&
194
Wnck.Screen.Default.ActiveWorkspace != null &&
195
window.IsVisibleOnWorkspace (Wnck.Screen.Default.ActiveWorkspace);
198
void UpdateWindowIntersect ()
200
Gdk.Rectangle adjustedDockArea = intersect_area;
201
adjustedDockArea.Inflate (-2, -2);
203
bool intersect = false;
204
Wnck.Window activeWindow = screen.ActiveWindow;
207
foreach (Wnck.Window window in screen.Windows.Where (w => IsIntersectableWindow (w))) {
208
if (Behavior == AutohideType.Intellihide && activeWindow != null && activeWindow.Pid != window.Pid) {
212
if (window.EasyGeometry ().IntersectsWith (adjustedDockArea)) {
217
} catch (Exception e) {
218
Log<AutohideManager>.Error ("Failed to update window intersect: '{0}'", e.Message);
219
Log<AutohideManager>.Debug (e.StackTrace);
222
if (WindowIntersectingOther != intersect) {
223
WindowIntersectingOther = intersect;
232
case AutohideType.None:
235
case AutohideType.Autohide:
236
Hidden = !DockHovered;
238
case AutohideType.Intellihide:
239
case AutohideType.UniversalIntellihide:
240
Hidden = !DockHovered && WindowIntersectingOther;
245
void OnDockHoveredChanged ()
247
if (DockHoveredChanged != null)
248
DockHoveredChanged (this, EventArgs.Empty);
251
void OnHiddenChanged ()
253
if (HiddenChanged != null)
254
HiddenChanged (this, EventArgs.Empty);
257
#region IDisposable implementation
258
public void Dispose ()
260
if (screen != null) {
261
screen.ActiveWindowChanged -= HandleActiveWindowChanged;
262
if (screen.ActiveWindow != null)
263
screen.ActiveWindow.GeometryChanged -= HandleGeometryChanged;
264
screen.WindowOpened -= HandleWindowOpened;
265
screen.WindowClosed -= HandleWindowClosed;
269
tracker.CursorPositionChanged -= HandleCursorPositionChanged;