NSWorkspace Уведомления в CFNotificationCenter - PullRequest
2 голосов
/ 31 января 2012

Мы работаем над проектом Qt, и мы должны добавить специальный код для Mac. Нам нужно зарегистрироваться на событие, в примере программы мы сделали это с помощью:

[[NSNotificationCenter defaultCenter] addObserver:self
                                   selector:@selector(notificationHandler:) 
                                   name:NSWorkspaceDidDeactivateApplicationNotification
                                   object:nil];

Поскольку мы можем использовать это непосредственно в нашем файле mm на Qt, мы используем такой подход:

MyClass::MyClass() : {
    // do other setup ...

    CFNotificationCenterAddObserver
    (
        CFNotificationCenterGetLocalCenter(),
        this,
        &notificationHandler,
        CFSTR("???"),
        NULL,
        CFNotificationSuspensionBehaviorDeliverImmediately
    );
}

Что за строка для "NSWorkspaceDidDeactivateApplicationNotification" ?? Или как нам присоединиться к этому конкретному уведомлению?

Мы попробовали подход NSGod, но, поскольку никакой код Objective-C не может быть добавлен в .h с Qt, мы добавили закрытый член, класс которого определен в файле mm, который содержит действительную логику. как это:

SelectedStuffManager.h

class MacWrap;

class SelectedStuffManager
{
  public:
   ....
    doSomething();

    MacWrap* d;

  private:
   ....
};

SelectedStuffManager.mm

@class MDWorkspaceWatcher;

class MacWrap
{
    public:
        MacWrap();
        ~MacWrap();

        void  applicationDeactivated(NSNotification * notification);

        SystemEventsApplication *systemApplication;
        NSRunningApplication *runApp;

        private:
           MDWorkspaceWatcher *workspaceWatcher;
};
MacWrap::MacWrap() {
      this->workspaceWatcher = [[MDWorkspaceWatcher alloc] initWithMyClass:this];
}

MacWrap::~MacWrap() {
      [this->workspaceWatcher release];
}

void  MacWrap::applicationDeactivated(NSNotification* notification)
{
    // guardar el id del proceso para utilizarlo luego
    runApp = [[notification userInfo] valueForKey:@"NSWorkspaceApplicationKey"];
    NSString *systemEventsASppName = [runApp bundleIdentifier];
    if( [ systemEventsASppName isNotEqualTo:@"com.yo.SelectedText"])
    {
        systemApplication = [SBApplication applicationWithBundleIdentifier:systemEventsASppName];
        NSLog(@"Launched. %@",systemEventsASppName);
    }

}

@interface MDWorkspaceWatcher : NSObject {

     MacWrap  *manager;
}

- (id)initWithMyClass:(MacWrap*)obj;
- (void)didDeactivateApp:(NSNotification *)notification; @end

@implementation MDWorkspaceWatcher
- (id)initWithMyClass:(MacWrap*)obj {
    if ((self = [super init])) {
       manager = obj;

       [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
                selector:@selector(didDeactivateApp:)
                name:NSWorkspaceDidDeactivateApplicationNotification
                object:nil];
    }
    return self;
}

- (void)dealloc {
    [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
    [super dealloc];
}

- (void)didDeactivateApp:(NSNotification *)notification {
   manager->applicationDeactivated(notification);
}
@end

SelectedStuffManager::SelectedStuffManager()
{
    d = new MacWrap();
}
SelectedStuffManager::doSomething()
{
    if ([[d->runApp localizedName] isEqualTo: @"something"]) --> here it fails, bad memory access
    {
       ...
    }
}

Кажется, что кто-то освобождает как runApp, так и systemApplication, поэтому мы получаем нулевой указатель или плохую память. Как или почему это может происходить?

1 Ответ

0 голосов
/ 31 января 2012

Я не верю, что вы можете делать то, на что надеетесь.Прежде всего, NSWorkspace использует свой собственный NSNotificationCenter, который отличается от значения по умолчанию NSNotificationCenter, возвращаемого с +defaultCenter.

Я не верю, что существует строгий CF-эквивалент этих NSWorkspace звонки.Вероятно, существуют высокоуровневые эквиваленты на основе углерода, но они недоступны в 64-разрядной среде, и их, скорее всего, следует избегать.

Вы должны быть в состоянии выполнить то, что вы хотите, с помощью небольшого помощника Objective-Cкласс для получения уведомлений и пересылки их вашему классу C ++, как показано в следующем коде:

EDIT: обновлено для удаления любого Objective-C из заголовочных файлов.Просто используйте общие void * указатели, которые вы можете использовать внутри файла .mm.

.h:

//@class MDWorkspaceWatcher;

class MyClass {
   private:
      // MDWorkspaceWatcher *workspaceWatcher;
      void *workspaceWatcher;
   public:
       MyClass();
       ~MyClass();

       // const void didActivateApp(NSNotification *notification) const;
       // const void didDeactivateApp(NSNotification *notification) const;
       const void didActivateApp(void *anNSnotification) const;
       const void didDeactivateApp(void *anNSnotification) const;

};

.mm:

Часть Objective-C:

@interface MDWorkspaceWatcher : NSObject {
    MyClass    *myClass;
}
- (id)initWithMyClass:(MyClass *)aMyClass;
@end

@implementation MDWorkspaceWatcher
- (id)initWithMyClass:(MyClass *)aMyClass {
    if ((self = [super init])) {
       myClass = aMyClass;
       [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
                selector:@selector(didActivateApp:)
                name:NSWorkspaceDidActivateApplicationNotification
                object:nil];
       [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
                selector:@selector(didDeactivateApp:)
                name:NSWorkspaceDidDeactivateApplicationNotification
                object:nil];
    }
    return self;
}
// very important:
- (void)dealloc {
    [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
    [super dealloc];
}
- (void)didActivateApp:(NSNotification *)notification {
   myClass->didActivateApp(notification);
}
- (void)didDeactivateApp:(NSNotification *)notification {
   myClass->didDeactivateApp(notification);
}
@end

C ++ part:

MyClass::MyClass() {
      this->workspaceWatcher = [[MDWorkspaceWatcher alloc] initWithMyClass:this];
}

MyClass::~MyClass() {
      [(MDWorkspaceWatcher *)this->workspaceWatcher release];
}

MyClass::didActivateApp(void *anNSnotification) {
     NSDictionary *appInfo = [(NSNotification *)anNSnotification userInfo];          
     NSLog(@"appInfo == %@", appInfo);

}

MyClass::didDeactivateApp(void *anNSnotification) {
     NSDictionary *appInfo = [(NSNotification *)anNSnotification userInfo];          
     NSLog(@"appInfo == %@", appInfo);

}

Обратите внимание, что для NSDictionary используется бесплатный номер CFDictionaryRef, поэтому вы можете просто разыграть appInfo NSDictionaryна CFDictionaryRef и затем вызовите функции CF, чтобы получить доступ к содержимому словаря, если вы предпочитаете C, а не Objective-C.

Обратите внимание, что центр уведомлений владеет словарем appInfo (в другихсловами, он будет автоматически освобожден), поэтому вы не должны вызывать CFRelease() на него, как если бы вы использовали CFCreate* / CFCopy* связанный код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...