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.

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

mercurial