2
// Copyright (C) 2009 GNOME Do
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.Runtime.InteropServices;
28
using Do.Interface.Xlib;
30
namespace Do.Interface.Wink
34
static Dictionary<Wnck.Window, WindowState> window_states = new Dictionary<Wnck.Window, WindowState> ();
36
private class WindowState {
37
public Gdk.Rectangle Area;
38
public Wnck.WindowState State;
40
public WindowState (Gdk.Rectangle area, Wnck.WindowState state)
50
public string Name { get; private set; }
52
public Rectangle Area {
56
public bool IsActive {
58
if (!parent.IsVirtual)
59
return Wnck.Screen.Default.ActiveWorkspace == parent;
61
return Wnck.Screen.Default.ActiveWorkspace.ViewportX == area.X && Wnck.Screen.Default.ActiveWorkspace.ViewportY == area.Y;
65
WindowMoveResizeMask MoveMask {
67
return WindowMoveResizeMask.X | WindowMoveResizeMask.Y;
71
WindowMoveResizeMask ResizeMask {
73
return WindowMoveResizeMask.Width | WindowMoveResizeMask.Height;
77
WindowMoveResizeMask MoveResizeMask {
79
return WindowMoveResizeMask.X |
80
WindowMoveResizeMask.Y |
81
WindowMoveResizeMask.Height |
82
WindowMoveResizeMask.Width;
86
internal Viewport(string name, Rectangle area, Workspace parent)
93
public void Present ()
95
parent.Screen.MoveViewport (area.X, area.Y);
98
public bool Contains (Gdk.Point point)
100
return area.Contains (point);
103
private IEnumerable<Wnck.Window> RawWindows ()
105
foreach (Wnck.Window window in WindowUtils.GetWindows ()) {
106
if (WindowCenterInViewport (window) || window.IsSticky)
111
public IEnumerable<Wnck.Window> Windows ()
113
return RawWindows ().Where (w => !w.IsSkipTasklist && w.WindowType != Wnck.WindowType.Dock);
116
public IEnumerable<Wnck.Window> UnprocessedWindows ()
118
return RawWindows ().Where (w => w.WindowType != Wnck.WindowType.Dock);
121
public void MoveWindowInto (Wnck.Window window)
123
if (parent.IsVirtual) {
124
Rectangle geo = window.EasyGeometry ();
126
geo.X += window.Workspace.ViewportX;
127
geo.Y += window.Workspace.ViewportY;
129
int x = area.X + (geo.X % area.Width);
130
int y = area.Y + (geo.Y % area.Height);
132
x -= window.Workspace.ViewportX;
133
y -= window.Workspace.ViewportY;
135
window.SetWorkaroundGeometry (WindowGravity.Current, MoveMask, x, y, 0, 0);
137
window.MoveToWorkspace (parent);
141
public bool WindowVisibleInVeiwport (Wnck.Window window)
143
if (!window.IsOnWorkspace (parent))
146
Rectangle geo = window.EasyGeometry ();
147
geo.X += parent.ViewportX;
148
geo.Y += parent.ViewportY;
150
return area.IntersectsWith (geo);
153
public bool WindowCenterInViewport (Wnck.Window window)
155
if (!window.IsOnWorkspace (parent))
158
Rectangle geo = window.EasyGeometry ();
159
geo.X += parent.ViewportX;
160
geo.Y += parent.ViewportY;
162
Point center = new Point (geo.X + geo.Width / 2, geo.Y + geo.Height / 2);
163
return Contains (center);
166
public void RestoreLayout ()
168
foreach (Wnck.Window window in Windows ())
169
RestoreTemporaryWindowGeometry (window);
172
public void Cascade ()
174
IEnumerable<Wnck.Window> windows = Windows ().Where (w => !w.IsMinimized);
175
if (windows.Count () <= 1) return;
177
Gdk.Rectangle screenGeo = GetScreenGeoMinusStruts ();
179
int titleBarSize = windows.First ().FrameExtents () [(int) Position.Top];
180
int windowHeight = screenGeo.Height - ((windows.Count () - 1) * titleBarSize);
181
int windowWidth = screenGeo.Width - ((windows.Count () - 1) * titleBarSize);
185
foreach (Wnck.Window window in windows) {
186
x = screenGeo.X + titleBarSize * count - parent.ViewportX;
187
y = screenGeo.Y + titleBarSize * count - parent.ViewportY;
189
SetTemporaryWindowGeometry (window, new Gdk.Rectangle (x, y, windowWidth, windowHeight));
194
public void ShowDesktop ()
196
if (!ScreenUtils.DesktopShown (parent.Screen))
197
ScreenUtils.ShowDesktop (parent.Screen);
199
ScreenUtils.UnshowDesktop (parent.Screen);
204
IEnumerable<Wnck.Window> windows = Windows ().Where (w => !w.IsMinimized);
205
if (windows.Count () <= 1) return;
207
Gdk.Rectangle screenGeo = GetScreenGeoMinusStruts ();
210
//We are going to tile to a square, so what we want is to find
211
//the smallest perfect square all our windows will fit into
212
width = (int) Math.Ceiling (Math.Sqrt (windows.Count ()));
214
//Our height is at least one (e.g. a 2x1)
216
while (width * height < windows.Count ())
219
int windowWidth, windowHeight;
220
windowWidth = screenGeo.Width / width;
221
windowHeight = screenGeo.Height / height;
223
int row = 0, column = 0;
226
foreach (Wnck.Window window in windows) {
227
x = screenGeo.X + (column * windowWidth) - parent.ViewportX;
228
y = screenGeo.Y + (row * windowHeight) - parent.ViewportY;
230
Gdk.Rectangle windowArea = new Gdk.Rectangle (x, y, windowWidth, windowHeight);;
232
if (window == windows.Last ())
233
windowArea.Width *= width - column;
235
SetTemporaryWindowGeometry (window, windowArea);
238
if (column == width) {
245
Gdk.Rectangle GetScreenGeoMinusStruts ()
247
IEnumerable<int []> struts = RawWindows ()
248
.Where (w => w.WindowType == Wnck.WindowType.Dock)
249
.Select (w => w.GetCardinalProperty (X11Atoms.Instance._NET_WM_STRUT_PARTIAL));
251
int [] offsets = new int [4];
252
for (int i = 0; i < 4; i++)
253
offsets [i] = struts.Max (a => a[i]);
255
Gdk.Rectangle screenGeo = Area;
256
screenGeo.Width -= offsets [(int) Position.Left] + offsets [(int) Position.Right];
257
screenGeo.Height -= offsets [(int) Position.Top] + offsets [(int) Position.Bottom];
258
screenGeo.X += offsets [(int) Position.Left];
259
screenGeo.Y += offsets [(int) Position.Top];
264
void SetTemporaryWindowGeometry (Wnck.Window window, Gdk.Rectangle area)
266
Gdk.Rectangle oldGeo = window.EasyGeometry ();
268
oldGeo.X += parent.ViewportX;
269
oldGeo.Y += parent.ViewportY;
271
if (!window_states.ContainsKey (window))
272
window_states [window] = new WindowState (oldGeo, window.State);
274
if (window.IsMaximized)
275
window.Unmaximize ();
277
window.SetWorkaroundGeometry (WindowGravity.Current, MoveResizeMask, area.X, area.Y, area.Width, area.Height);
280
void RestoreTemporaryWindowGeometry (Wnck.Window window)
282
if (!window_states.ContainsKey (window))
285
WindowState state = window_states [window];
286
window.SetWorkaroundGeometry (WindowGravity.Current, MoveResizeMask, state.Area.X - parent.ViewportX,
287
state.Area.Y - parent.ViewportY, state.Area.Width, state.Area.Height);
289
window_states.Remove (window);