Hacking Mac OSX Cocoa API from Perl
-
Upload
typester -
Category
Technology
-
view
4.357 -
download
6
Transcript of Hacking Mac OSX Cocoa API from Perl
Hacking Mac OS X Cocoa API from Perl
Daisuke Murase (typester)YAPC::Asia Tokyo 2011
About me
• Daisuke Murase
• KAYAC Inc. (2004 - present)
• This year’s work:
About me
• Daisuke Murase
• KAYAC Inc. (2004 - present)
• This year’s work:
• Reengo(Facebook integrated VoIP application for iOS)
About me
• Daisuke Murase
• KAYAC Inc. (2004 - present)
• This year’s work:
• Reengo(Facebook integrated VoIP application for iOS)
• VQ Checker (Voice Quotient analyzer for PC and iOS)
About me
• Daisuke Murase
• KAYAC Inc. (2004 - present)
• This year’s work:
• Reengo(Facebook integrated VoIP application for iOS)
• VQ Checker (Voice Quotient analyzer for PC and iOS)
• One more thing...(Will be released before this xmas!)
About me
• a.k.a typester
About me
• a.k.a typester• http://search.cpan.org/~TYPESTER/• http://github.com/typester• http://facebook.com/typester• http://twitter.com/typester
♥ Mazda Roadster (known as MX-5 in other countries)
Agenda
• A little knowledge about Objective-C• How to use Objective-C from Perl• A little knowledge about XS• Some tips about XS and Objective-C• Introducing Cocoa:: modules I’ve created
Objective-C
Objective-C
• Created for NextStep.• It’s currently used as primary programming language for Mac OS X.
• Implemented based C.All C syntax and features can be used in Objective-C file.
Objective-C
• #import <Foundation/Foundation.h>
int main(int argc, char** argv) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
// Objective-C code here NSLog(@”Hello World!”);
[pool drain]; return 0;}
Objective-C
• gcc -framework Foundation foo.m
Objective-C
• gcc -framework Foundation foo.m• (like gcc -lFoundation foo.c)
Objective-C
• gcc -framework Foundation foo.m• (like gcc -lFoundation foo.c)• ./a.out
XS
• Foo.xs file is not use directly for C compiler
• Foo.xs will convert Foo.c by xsubpp• You can write Foo.c directly if you want.
Foo.c
• #include "EXTERN.h"#include "perl.h"#include "XSUB.h"#include "ppport.h"
XS(func) { dXSARGS;
// code here
XSRETURN(0);}
XS(boot_Foo) { newXS("Foo::xs_function", func, __FILE__);}
package Foo
• package Foo;use strict;use XSLoader;
XSLoader::load __PACKAGE__, $VERSION;
1;
Run it
• use Foo;
Foo::xs_function();
Makefile.PL for Foo.c
• use inc::Module::Install;
# some basic descriptions here
use_ppport '3.19';
WriteAll;
• (Module::Install::XSUtil)++
• See also Data::MessagePack, Data::AMF::XS, that is using this pseudo-XS technique.
Makefile.PL for Foo.m
Makefile.PL for Foo.m
• use inc::Module::Install;
# some basic descriptions hereuse_ppport '3.19';cc_append_to_libs '-lobjc';
makemaker_args->{dynamic_lib} = { OTHERLDFLAGS => '-framework Foundation',};
{ # http://www.mail-archive.com/[email protected]/msg02823.html # Add some required machinery to support .m files package MY; sub c_o { my $inherited = shift->SUPER::c_o(@_); $inherited .= <<'EOMESS';.m$(OBJ_EXT): $(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.m
EOMESS $inherited; }
sub xs_c { my $inherited = shift->SUPER::xs_c(@_); $inherited .= <<'EOMESS';.xs.m: $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $(XSUBPP_EXTRA_ARGS) $*.xs > $*.xsm && $(MV) $*.xsm $*.m
EOMESS $inherited; }
sub init_dirscan { my $self = shift; $self->SUPER::init_dirscan; foreach my $name ($self->lsdir($self->curdir)) {
Makefile.PL for Foo.m
• Sorry :)
Makefile.PL for Foo.m
• Sorry :)• See Cocoa::* ‘s Makefile.PL• https://metacpan.org/source/TYPESTER/Cocoa-EventLoop-0.04/Makefile.PL
That’s it
• Objective-C involve all C functions and features.
• Just rename Foo.c to Foo.m, it completely works by this Makefile.PL
• And of cause, you can use Objective-C specific syntax in this file!
Hello.m• #include "EXTERN.h"
#include "perl.h"#include "XSUB.h"#include "ppport.h"
// undefine Move macro, this is conflict to Mac OS X QuickDraw API.#undef Move
#import <Foundation/Foundation.h>
XS(hello) { dXSARGS;
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSLog(@"Hello!"); [pool drain];
XSRETURN(0);}
XS(boot_Hello) { newXS("Hello::hello", hello, __FILE__);}
Copies and pastes for XS
• #include "EXTERN.h"#include "perl.h"#include "XSUB.h"#include "ppport.h"
Copies and pastes for XS
• #undef Move
Copies and pastes for XS
• XS(function) { dXSARGS; // code here XSRETURN(0);}
Copies and pastes for XS
• XS(function) { dXSARGS; // code here ST(0) = some_sv; XSRETURN(1);}
Copies and pastes for XS
• XS(function) { dXSARGS; // code here ST(0) = some_sv; ST(1) = some_sv2; XSRETURN(2);}
Copies and pastes for XS
• XS(function) { dXSARGS;
SV* sv_args1 = ST(0); SV* sv_args2 = ST(1); // code here
ST(0) = some_sv; ST(1) = some_sv2; XSRETURN(2);}
Copies and pastes for XS
• XS(function) { dXSARGS;
if (items < 2) { Perl_croak(aTHX_ "Usage: function($args1, $args2)"); }
SV* sv_args1 = ST(0); SV* sv_args2 = ST(1);
// code here ST(0) = some_sv; ST(1) = some_sv2; XSRETURN(2);}
for Objective-C and Perl
• Perl string to NSString
STRLEN len; char* c = SvPV(sv, len); NSString* str = [NSString stringWithUTF8String:c];
• NSString to Perl string
SV* sv = sv_2mortal(newSV(0)); sv_setpv(sv, [str UTF8String]);
for Objective-C and Perl
• Perl number to NSNumber
NSNumber* n;if (SvNOKp(sv)) { n = [NSNumber numberWithDouble:(double)SvNVX(sv))];}else if (SvIOK_UV(sv)) { n = [NSNumber numberWithDouble:(double)SvUV(sv))];}else if (SvIOKp(sv)) { n = [NSNumber numberWithDouble:(double)SvIV(sv))];}
• NSNumber to Perl number
SV* sv = sv_2mortal(newSVnv([n doubleValue]));
for Objective-C and Perl
• Snip.., described in my blog later• Perl array to NSArray• NSArray to Perl array• Perl hash to NSDictionary• NSDictionary to Perl hash
Don’t forget
• enable NSAutoreleasePool scope around your NS* objects
• otherwise the code will crash.
Your friends
• perldoc perlguts• perldoc perlapi• xcode documentation
Cocoa:: modules
Cocoa:: modules
• Cocoa::EventLoop• Cocoa::Growl• AnyEvent::Impl::Cocoa
Cocoa::EventLoop
• provides perl interface for Cocoa's event loop, NSRunLoop.
• also provides timers, I/O watchers acts with that event loop.
• You can handle event callbacks correctly by using this module.
Cocoa::Growl
• Perl interface for Growl.framework• Support click event with Cocoa::EventLoop
Cocoa::Growl
• use Cocoa::Growl ':all';
my $installed = growl_installed();my $running = growl_running();
Cocoa::Growl
• use Cocoa::Growl ':all';
# register applicationgrowl_register( app => 'My growl script', icon => '/path/to/icon.png', # or 'http://urlto/icon' notifications => [qw(Notification1 Notification2)],);
Cocoa::Growl
• use Cocoa::Growl ':all';
# show growl notificationgrowl_notify( name => 'Notification1', title => 'Hello!', description => 'Growl world!',);
Cocoa::Growl• use Cocoa::EventLoop;
use Cocoa::Growl ':all'; growl_register( name => 'test script', notifications => ['test notification'], ); my $wait = 1; growl_notify( name => 'test notification', title => 'Hello', description => 'Growl World!', on_click => sub { warn 'click'; $wait = 0; }, on_timeout => sub { warn 'timeout'; $want = 0; }, ); Cocoa::EventLoop->run_while(0.1) while unless $wait;
AnyEvent::Impl::Cocoa
• AnyEvent adaptor for Cocoa::EventLoop• you can use Cocoa based API in your AnyEvent application, or AnyEvent within Cocoa applications
AnyEvent::Impl::Cocoa
• Just do this:use AnyEvent;use Cocoa::EventLoop;
# then all anyevent based api use Cocoa::EventLoop!
AnyEvent::Impl::Cocoa
• use AnyEvent;use Cocoa::EventLoop;use Cocoa::Growl;
my $cv = AE::cv;growl_notify( name => 'test notification', title => 'Hello', description => 'Growl World!', on_click => sub { warn ‘click’; $cv->send; }, on_timeout => sub { warn ‘timeout’; $cv->send; },);$cv->recv;
Enjoy!