-
Notifications
You must be signed in to change notification settings - Fork 0
/
CLiveResizeAttachment.cp
executable file
·148 lines (129 loc) · 4.26 KB
/
CLiveResizeAttachment.cp
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
/*
File: CLiveResizeAttachment.cp
Author: Richard Buckle, Sailmaker Software Ltd
<mailto:[email protected]>
<http://www.sailmaker.co.uk/>
Version: 1.0.1
Purpose: Attachment to add Carbon live resizing to windows
Status: Public domain
*/
// IMPORTANT: see CLiveResizeAttachment.h for usage notes
#include "CLiveResizeAttachment.h"
#if PP_Target_Carbon
// EventHandlerUPP TEventHandler<CLiveResizeAttachment>::sHandlerUPP = 0;
#endif
//
CLiveResizeAttachment::CLiveResizeAttachment()
: LAttachment(msg_FinishCreate), // We only handle this message
mWindow(0)
{}
//
CLiveResizeAttachment::CLiveResizeAttachment(LWindow* inWindow)
: LAttachment(msg_FinishCreate), // We only handle this message
mWindow(inWindow)
{
Execute(msg_FinishCreate, mWindow);
}
//
CLiveResizeAttachment::CLiveResizeAttachment(LStream* inStream)
: LAttachment(inStream),
mWindow(0)
{
mMessage = msg_FinishCreate; // We only handle this message
}
//
CLiveResizeAttachment::~CLiveResizeAttachment()
{}
#if PP_Target_Carbon
//
Boolean
CLiveResizeAttachment::Execute(
MessageT inMessage,
void* ioParam)
{
Boolean executeHost = true;
if (inMessage == msg_FinishCreate)
{
mWindow = static_cast<LWindow*>(ioParam);
if( mWindow != nil
&& mWindow->HasAttribute(windAttr_Resizable)
&& UEnvironment::HasFeature(env_HasAquaTheme)
)
{
WindowRef windowRef = mWindow->GetMacWindow();
EventTargetRef target = ::GetWindowEventTarget(windowRef);
mResizeHandler.Install( target, kEventClassWindow, kEventWindowBoundsChanged, this, &HandleResize );
mCloseHandler.Install( target, kEventClassWindow, kEventWindowClosed, this, &HandleClose );
OSStatus err = ::ChangeWindowAttributes( windowRef, kWindowLiveResizeAttribute, kWindowNoAttributes);
SignalIfOSStatus_(err);
}
executeHost = mExecuteHost;
}
return executeHost;
}
//
OSStatus
CLiveResizeAttachment::HandleResize(
EventHandlerCallRef /* inCallRef */,
EventRef inEventRef)
{
// We also get this event when the user is moving the window,
// but we only need to intervene if the window size is changed.
// If the window is merely moving then we should just return.
UInt32 attributes;
OSStatus result = ::GetEventParameter(
inEventRef, kEventParamAttributes,
typeUInt32, NULL,
sizeof( attributes ), NULL,
&attributes );
if( (result == noErr) && (attributes & kWindowBoundsChangeSizeChanged) )
{
// OK, we have kWindowBoundsChangeSizeChanged so we need to draw
Rect newBounds; // global co-ords
result = ::GetEventParameter( inEventRef,
kEventParamCurrentBounds,
typeQDRectangle, nil,
sizeof(newBounds), nil,
&newBounds );
if( result == noErr && mWindow != nil )
{
// there's no need to call mWindow->SendAESetBounds() because
// LWindow::ClickInGrow() gets called when the resize is complete.
// i.e the resize is still recordable.
// Carbon Events are bliss!
mWindow->DoSetBounds(newBounds);
mWindow->UpdatePort();
}
}
return result;
}
// Unfortunately, LWindow's destructor runs before LAttachable's,
// which means that by the time CLiveResizeAttachment's destructor gets called
// ::DisposeWindow() has already been called by ~LWindow and the OS has already
// removed our handlers.
// If we don't deal with this, the destructors of our TEventHandler members
// will remove their handlers a second time, leading to a double-free and
// memory corruption.
// So, we listen for the kEventWindowClosed Carbon event and remove our handlers
// at that point.
// The fix to LEventHandler::Remove() documented in CLiveResizeAttachment.h
// then ensures that the destructors don't try to remove the handlers a second
// time.
//
// James Walker has suggested an alternative way of dealing with this,
// which is in CLiveResizeAttachment::Execute() to detach from the window
// and attach to one of its subpanes. After some thought, I have decided
// to stick with my method because it strikes me as more robust against
// future changes in PowerPlant.
OSStatus
CLiveResizeAttachment::HandleClose(
EventHandlerCallRef inCallRef,
EventRef inEventRef)
{
Assert_(mWindow != nil);
mResizeHandler.Remove();
mCloseHandler.Remove();
OSStatus result = ::CallNextEventHandler(inCallRef, inEventRef);
return result;
}
#endif // PP_Target_Carbon