Module: Echoes::ObjC

Defined in:
lib/echoes/objc.rb

Constant Summary collapse

LIBOBJC =
Fiddle.dlopen('/usr/lib/libobjc.A.dylib')
APPKIT =
Fiddle.dlopen('/System/Library/Frameworks/AppKit.framework/AppKit')
FOUNDATION =
Fiddle.dlopen('/System/Library/Frameworks/Foundation.framework/Foundation')
P =

Type aliases

Fiddle::TYPE_VOIDP
D =
Fiddle::TYPE_DOUBLE
L =
Fiddle::TYPE_LONG
I =
Fiddle::TYPE_INT
V =
Fiddle::TYPE_VOID
GetClass =

Core runtime functions

Fiddle::Function.new(LIBOBJC['objc_getClass'], [P], P)
RegisterName =
Fiddle::Function.new(LIBOBJC['sel_registerName'], [P], P)
AllocateClassPair =
Fiddle::Function.new(LIBOBJC['objc_allocateClassPair'], [P, P, I], P)
AddMethod =
Fiddle::Function.new(LIBOBJC['class_addMethod'], [P, P, P, P], I)
RegisterClassPair =
Fiddle::Function.new(LIBOBJC['objc_registerClassPair'], [P], V)
GetMethodImpl =
Fiddle::Function.new(LIBOBJC['class_getMethodImplementation'], [P, P], P)
AddProtocol =
Fiddle::Function.new(LIBOBJC['class_addProtocol'], [P, P], I)
GetProtocol =
Fiddle::Function.new(LIBOBJC['objc_getProtocol'], [P], P)
MSG_PTR =

id = msg(id, SEL)

new_msg([P, P], P)
MSG_PTR_1 =

id = msg(id, SEL, id)

new_msg([P, P, P], P)
MSG_PTR_2 =

id = msg(id, SEL, id, id)

new_msg([P, P, P, P], P)
MSG_PTR_L =

id = msg(id, SEL, long)

new_msg([P, P, L], P)
MSG_PTR_1L =

id = msg(id, SEL, id, long)

new_msg([P, P, P, L], P)
MSG_VOID =

void = msg(id, SEL)

new_msg([P, P], V)
MSG_VOID_1 =

void = msg(id, SEL, id)

new_msg([P, P, P], V)
MSG_VOID_2 =

void = msg(id, SEL, id, id)

new_msg([P, P, P, P], V)
MSG_VOID_4 =

void = msg(id, SEL, id, id, id, id)

new_msg([P, P, P, P, P, P], V)
MSG_PTR_3 =

id = msg(id, SEL, id, id, id)

new_msg([P, P, P, P, P], P)
MSG_VOID_I =

void = msg(id, SEL, int)

new_msg([P, P, I], V)
MSG_VOID_L =

void = msg(id, SEL, long)

new_msg([P, P, L], V)
MSG_VOID_2D =

void = msg(id, SEL, double, double)

new_msg([P, P, D, D], V)
MSG_RET_D =

double = msg(id, SEL)

new_msg([P, P], D)
MSG_PTR_D =

id = msg(id, SEL, double)

new_msg([P, P, D], P)
MSG_RET_D_1 =

double = msg(id, SEL, id)

new_msg([P, P, P], D)
MSG_RET_L =

long = msg(id, SEL)

new_msg([P, P], L)
MSG_PTR_RECT =

CGRect as 4 doubles

new_msg([P, P, D, D, D, D], P)
MSG_VOID_RECT =

NSRectFill equivalent

new_msg([P, P, D, D, D, D], V)
MSG_VOID_RECT_1 =

addCursorRect:cursor:

new_msg([P, P, D, D, D, D, P], V)
MSG_VOID_RECT_D =

NSGradient drawInRect:angle: (4 doubles for rect + 1 double for angle)

new_msg([P, P, D, D, D, D, D], V)
MSG_PTR_RECT_L_L_I =

initWithContentRect:styleMask:backing:defer:

new_msg([P, P, D, D, D, D, L, L, I], P)
MSG_VOID_PT_1 =

drawAtPoint:withAttributes: (NSPoint = 2 doubles + id)

new_msg([P, P, D, D, P], V)
MSG_VOID_1_PT_1 =

popUpMenuPositioningItem:atLocation:inView: (id + NSPoint + id)

new_msg([P, P, P, D, D, P], V)
MSG_VOID_D_1 =

setDouble:forKey: (double + id) -> void

new_msg([P, P, D, P], V)
MSG_PTR_4D =

colorWithRed:green:blue:alpha: (4 doubles)

new_msg([P, P, D, D, D, D], P)
MSG_PTR_1D =

fontWithName:size: (id, double)

new_msg([P, P, P, D], P)
MSG_PTR_2D =

monospacedSystemFontOfSize:weight: (2 doubles)

new_msg([P, P, D, D], P)
MSG_PTR_D_P_P_P_I =

scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:

new_msg([P, P, D, P, P, P, I], P)
NSRectFill =

NSRectFill C function

Fiddle::Function.new(APPKIT['NSRectFill'], [D, D, D, D], V)
NSWindowStyleMaskTitled =

Cocoa constants

1 << 0
NSWindowStyleMaskClosable =
1 << 1
NSWindowStyleMaskMiniaturizable =
1 << 2
NSWindowStyleMaskResizable =
1 << 3
NSWindowStyleMaskDefault =
NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable
NSBackingStoreBuffered =
2
NSEventModifierFlagShift =
1 << 17
NSEventModifierFlagControl =
1 << 18
NSEventModifierFlagOption =
1 << 19
NSEventModifierFlagCommand =
1 << 20
NSEventModifierFlagNumericPad =
1 << 21
SEL_CACHE =

Selector cache

{}
NSFontAttributeName =
appkit_const('NSFontAttributeName')
NSForegroundColorAttributeName =
appkit_const('NSForegroundColorAttributeName')
NSUnderlineStyleAttributeName =
appkit_const('NSUnderlineStyleAttributeName')
NSStrikethroughStyleAttributeName =
appkit_const('NSStrikethroughStyleAttributeName')
NSPasteboardTypeString =
appkit_const('NSPasteboardTypeString')
NSPasteboardTypeFileURL =
appkit_const('NSPasteboardTypeFileURL')
COREGRAPHICS =

CoreGraphics framework

Fiddle.dlopen('/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics')
CGColorSpaceCreateDeviceRGB =
Fiddle::Function.new(COREGRAPHICS['CGColorSpaceCreateDeviceRGB'], [], P)
CGColorSpaceRelease =
Fiddle::Function.new(COREGRAPHICS['CGColorSpaceRelease'], [P], V)
CGBitmapContextCreate =
Fiddle::Function.new(COREGRAPHICS['CGBitmapContextCreate'], [P, L, L, L, L, P, I], P)
CGBitmapContextCreateImage =
Fiddle::Function.new(COREGRAPHICS['CGBitmapContextCreateImage'], [P], P)
CGContextDrawImage =
Fiddle::Function.new(COREGRAPHICS['CGContextDrawImage'], [P, D, D, D, D, P], V)
CGContextSaveGState =
Fiddle::Function.new(COREGRAPHICS['CGContextSaveGState'], [P], V)
CGContextRestoreGState =
Fiddle::Function.new(COREGRAPHICS['CGContextRestoreGState'], [P], V)
CGContextTranslateCTM =
Fiddle::Function.new(COREGRAPHICS['CGContextTranslateCTM'], [P, D, D], V)
CGContextScaleCTM =
Fiddle::Function.new(COREGRAPHICS['CGContextScaleCTM'], [P, D, D], V)
CGImageRelease =
Fiddle::Function.new(COREGRAPHICS['CGImageRelease'], [P], V)
CGContextRelease =
Fiddle::Function.new(COREGRAPHICS['CGContextRelease'], [P], V)
KCGImageAlphaPremultipliedLast =

kCGImageAlphaPremultipliedLast | kCGBitmapByteOrderDefault

1
CORETEXT =

CoreText framework

Fiddle.dlopen('/System/Library/Frameworks/CoreText.framework/CoreText')
CTFontCreateForString =

CTFontCreateForString(CTFontRef currentFont, CFStringRef string, CFRange range) -> CTFontRef CFRange is CFIndex = long, decomposed into 2 GPR args on arm64

Fiddle::Function.new(CORETEXT['CTFontCreateForString'], [P, P, L, L], P)

Class Method Summary collapse

Class Method Details

.appkit_const(name) ⇒ Object

AppKit string constant accessors



151
152
153
154
# File 'lib/echoes/objc.rb', line 151

def self.appkit_const(name)
  ptr = Fiddle::Pointer.new(APPKIT[name])
  Fiddle::Pointer.new(ptr[0, Fiddle::SIZEOF_VOIDP].unpack1('J'))
end

.cls(name) ⇒ Object



103
104
105
# File 'lib/echoes/objc.rb', line 103

def self.cls(name)
  GetClass.call(name)
end

.define_class(name, superclass_name, methods) ⇒ Object



140
141
142
143
144
145
146
147
148
# File 'lib/echoes/objc.rb', line 140

def self.define_class(name, superclass_name, methods)
  super_cls = cls(superclass_name)
  new_cls = AllocateClassPair.call(super_cls, name, 0)
  methods.each do |sel_name, (type_encoding, closure)|
    AddMethod.call(new_cls, sel(sel_name), closure, type_encoding)
  end
  RegisterClassPair.call(new_cls)
  new_cls
end

.new_msg(args, ret) ⇒ Object

objc_msgSend variants for different signatures



29
30
31
# File 'lib/echoes/objc.rb', line 29

def self.new_msg(args, ret)
  Fiddle::Function.new(LIBOBJC['objc_msgSend'], args, ret)
end

.nsdict(hash) ⇒ Object



128
129
130
131
132
133
134
# File 'lib/echoes/objc.rb', line 128

def self.nsdict(hash)
  dict = MSG_PTR.call(cls('NSMutableDictionary'), sel('dictionary'))
  hash.each do |key, value|
    MSG_VOID_2.call(dict, sel('setObject:forKey:'), value, key)
  end
  dict
end

.nsnumber_int(val) ⇒ Object



136
137
138
# File 'lib/echoes/objc.rb', line 136

def self.nsnumber_int(val)
  MSG_PTR_L.call(cls('NSNumber'), sel('numberWithInteger:'), val)
end

.nsstring(str) ⇒ Object



119
120
121
# File 'lib/echoes/objc.rb', line 119

def self.nsstring(str)
  MSG_PTR_1.call(cls('NSString'), sel('stringWithUTF8String:'), str)
end

.release(obj) ⇒ Object



115
116
117
# File 'lib/echoes/objc.rb', line 115

def self.release(obj)
  MSG_VOID.call(obj, sel('release'))
end

.retain(obj) ⇒ Object



111
112
113
# File 'lib/echoes/objc.rb', line 111

def self.retain(obj)
  MSG_PTR.call(obj, sel('retain'))
end

.sel(name) ⇒ Object



107
108
109
# File 'lib/echoes/objc.rb', line 107

def self.sel(name)
  SEL_CACHE[name] ||= RegisterName.call(name)
end

.to_ruby_string(nsstring_ptr) ⇒ Object



123
124
125
126
# File 'lib/echoes/objc.rb', line 123

def self.to_ruby_string(nsstring_ptr)
  cstr = MSG_PTR.call(nsstring_ptr, sel('UTF8String'))
  cstr.to_s.force_encoding(Encoding::UTF_8)
end