widget/cocoa/nsWindowMap.mm

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "nsWindowMap.h"
michael@0 7 #include "nsObjCExceptions.h"
michael@0 8 #include "nsChildView.h"
michael@0 9 #include "nsCocoaWindow.h"
michael@0 10
michael@0 11 @interface WindowDataMap(Private)
michael@0 12
michael@0 13 - (NSString*)keyForWindow:(NSWindow*)inWindow;
michael@0 14
michael@0 15 @end
michael@0 16
michael@0 17 @interface TopLevelWindowData(Private)
michael@0 18
michael@0 19 - (void)windowResignedKey:(NSNotification*)inNotification;
michael@0 20 - (void)windowBecameKey:(NSNotification*)inNotification;
michael@0 21 - (void)windowWillClose:(NSNotification*)inNotification;
michael@0 22
michael@0 23 @end
michael@0 24
michael@0 25 #pragma mark -
michael@0 26
michael@0 27 @implementation WindowDataMap
michael@0 28
michael@0 29 + (WindowDataMap*)sharedWindowDataMap
michael@0 30 {
michael@0 31 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
michael@0 32
michael@0 33 static WindowDataMap* sWindowMap = nil;
michael@0 34 if (!sWindowMap)
michael@0 35 sWindowMap = [[WindowDataMap alloc] init];
michael@0 36
michael@0 37 return sWindowMap;
michael@0 38
michael@0 39 NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
michael@0 40 }
michael@0 41
michael@0 42 - (id)init
michael@0 43 {
michael@0 44 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
michael@0 45
michael@0 46 if ((self = [super init])) {
michael@0 47 mWindowMap = [[NSMutableDictionary alloc] initWithCapacity:10];
michael@0 48 }
michael@0 49 return self;
michael@0 50
michael@0 51 NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
michael@0 52 }
michael@0 53
michael@0 54 - (void)dealloc
michael@0 55 {
michael@0 56 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 57
michael@0 58 [mWindowMap release];
michael@0 59 [super dealloc];
michael@0 60
michael@0 61 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 62 }
michael@0 63
michael@0 64 - (void)ensureDataForWindow:(NSWindow*)inWindow
michael@0 65 {
michael@0 66 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 67
michael@0 68 if (!inWindow || [self dataForWindow:inWindow])
michael@0 69 return;
michael@0 70
michael@0 71 TopLevelWindowData* windowData = [[TopLevelWindowData alloc] initWithWindow:inWindow];
michael@0 72 [self setData:windowData forWindow:inWindow]; // takes ownership
michael@0 73 [windowData release];
michael@0 74
michael@0 75 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 76 }
michael@0 77
michael@0 78 - (id)dataForWindow:(NSWindow*)inWindow
michael@0 79 {
michael@0 80 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
michael@0 81
michael@0 82 return [mWindowMap objectForKey:[self keyForWindow:inWindow]];
michael@0 83
michael@0 84 NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
michael@0 85 }
michael@0 86
michael@0 87 - (void)setData:(id)inData forWindow:(NSWindow*)inWindow
michael@0 88 {
michael@0 89 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 90
michael@0 91 [mWindowMap setObject:inData forKey:[self keyForWindow:inWindow]];
michael@0 92
michael@0 93 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 94 }
michael@0 95
michael@0 96 - (void)removeDataForWindow:(NSWindow*)inWindow
michael@0 97 {
michael@0 98 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 99
michael@0 100 [mWindowMap removeObjectForKey:[self keyForWindow:inWindow]];
michael@0 101
michael@0 102 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 103 }
michael@0 104
michael@0 105 - (NSString*)keyForWindow:(NSWindow*)inWindow
michael@0 106 {
michael@0 107 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
michael@0 108
michael@0 109 return [NSString stringWithFormat:@"%p", inWindow];
michael@0 110
michael@0 111 NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
michael@0 112 }
michael@0 113
michael@0 114 @end
michael@0 115
michael@0 116 // TopLevelWindowData
michael@0 117 //
michael@0 118 // This class holds data about top-level windows. We can't use a window
michael@0 119 // delegate, because an embedder may already have one.
michael@0 120
michael@0 121 @implementation TopLevelWindowData
michael@0 122
michael@0 123 - (id)initWithWindow:(NSWindow*)inWindow
michael@0 124 {
michael@0 125 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
michael@0 126
michael@0 127 if ((self = [super init])) {
michael@0 128 [[NSNotificationCenter defaultCenter] addObserver:self
michael@0 129 selector:@selector(windowBecameKey:)
michael@0 130 name:NSWindowDidBecomeKeyNotification
michael@0 131 object:inWindow];
michael@0 132
michael@0 133 [[NSNotificationCenter defaultCenter] addObserver:self
michael@0 134 selector:@selector(windowResignedKey:)
michael@0 135 name:NSWindowDidResignKeyNotification
michael@0 136 object:inWindow];
michael@0 137
michael@0 138 [[NSNotificationCenter defaultCenter] addObserver:self
michael@0 139 selector:@selector(windowBecameMain:)
michael@0 140 name:NSWindowDidBecomeMainNotification
michael@0 141 object:inWindow];
michael@0 142
michael@0 143 [[NSNotificationCenter defaultCenter] addObserver:self
michael@0 144 selector:@selector(windowResignedMain:)
michael@0 145 name:NSWindowDidResignMainNotification
michael@0 146 object:inWindow];
michael@0 147
michael@0 148 [[NSNotificationCenter defaultCenter] addObserver:self
michael@0 149 selector:@selector(windowWillClose:)
michael@0 150 name:NSWindowWillCloseNotification
michael@0 151 object:inWindow];
michael@0 152 }
michael@0 153 return self;
michael@0 154
michael@0 155 NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
michael@0 156 }
michael@0 157
michael@0 158 - (void)dealloc
michael@0 159 {
michael@0 160 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 161
michael@0 162 [[NSNotificationCenter defaultCenter] removeObserver:self];
michael@0 163 [super dealloc];
michael@0 164
michael@0 165 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 166 }
michael@0 167
michael@0 168 // As best I can tell, if the notification's object has a corresponding
michael@0 169 // top-level widget (an nsCocoaWindow object), it has a delegate (set in
michael@0 170 // nsCocoaWindow::StandardCreate()) of class WindowDelegate, and otherwise
michael@0 171 // not (Camino doesn't use top-level widgets (nsCocoaWindow objects) --
michael@0 172 // only child widgets (nsChildView objects)). (The notification is sent
michael@0 173 // to windowBecameKey: or windowBecameMain: below.)
michael@0 174 //
michael@0 175 // For use with clients that (like Firefox) do use top-level widgets (and
michael@0 176 // have NSWindow delegates of class WindowDelegate).
michael@0 177 + (void)activateInWindow:(NSWindow*)aWindow
michael@0 178 {
michael@0 179 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 180
michael@0 181 WindowDelegate* delegate = (WindowDelegate*) [aWindow delegate];
michael@0 182 if (!delegate || ![delegate isKindOfClass:[WindowDelegate class]])
michael@0 183 return;
michael@0 184
michael@0 185 if ([delegate toplevelActiveState])
michael@0 186 return;
michael@0 187 [delegate sendToplevelActivateEvents];
michael@0 188
michael@0 189 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 190 }
michael@0 191
michael@0 192 // See comments above activateInWindow:
michael@0 193 //
michael@0 194 // If we're using top-level widgets (nsCocoaWindow objects), we send them
michael@0 195 // NS_DEACTIVATE events (which propagate to child widgets (nsChildView
michael@0 196 // objects) via nsWebShellWindow::HandleEvent()).
michael@0 197 //
michael@0 198 // For use with clients that (like Firefox) do use top-level widgets (and
michael@0 199 // have NSWindow delegates of class WindowDelegate).
michael@0 200 + (void)deactivateInWindow:(NSWindow*)aWindow
michael@0 201 {
michael@0 202 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 203
michael@0 204 WindowDelegate* delegate = (WindowDelegate*) [aWindow delegate];
michael@0 205 if (!delegate || ![delegate isKindOfClass:[WindowDelegate class]])
michael@0 206 return;
michael@0 207
michael@0 208 if (![delegate toplevelActiveState])
michael@0 209 return;
michael@0 210 [delegate sendToplevelDeactivateEvents];
michael@0 211
michael@0 212 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 213 }
michael@0 214
michael@0 215 // For use with clients that (like Camino) don't use top-level widgets (and
michael@0 216 // don't have NSWindow delegates of class WindowDelegate).
michael@0 217 + (void)activateInWindowViews:(NSWindow*)aWindow
michael@0 218 {
michael@0 219 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 220
michael@0 221 id firstResponder = [aWindow firstResponder];
michael@0 222 if ([firstResponder isKindOfClass:[ChildView class]])
michael@0 223 [firstResponder viewsWindowDidBecomeKey];
michael@0 224
michael@0 225 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 226 }
michael@0 227
michael@0 228 // For use with clients that (like Camino) don't use top-level widgets (and
michael@0 229 // don't have NSWindow delegates of class WindowDelegate).
michael@0 230 + (void)deactivateInWindowViews:(NSWindow*)aWindow
michael@0 231 {
michael@0 232 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 233
michael@0 234 id firstResponder = [aWindow firstResponder];
michael@0 235 if ([firstResponder isKindOfClass:[ChildView class]])
michael@0 236 [firstResponder viewsWindowDidResignKey];
michael@0 237
michael@0 238 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 239 }
michael@0 240
michael@0 241 // We make certain exceptions for top-level windows in non-embedders (see
michael@0 242 // comment above windowBecameMain below). And we need (elsewhere) to guard
michael@0 243 // against sending duplicate events. But in general the NS_ACTIVATE event
michael@0 244 // should be sent when a native window becomes key, and the NS_DEACTIVATE
michael@0 245 // event should be sent when it resignes key.
michael@0 246 - (void)windowBecameKey:(NSNotification*)inNotification
michael@0 247 {
michael@0 248 NSWindow* window = (NSWindow*)[inNotification object];
michael@0 249
michael@0 250 id delegate = [window delegate];
michael@0 251 if (!delegate || ![delegate isKindOfClass:[WindowDelegate class]]) {
michael@0 252 [TopLevelWindowData activateInWindowViews:window];
michael@0 253 } else if ([window isSheet]) {
michael@0 254 [TopLevelWindowData activateInWindow:window];
michael@0 255 }
michael@0 256
michael@0 257 [[window contentView] setNeedsDisplay:YES];
michael@0 258 }
michael@0 259
michael@0 260 - (void)windowResignedKey:(NSNotification*)inNotification
michael@0 261 {
michael@0 262 NSWindow* window = (NSWindow*)[inNotification object];
michael@0 263
michael@0 264 id delegate = [window delegate];
michael@0 265 if (!delegate || ![delegate isKindOfClass:[WindowDelegate class]]) {
michael@0 266 [TopLevelWindowData deactivateInWindowViews:window];
michael@0 267 } else if ([window isSheet]) {
michael@0 268 [TopLevelWindowData deactivateInWindow:window];
michael@0 269 }
michael@0 270
michael@0 271 [[window contentView] setNeedsDisplay:YES];
michael@0 272 }
michael@0 273
michael@0 274 // The appearance of a top-level window depends on its main state (not its key
michael@0 275 // state). So (for non-embedders) we need to ensure that a top-level window
michael@0 276 // is main when an NS_ACTIVATE event is sent to Gecko for it.
michael@0 277 - (void)windowBecameMain:(NSNotification*)inNotification
michael@0 278 {
michael@0 279 NSWindow* window = (NSWindow*)[inNotification object];
michael@0 280
michael@0 281 id delegate = [window delegate];
michael@0 282 // Don't send events to a top-level window that has a sheet open above it --
michael@0 283 // as far as Gecko is concerned, it's inactive, and stays so until the sheet
michael@0 284 // closes.
michael@0 285 if (delegate && [delegate isKindOfClass:[WindowDelegate class]] && ![window attachedSheet])
michael@0 286 [TopLevelWindowData activateInWindow:window];
michael@0 287 }
michael@0 288
michael@0 289 - (void)windowResignedMain:(NSNotification*)inNotification
michael@0 290 {
michael@0 291 NSWindow* window = (NSWindow*)[inNotification object];
michael@0 292
michael@0 293 id delegate = [window delegate];
michael@0 294 if (delegate && [delegate isKindOfClass:[WindowDelegate class]] && ![window attachedSheet])
michael@0 295 [TopLevelWindowData deactivateInWindow:window];
michael@0 296 }
michael@0 297
michael@0 298 - (void)windowWillClose:(NSNotification*)inNotification
michael@0 299 {
michael@0 300 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 301
michael@0 302 // postpone our destruction
michael@0 303 [[self retain] autorelease];
michael@0 304
michael@0 305 // remove ourselves from the window map (which owns us)
michael@0 306 [[WindowDataMap sharedWindowDataMap] removeDataForWindow:[inNotification object]];
michael@0 307
michael@0 308 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 309 }
michael@0 310
michael@0 311 @end

mercurial