-
Notifications
You must be signed in to change notification settings - Fork 4
/
PMNormalWindowDecorator.m
214 lines (198 loc) · 6.94 KB
/
PMNormalWindowDecorator.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#import "PMNormalWindowDecorator.h"
#import "PMManagedWindow.h"
#import <XCBKit/XCBShape.h>
#import <XCBKit/EWMH.h>
#import <XCBKit/XCBAtomCache.h>
/**
* The width of the border used to house the
* resize handles. This should be at least 1px
* greater than the resize handle width to allow
* some space between the outer child border and
* the resize handles
*/
static const ICCCMBorderExtents BORDER_WIDTHS = { 8, 8, 8, 8};
static const uint32_t RH_WIDTH = 4;
static const uint32_t MIN_RH_LENGTH = 20;
static const float RH_QUOTIENT = 0.15;
static const uint16_t CHILD_BORDER_WIDTH = 1;
@interface PMNormalWindowDecorator (Private)
- (void)updateShapeWithManagedWindow: (PMManagedWindow*)managedWindow
decorationFrame: (XCBRect)decorationFrame
childFrame: (XCBRect)childFrame;
- (void)updateShapeWithManagedWindow: (PMManagedWindow*)managedWindow;
@end
@implementation PMNormalWindowDecorator
static PMNormalWindowDecorator *SharedInstance = nil;
+ (void)initialize
{
if (SharedInstance == nil)
{
SharedInstance = [PMNormalWindowDecorator new];
}
}
+ (PMNormalWindowDecorator*)sharedInstance
{
return SharedInstance;
}
- (ICCCMBorderExtents)extentsForDecorationWindow: (PMManagedWindow*)managedWindow
{
return BORDER_WIDTHS;
}
- (uint16_t)childBorderWidth: (PMManagedWindow*)managedWindow
{
return CHILD_BORDER_WIDTH;
}
- (BOOL)shouldDecorateManagedWindow: (PMManagedWindow*)managedWindow
{
BOOL decorate = YES;
XCBAtomCache *atomCache = [XCBAtomCache sharedInstance];
XCBCachedProperty *ewmhWindowType = [[managedWindow childWindow] cachedProperty: EWMH_WMWindowType];
if (![ewmhWindowType isEmpty])
{
// FIXME: This is an atom list, not a single atom
NSArray *atomArray = [ewmhWindowType asAtomArray];
NSDebugLLog(@"PMManagedWindow", @"%@ window type = %@", managedWindow, atomArray);
if ([ewmhWindowType hasAtomInAtomArray: EWMH_WMWindowTypeNormal] ||
[ewmhWindowType hasAtomInAtomArray: EWMH_WMWindowTypeDialog])
decorate = YES;
else
decorate = NO;
}
else
{
XCBCachedProperty *wmTransientFor = [[managedWindow childWindow] cachedProperty: ICCCMWMTransientFor];
if (![wmTransientFor isEmpty])
{
// FIXME: Should check if transient for root window
decorate = NO;
}
}
return decorate;
}
- (void)managedWindowRepositioned: (PMManagedWindow*)managedWindow
decorationFrame: (XCBRect)decorationFrame
childFrame: (XCBRect)childFrame
{
[self updateShapeWithManagedWindow: managedWindow
decorationFrame: decorationFrame
childFrame: childFrame];
}
- (XCBSize)minimumSizeForClientFrame: (PMManagedWindow*)managedWindow
{
uint32_t extent = MIN_RH_LENGTH * 2 + RH_WIDTH * 2 + 2;
return XCBMakeSize(extent, extent);
}
- (void)managedWindow: (PMManagedWindow*)managedWindow focusIn: (NSNotification*)aNot
{
NSDebugLLog(@"PMNormalWindowDecorator", @"%@: bringing to top and releasing inactive grabs", self);
// FIXME: This needs to be routed through managedWindow so that we
// can later handle window levels
XCBWindow *w = [managedWindow outermostWindow];
[w restackAboveWindow: nil];
// [managedWindow releaseInactiveGrabs];
[self updateShapeWithManagedWindow: managedWindow];
}
- (void)managedWindow: (PMManagedWindow*)managedWindow focusOut: (NSNotification*)aNot
{
NSDebugLLog(@"PMNormalWindowDecorator", @"%@: establishing inactive grabs on focus out", self);
//[managedWindow establishInactiveGrabs];
[self updateShapeWithManagedWindow: managedWindow];
}
- (void)updateShapeWithManagedWindow: (PMManagedWindow*)managedWindow
{
[self updateShapeWithManagedWindow: managedWindow
decorationFrame: [[managedWindow decorationWindow] frame]
childFrame: [[managedWindow childWindow] frame]];
}
- (void)updateShapeWithManagedWindow: (PMManagedWindow*)managedWindow
decorationFrame: (XCBRect)decorationFrame
childFrame: (XCBRect)childFrame
{
XCBWindow *decorationWindow = [managedWindow decorationWindow];
XCBWindow *childWindow = [managedWindow childWindow];
if (nil != decorationWindow)
{
// Child location
XCBPoint cp = childFrame.origin;
// Child size
XCBSize cs = childFrame.size;
// Decoration Size
XCBSize ds = decorationFrame.size;
// Resize Handle Length
int16_t rhl = MIN_RH_LENGTH;
// Resize Handle Width
int16_t rhw = RH_WIDTH;
// Child border width
int16_t cbw = CHILD_BORDER_WIDTH;
if ([managedWindow hasFocus])
{
xcb_rectangle_t rects[10] = {
{ 0, 0, rhw + rhl, rhw }, // NW H
{ ds.width - rhw - rhl, 0, rhw + rhl, rhw }, // NE H
{ 0, rhw, rhw, rhl }, // NW V
{ ds.width - rhw, rhw, rhw, rhl }, // NE V
{ cp.x - cbw, cp.y - cbw, cs.width + cbw * 2, cs.height + cbw * 2},
{ 0, ds.height - rhw - rhl, rhw, rhl }, // SW V
{ ds.width - rhw, ds.height - rhl - rhw, rhw, rhl }, // SE V
{ 0, ds.height - rhw, rhw + rhl, rhw }, // SW H
{ ds.width - rhl - rhw, ds.height - rhw, rhl + rhw, rhw } // SE H
};
[decorationWindow
setShapeRectangles: rects
count: 9
ordering: XCB_SHAPE_YXSORTED
operation: XCB_SHAPE_SO_SET
kind: XCB_SHAPE_SK_BOUNDING
offset: XCBMakePoint(0, 0)];
[decorationWindow
shapeCombineWithKind: XCB_SHAPE_SK_BOUNDING
operation: XCB_SHAPE_SO_UNION
offset: XCBMakePoint(BORDER_WIDTHS.left, BORDER_WIDTHS.top)
source: childWindow
sourceKind: XCB_SHAPE_SK_BOUNDING];
}
else
{
//xcb_rectangle_t rects[1] = {
// { cp.x - cbw, cp.y - cbw, cs.width + cbw *2, cs.height + cbw * 2 };
[decorationWindow
shapeCombineWithKind: XCB_SHAPE_SK_BOUNDING
operation: XCB_SHAPE_SO_SET
offset: XCBMakePoint(BORDER_WIDTHS.left, BORDER_WIDTHS.top)
source: childWindow
sourceKind: XCB_SHAPE_SK_BOUNDING];
}
}
}
- (int)managedWindow: (PMManagedWindow*)managedWindow
moveresizeTypeForPoint: (XCBPoint)point;
{
XCBRect df = [[managedWindow decorationWindow] frame];
XCBRect cf = [[managedWindow childWindow] frame];
// Resize handle square size - the length of a resize handle square
int16_t rhss = RH_WIDTH + MIN_RH_LENGTH;
if (XCBPointInRect(point, cf))
return EWMH_WMMoveresizeMove;
else if (point.x < rhss && point.y < rhss)
return EWMH_WMMoveresizeSizeTopLeft;
else if (point.x >= (df.size.width - rhss) && point.y < rhss)
return EWMH_WMMoveresizeSizeTopRight;
else if (point.x < rhss && point.y >= (df.size.height - rhss))
return EWMH_WMMoveresizeSizeBottomLeft;
else if (point.x >= (df.size.width - rhss) && point.y >= (df.size.height - rhss))
return EWMH_WMMoveresizeSizeBottomRight;
else
return EWMH_WMMoveresizeCancel;
}
- (void)managedWindow: (PMManagedWindow*)managedWindow changedState: (ICCCMWindowState) state
{
switch (state)
{
case ICCCMNormalWindowState:
// [managedWindow establishInactiveGrabs];
break;
default:
break;
}
}
@end