SIMBL кипит в Finder

Мне удалось интегрировать Icon Overlay, как Dropbox, в Mac Os Finder с помощью плагина SIMBL! Я использую метод swizzle, чтобы переопределить некоторые функции поиска.

Вот мой метод swizzle:

void PluginSwizzleInstanceMethod(Class cls, SEL oldSel, SEL newSel) 
{
    Method mnew = class_getInstanceMethod(cls, newSel);
    Method mold = class_getInstanceMethod(cls, oldSel);
    method_exchangeImplementations(mnew, mold);
}

Итак, на данный момент я переопределяю метод drawWithFrame следующим образом:

Class cls = NSClassFromString(@"TIconAndTextCell");
SEL oldSel = @selector(drawWithFrame:inView:);
SEL newSel = @selector(PluginDrawWithFrame:inView:);
PluginSwizzleInstanceMethod(cls, oldSel, newSel);

все мои значки отображаются, но не на моем рабочем столе или в представлении, которое показывает элементы в виде значков ... Почему?

Спасибо ,


person kavaliero    schedule 07.05.2012    source источник


Ответы (2)


Мне только что удалось сделать кое-что для рабочего стола, поэтому я опубликую, если это все еще актуально для кого-то:

Итак, как вы поняли, Finder по-разному рисует значки на рабочем столе.
За это отвечает класс TDesktopIcon.
Например, можно изменить значки, переопределив метод drawIconInContext: , и установить для свойства thumbnailImage любое значение NSImage*, которое ему нравится.

- (void) FO_drawIconInContext:(struct CGContext *)arg1 {
    NSImage *image;
    // set image... 
    [(TDesktopIcon*)self setThumbnailImage:image];
    [self FO_drawIconInContext:arg1];
}

Получение URL-адреса для каждого элемента было не таким простым, как с TIconAndTextCell или IKImageBrowserCell.

Чтобы получить URL-адреса, вам нужно переопределить метод prepareToDrawNode: TDesktopViewController. Вы получаете URL-адрес от arg1 следующим образом:

- (void) FO_prepareToDrawNode:(const struct TFENode *)arg1 {
    struct OpaqueNodeRef *opr = arg1->fNodeRef;  
    struct FINode *fiNode = [FINode nodeFromNodeRef:opr];  
    NSURL *url = [fiNode previewItemURL];  
    // save url somewhere (I use NSUserDefaults) 
    [self FO_prepareToDrawNode:arg1];  
}  

Может быть, есть лучший способ, но это то, что я понял...

person Barracuda    schedule 15.11.2012
comment
Вы видели последствия этого кода? Это действительно интересно... кажется, что замена изображения вызывает странные проблемы, когда искатель записывает другие наложения на значок... Я могу заставить половину значков на моем рабочем столе правильно рисовать свои оригинальные значки, но все они будут иметь наложение. их - person Orbitus007; 21.02.2013
comment
Есть идеи, как это сделать на Mavericks? - person Ali; 02.11.2013

Понятно! (ХОТЯ ЭТОТ КОД РАБОТАЕТ ТОЛЬКО ДЛЯ 10.7) У меня были проблемы, потому что значок рисовался до того, как окончательное изображение было преобразовано в миниатюру .... поэтому я получил эти артефакты, где исходный значок отсутствовал .... но оверлей был всегда... это был неправильный порядок операций рисования...!

У меня даже есть имя целевого узла... вам нужен класс TFENodeHelper, чтобы преобразовать TFENode в путь к файлу...

//
//  DesktopViewIconOverlay.h
//  FinderIconOverlayExample
//
//  Created by Orbitus007 on 2/20/13.
//
//

#import <Foundation/Foundation.h>
#import <Quartz/Quartz.h>
#import "Finder.h"

@interface DesktopViewIconOverlay : NSObject

+ (void)pluginLoad;
- (void) FO_prepareToDrawNode:(const struct TFENode *)arg1;
- (void) FO_drawIconInContext:(struct CGContext *)arg1;

@end

//
//  DesktopViewIconOverlay.m
//  FinderIconOverlayExample
//
//  Created by Orbitus007 on 2/20/13.
//
//

#import "DesktopViewIconOverlay.h"
#import "FinderIconOverlayExample.h"
#include <objc/objc.h>
#include <objc/runtime.h>
#import <Quartz/Quartz.h>
#import "TFENodeHelper.h"

static TFENodeHelper *gNodeHelper;





@implementation DesktopViewIconOverlay

+ (void)pluginLoad
{



    // Create helper object
    gNodeHelper = [[TFENodeHelper alloc] init];
    if (gNodeHelper == nil) {
        NSLog(@"Failed to instantiate 'TFENodeHelper' class");
        return;
    }


    Method old, new;
    Class self_class = [self class];
    Class finder_class = [objc_getClass("TDesktopIcon") class];

    class_addMethod(finder_class, @selector(FO_drawIconInContext:),
                    class_getMethodImplementation(self_class, @selector(FO_drawIconInContext:)),"v@:@");

    old = class_getInstanceMethod(finder_class, @selector(drawIconInContext:));
    new = class_getInstanceMethod(finder_class, @selector(FO_drawIconInContext:));
    method_exchangeImplementations(old, new);


    finder_class = [objc_getClass("TDesktopViewController") class];


    class_addMethod(finder_class, @selector(FO_prepareToDrawNode:),
                    class_getMethodImplementation(self_class, @selector(FO_prepareToDrawNode:)),"v@:@");

    old = class_getInstanceMethod(finder_class, @selector(prepareToDrawNode:));
    new = class_getInstanceMethod(finder_class, @selector(FO_prepareToDrawNode:));
    method_exchangeImplementations(old, new);

}


- (void) FO_prepareToDrawNode:(const struct TFENode *)arg1 {

    NSString *path = [gNodeHelper pathForNode:arg1];
    NSLog(@"Path = %@", path);
    [[NSUserDefaults standardUserDefaults] setValue:path forKey:@"TDesktopIconURL"];

    //struct OpaqueNodeRef *opr = arg1->fNodeRef;

    //NSLog(@"path = %@", [[FINode nodeWithFENode:arg1] fullPath]);

    //id fiNode = [FINode nodeFromNodeRef:opr];
    //NSURL *url = [fiNode previewItemURL];
    //[[NSUserDefaults standardUserDefaults] setValue:[url path] forKey:@"TDesktopIconURL"];
    //NSLog(@"sending ", arg1->fNodeRef);
    // save url somewhere (I use NSUserDefaults)
    [self FO_prepareToDrawNode:arg1];
}



- (void) FO_drawIconInContext:(struct CGContext *)arg1
{
    [self FO_drawIconInContext:arg1];

    NSString *iconPath = [[NSUserDefaults standardUserDefaults] valueForKey:@"TDesktopIconURL"];
    NSLog(@"recieved %@", iconPath);

    if (![iconPath isEqualToString:@"/Users/h0xff/Desktop/Restart Finder.app"])
        return;

    NSString *imagePath = @"/Users/h0xff/Desktop/020513_icons/128_synced_green.png";
    NSImage *overlay = [[NSImage alloc] initWithContentsOfFile:imagePath];

    NSImage *mainImage = [(TDesktopIcon*)self thumbnailImage];

    float width = 256.0;
    float height = 256.0;

    NSImage *finalImage = [[NSImage alloc] initWithSize:NSMakeSize(width, height)];

    [finalImage lockFocus];

    // draw the base image
    [mainImage drawInRect:NSMakeRect(0, 0, width, height)
                 fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];

    // draw the overlay image at some offset point
    [overlay drawInRect:NSMakeRect(0, 0, [overlay size].width/1.5, [overlay size].height/1.5)
               fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];

    [finalImage unlockFocus];


    // set image...
    [(TDesktopIcon*)self setThumbnailImage:finalImage];
    [self FO_drawIconInContext:arg1];
}

@end

Этот код был получен от Алексея Жучкова и многих других... пожалуйста, задавайте вопросы, если они у вас есть!

//
//  TFENodeHelper.h
//  FinderMenu
//
//  Helper class to get full path from TFENode
//
//  Created by Alexey Zhuchkov on 11/4/12.
//  Copyright (c) 2012 InfiniteLabs. All rights reserved.
//

#import <Foundation/Foundation.h>

// Forward declarations
struct TFENode;

typedef enum {
    TFENodeCtorTypeUnknown,
    TFENodeCtorTypeNodeWithFENode,  // nodeWithFENode
    TFENodeCtorTypeNodeFromNodeRef,  // nodeFromNodeRef
} TFENodeCtorType;

typedef enum {
    TFENodePathMethodTypeUnknown,
    TFENodePathMethodTypeFullPath,  // fullPath
    TFENodePathMethodTypePreviewItemURL,  // previewItemURL
} TFENodePathMethodType;

@interface TFENodeHelper : NSObject {
    @private
    Class _class;
    TFENodeCtorType _ctorType;
    TFENodePathMethodType _pathMethodType;
}

- (NSString *)pathForNode:(const struct TFENode *)node;
@end


//
//  TFENodeHelper.m
//  FinderMenu
//
//  Created by Alexey Zhuchkov on 11/4/12.
//  Copyright (c) 2012 InfiniteLabs. All rights reserved.
//

#import "TFENodeHelper.h"

#import <objc/runtime.h>

#import "Finder.h"

@implementation TFENodeHelper

- (id)init {
    self = [super init];
    if (self) {
        _class = NSClassFromString(@"FINode");
        _ctorType = TFENodeCtorTypeUnknown;
        _pathMethodType = TFENodePathMethodTypeUnknown;

        if (_class) {
            if (class_getClassMethod(_class, @selector(nodeWithFENode:))) {
                _ctorType = TFENodeCtorTypeNodeWithFENode;
            } else if (class_getClassMethod(_class, @selector(nodeFromNodeRef:))) {
                _ctorType = TFENodeCtorTypeNodeFromNodeRef;
            }

            if (class_getInstanceMethod(_class, @selector(fullPath))) {
                _pathMethodType = TFENodePathMethodTypeFullPath;
            } else if (class_getInstanceMethod(_class, @selector(previewItemURL))) {
                _pathMethodType = TFENodePathMethodTypePreviewItemURL;
            }
        }

        if (!_class
            || (_ctorType == TFENodePathMethodTypeUnknown)
            || (_pathMethodType == TFENodePathMethodTypeUnknown)) {

            [self release];
            return nil;
        }
    }
    return self;
}

- (NSString *)pathForNode:(const struct TFENode *)node {
    FINode *fiNode = nil;
    NSString *path = nil;
    switch (_ctorType) {
        case TFENodeCtorTypeNodeWithFENode:
            fiNode = [_class nodeWithFENode:node];
            break;
        case TFENodeCtorTypeNodeFromNodeRef:
            fiNode = [_class nodeFromNodeRef:node->fNodeRef];
            break;
        default:
            break;
    }

    NSURL *url;
    if (fiNode) {
        switch (_pathMethodType) {
            case TFENodePathMethodTypeFullPath:
                path = [fiNode fullPath];
                break;
            case TFENodePathMethodTypePreviewItemURL:
                url = [fiNode previewItemURL];
                path = [url path];
            default:
                break;
        }
    }

    return path;
}

@end
person Orbitus007    schedule 21.02.2013