2001-11-07 01:52:52 +03:00
|
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2012-05-21 15:12:37 +04:00
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2001-11-07 01:52:52 +03:00
|
|
|
|
|
|
|
|
|
#include "nsToolkit.h"
|
|
|
|
|
|
2006-12-08 11:29:46 +03:00
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
|
|
#include <mach/mach_port.h>
|
|
|
|
|
#include <mach/mach_interface.h>
|
|
|
|
|
#include <mach/mach_init.h>
|
|
|
|
|
|
2010-04-05 18:04:49 +04:00
|
|
|
|
extern "C" {
|
|
|
|
|
#include <mach-o/getsect.h>
|
|
|
|
|
}
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <dlfcn.h>
|
|
|
|
|
|
2007-05-18 06:06:59 +04:00
|
|
|
|
#import <Cocoa/Cocoa.h>
|
2007-01-18 09:34:07 +03:00
|
|
|
|
#import <IOKit/pwr_mgt/IOPMLib.h>
|
|
|
|
|
#import <IOKit/IOMessage.h>
|
2006-12-08 11:29:46 +03:00
|
|
|
|
|
2007-07-18 00:29:39 +04:00
|
|
|
|
#include "nsCocoaUtils.h"
|
2008-02-21 02:47:05 +03:00
|
|
|
|
#include "nsObjCExceptions.h"
|
2007-07-18 00:29:39 +04:00
|
|
|
|
|
2011-10-14 22:11:22 +04:00
|
|
|
|
#include "nsGkAtoms.h"
|
2007-05-18 06:06:59 +04:00
|
|
|
|
#include "nsIRollupListener.h"
|
|
|
|
|
#include "nsIWidget.h"
|
2012-10-26 17:15:22 +04:00
|
|
|
|
#include "nsBaseWidget.h"
|
2006-12-08 11:29:46 +03:00
|
|
|
|
|
|
|
|
|
#include "nsIObserverService.h"
|
|
|
|
|
#include "nsIServiceManager.h"
|
2011-05-27 12:15:20 +04:00
|
|
|
|
|
|
|
|
|
#include "mozilla/Preferences.h"
|
2014-04-29 21:31:06 +04:00
|
|
|
|
#include "mozilla/Services.h"
|
2011-05-27 12:15:20 +04:00
|
|
|
|
|
|
|
|
|
using namespace mozilla;
|
2006-12-18 22:50:14 +03:00
|
|
|
|
|
|
|
|
|
static io_connect_t gRootPort = MACH_PORT_NULL;
|
2006-12-08 11:29:46 +03:00
|
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
|
nsToolkit* nsToolkit::gToolkit = nullptr;
|
2006-12-08 11:29:46 +03:00
|
|
|
|
|
2002-12-13 11:43:18 +03:00
|
|
|
|
nsToolkit::nsToolkit()
|
2019-07-31 04:03:49 +03:00
|
|
|
|
: mSleepWakeNotificationRLS(nullptr), mPowerNotifier{0}, mAllProcessMouseMonitor(nil) {
|
2011-10-28 18:47:54 +04:00
|
|
|
|
MOZ_COUNT_CTOR(nsToolkit);
|
2014-09-08 18:59:34 +04:00
|
|
|
|
RegisterForSleepWakeNotifications();
|
2001-11-07 01:52:52 +03:00
|
|
|
|
}
|
|
|
|
|
|
2019-01-21 20:18:16 +03:00
|
|
|
|
nsToolkit::~nsToolkit() {
|
2011-10-06 03:54:07 +04:00
|
|
|
|
MOZ_COUNT_DTOR(nsToolkit);
|
2014-09-08 18:59:34 +04:00
|
|
|
|
RemoveSleepWakeNotifications();
|
2019-07-31 04:03:49 +03:00
|
|
|
|
StopMonitoringAllProcessMouseEvents();
|
2006-12-08 11:29:46 +03:00
|
|
|
|
}
|
|
|
|
|
|
2019-01-21 20:18:16 +03:00
|
|
|
|
void nsToolkit::PostSleepWakeNotification(const char* aNotification) {
|
2014-04-29 21:31:06 +04:00
|
|
|
|
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
|
2019-01-21 20:18:16 +03:00
|
|
|
|
if (observerService) observerService->NotifyObservers(nullptr, aNotification, nullptr);
|
2006-12-08 11:29:46 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// http://developer.apple.com/documentation/DeviceDrivers/Conceptual/IOKitFundamentals/PowerMgmt/chapter_10_section_3.html
|
2019-01-21 20:18:16 +03:00
|
|
|
|
static void ToolkitSleepWakeCallback(void* refCon, io_service_t service, natural_t messageType,
|
|
|
|
|
void* messageArgument) {
|
2008-02-21 02:47:05 +03:00
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
|
2019-01-21 20:18:16 +03:00
|
|
|
|
switch (messageType) {
|
2006-12-08 11:29:46 +03:00
|
|
|
|
case kIOMessageSystemWillSleep:
|
|
|
|
|
// System is going to sleep now.
|
2012-11-09 19:34:10 +04:00
|
|
|
|
nsToolkit::PostSleepWakeNotification(NS_WIDGET_SLEEP_OBSERVER_TOPIC);
|
2006-12-08 11:29:46 +03:00
|
|
|
|
::IOAllowPowerChange(gRootPort, (long)messageArgument);
|
|
|
|
|
break;
|
2017-10-31 13:25:04 +03:00
|
|
|
|
|
2006-12-08 11:29:46 +03:00
|
|
|
|
case kIOMessageCanSystemSleep:
|
|
|
|
|
// In this case, the computer has been idle for several minutes
|
|
|
|
|
// and will sleep soon so you must either allow or cancel
|
|
|
|
|
// this notification. Important: if you don’t respond, there will
|
|
|
|
|
// be a 30-second timeout before the computer sleeps.
|
|
|
|
|
// In Mozilla's case, we always allow sleep.
|
2019-01-21 20:18:16 +03:00
|
|
|
|
::IOAllowPowerChange(gRootPort, (long)messageArgument);
|
2006-12-08 11:29:46 +03:00
|
|
|
|
break;
|
2017-10-31 13:25:04 +03:00
|
|
|
|
|
2006-12-08 11:29:46 +03:00
|
|
|
|
case kIOMessageSystemHasPoweredOn:
|
|
|
|
|
// Handle wakeup.
|
2012-11-09 19:34:10 +04:00
|
|
|
|
nsToolkit::PostSleepWakeNotification(NS_WIDGET_WAKE_OBSERVER_TOPIC);
|
2006-12-08 11:29:46 +03:00
|
|
|
|
break;
|
|
|
|
|
}
|
2008-02-21 02:47:05 +03:00
|
|
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2001-11-07 01:52:52 +03:00
|
|
|
|
}
|
|
|
|
|
|
2019-01-21 20:18:16 +03:00
|
|
|
|
nsresult nsToolkit::RegisterForSleepWakeNotifications() {
|
2008-02-21 02:47:05 +03:00
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
|
2006-12-08 11:29:46 +03:00
|
|
|
|
IONotificationPortRef notifyPortRef;
|
|
|
|
|
|
|
|
|
|
NS_ASSERTION(!mSleepWakeNotificationRLS, "Already registered for sleep/wake");
|
|
|
|
|
|
2019-01-21 20:18:16 +03:00
|
|
|
|
gRootPort =
|
|
|
|
|
::IORegisterForSystemPower(0, ¬ifyPortRef, ToolkitSleepWakeCallback, &mPowerNotifier);
|
2006-12-08 11:29:46 +03:00
|
|
|
|
if (gRootPort == MACH_PORT_NULL) {
|
2009-08-14 18:09:00 +04:00
|
|
|
|
NS_ERROR("IORegisterForSystemPower failed");
|
2006-12-08 11:29:46 +03:00
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mSleepWakeNotificationRLS = ::IONotificationPortGetRunLoopSource(notifyPortRef);
|
2019-01-21 20:18:16 +03:00
|
|
|
|
::CFRunLoopAddSource(::CFRunLoopGetCurrent(), mSleepWakeNotificationRLS, kCFRunLoopDefaultMode);
|
2006-12-08 11:29:46 +03:00
|
|
|
|
|
2002-12-13 11:43:18 +03:00
|
|
|
|
return NS_OK;
|
2008-02-21 02:47:05 +03:00
|
|
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
2002-12-13 11:43:18 +03:00
|
|
|
|
}
|
|
|
|
|
|
2019-01-21 20:18:16 +03:00
|
|
|
|
void nsToolkit::RemoveSleepWakeNotifications() {
|
2008-02-21 02:47:05 +03:00
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
|
2006-12-08 11:29:46 +03:00
|
|
|
|
if (mSleepWakeNotificationRLS) {
|
|
|
|
|
::IODeregisterForSystemPower(&mPowerNotifier);
|
2019-01-21 20:18:16 +03:00
|
|
|
|
::CFRunLoopRemoveSource(::CFRunLoopGetCurrent(), mSleepWakeNotificationRLS,
|
2006-12-08 11:29:46 +03:00
|
|
|
|
kCFRunLoopDefaultMode);
|
|
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
|
mSleepWakeNotificationRLS = nullptr;
|
2006-12-08 11:29:46 +03:00
|
|
|
|
}
|
2008-02-21 02:47:05 +03:00
|
|
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2006-12-08 11:29:46 +03:00
|
|
|
|
}
|
|
|
|
|
|
2007-07-18 00:29:39 +04:00
|
|
|
|
// Cocoa Firefox's use of custom context menus requires that we explicitly
|
|
|
|
|
// handle mouse events from other processes that the OS handles
|
|
|
|
|
// "automatically" for native context menus -- mouseMoved events so that
|
|
|
|
|
// right-click context menus work properly when our browser doesn't have the
|
|
|
|
|
// focus (bmo bug 368077), and mouseDown events so that our browser can
|
|
|
|
|
// dismiss a context menu when a mouseDown happens in another process (bmo
|
|
|
|
|
// bug 339945).
|
2019-07-31 04:03:49 +03:00
|
|
|
|
void nsToolkit::MonitorAllProcessMouseEvents() {
|
2008-02-21 02:47:05 +03:00
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
|
2019-01-21 20:18:16 +03:00
|
|
|
|
// Don't do this for apps that use native context menus.
|
2011-06-22 01:00:47 +04:00
|
|
|
|
#ifdef MOZ_USE_NATIVE_POPUP_WINDOWS
|
|
|
|
|
return;
|
|
|
|
|
#endif /* MOZ_USE_NATIVE_POPUP_WINDOWS */
|
|
|
|
|
|
2019-07-31 04:03:49 +03:00
|
|
|
|
if (getenv("MOZ_NO_GLOBAL_MOUSE_MONITOR")) return;
|
|
|
|
|
|
|
|
|
|
if (mAllProcessMouseMonitor == nil) {
|
|
|
|
|
mAllProcessMouseMonitor = [NSEvent
|
|
|
|
|
addGlobalMonitorForEventsMatchingMask:NSLeftMouseDownMask | NSOtherMouseDownMask
|
|
|
|
|
handler:^(NSEvent* evt) {
|
|
|
|
|
if ([NSApp isActive]) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nsIRollupListener* rollupListener =
|
|
|
|
|
nsBaseWidget::GetActiveRollupListener();
|
|
|
|
|
if (!rollupListener) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nsCOMPtr<nsIWidget> rollupWidget =
|
|
|
|
|
rollupListener->GetRollupWidget();
|
|
|
|
|
if (!rollupWidget) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NSWindow* ctxMenuWindow =
|
|
|
|
|
(NSWindow*)rollupWidget->GetNativeData(
|
|
|
|
|
NS_NATIVE_WINDOW);
|
|
|
|
|
if (!ctxMenuWindow) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Don't roll up the rollup widget if our mouseDown happens
|
|
|
|
|
// over it (doing so would break the corresponding context
|
|
|
|
|
// menu).
|
|
|
|
|
NSPoint screenLocation = [NSEvent mouseLocation];
|
|
|
|
|
if (NSPointInRect(screenLocation, [ctxMenuWindow frame])) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rollupListener->Rollup(0, false, nullptr, nullptr);
|
|
|
|
|
}];
|
2007-07-18 00:29:39 +04:00
|
|
|
|
}
|
2008-02-21 02:47:05 +03:00
|
|
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-07-18 00:29:39 +04:00
|
|
|
|
}
|
2007-05-18 06:06:59 +04:00
|
|
|
|
|
2019-07-31 04:03:49 +03:00
|
|
|
|
void nsToolkit::StopMonitoringAllProcessMouseEvents() {
|
2008-02-21 02:47:05 +03:00
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
|
2019-07-31 04:03:49 +03:00
|
|
|
|
if (mAllProcessMouseMonitor != nil) {
|
|
|
|
|
[NSEvent removeMonitor:mAllProcessMouseMonitor];
|
|
|
|
|
mAllProcessMouseMonitor = nil;
|
2007-07-18 00:29:39 +04:00
|
|
|
|
}
|
2008-02-21 02:47:05 +03:00
|
|
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-05-18 06:06:59 +04:00
|
|
|
|
}
|
|
|
|
|
|
2011-10-25 19:05:32 +04:00
|
|
|
|
// Return the nsToolkit instance. If a toolkit does not yet exist, then one
|
|
|
|
|
// will be created.
|
|
|
|
|
// static
|
2019-01-21 20:18:16 +03:00
|
|
|
|
nsToolkit* nsToolkit::GetToolkit() {
|
2011-10-25 19:05:32 +04:00
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
2008-02-21 02:47:05 +03:00
|
|
|
|
|
2011-10-25 19:05:32 +04:00
|
|
|
|
if (!gToolkit) {
|
|
|
|
|
gToolkit = new nsToolkit();
|
2006-12-08 11:29:46 +03:00
|
|
|
|
}
|
2008-02-21 02:47:05 +03:00
|
|
|
|
|
2011-10-25 19:05:32 +04:00
|
|
|
|
return gToolkit;
|
|
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(nullptr);
|
2006-12-08 11:29:46 +03:00
|
|
|
|
}
|
|
|
|
|
|
2008-02-13 18:57:12 +03:00
|
|
|
|
// An alternative to [NSObject poseAsClass:] that isn't deprecated on OS X
|
|
|
|
|
// Leopard and is available to 64-bit binaries on Leopard and above. Based on
|
|
|
|
|
// ideas and code from http://www.cocoadev.com/index.pl?MethodSwizzling.
|
|
|
|
|
// Since the Method type becomes an opaque type as of Objective-C 2.0, we'll
|
|
|
|
|
// have to switch to using accessor methods like method_exchangeImplementations()
|
|
|
|
|
// when we build 64-bit binaries that use Objective-C 2.0 (on and for Leopard
|
2013-10-11 22:58:35 +04:00
|
|
|
|
// and above).
|
2008-02-13 18:57:12 +03:00
|
|
|
|
//
|
|
|
|
|
// Be aware that, if aClass doesn't have an orgMethod selector but one of its
|
|
|
|
|
// superclasses does, the method substitution will (in effect) take place in
|
|
|
|
|
// that superclass (rather than in aClass itself). The substitution has
|
|
|
|
|
// effect on the class where it takes place and all of that class's
|
|
|
|
|
// subclasses. In order for method swizzling to work properly, posedMethod
|
|
|
|
|
// needs to be unique in the class where the substitution takes place and all
|
|
|
|
|
// of its subclasses.
|
2008-03-27 19:30:13 +03:00
|
|
|
|
nsresult nsToolkit::SwizzleMethods(Class aClass, SEL orgMethod, SEL posedMethod,
|
2019-01-21 20:18:16 +03:00
|
|
|
|
bool classMethods) {
|
2008-02-21 02:47:05 +03:00
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
|
2008-03-27 19:30:13 +03:00
|
|
|
|
Method original = nil;
|
|
|
|
|
Method posed = nil;
|
|
|
|
|
|
|
|
|
|
if (classMethods) {
|
|
|
|
|
original = class_getClassMethod(aClass, orgMethod);
|
|
|
|
|
posed = class_getClassMethod(aClass, posedMethod);
|
|
|
|
|
} else {
|
|
|
|
|
original = class_getInstanceMethod(aClass, orgMethod);
|
|
|
|
|
posed = class_getInstanceMethod(aClass, posedMethod);
|
|
|
|
|
}
|
2008-02-13 18:57:12 +03:00
|
|
|
|
|
2019-01-21 20:18:16 +03:00
|
|
|
|
if (!original || !posed) return NS_ERROR_FAILURE;
|
2008-02-13 18:57:12 +03:00
|
|
|
|
|
2009-08-13 02:32:41 +04:00
|
|
|
|
method_exchangeImplementations(original, posed);
|
2008-02-13 18:57:12 +03:00
|
|
|
|
|
|
|
|
|
return NS_OK;
|
2008-02-21 02:47:05 +03:00
|
|
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
2008-02-13 18:57:12 +03:00
|
|
|
|
}
|