Last active
April 5, 2018 11:19
-
-
Save knugie/4999c3756cc317a2771bda369cbded01 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
################################################### | |
## Display screen dimensions in macOS using ruby ## | |
################################################## | |
# found https://developer.apple.com/reference/coregraphics/1456395-cgdisplaybounds?language=objc | |
# --> use CoreGraphics framework | |
# --> CGRect CGDisplayBounds(CGDirectDisplayID display); | |
############################################# | |
## How to bind (objective)C code in ruby ? ## | |
############################################# | |
# found https://github.com/ffi/ffi/wiki | |
# --> gem install ffi | |
require 'ffi' | |
module Display | |
extend FFI::Library | |
###################################### | |
## How to find CoreGraphics dynlib? ## | |
###################################### | |
# --> it's in "/System/Library/Frameworks" ;-) | |
ffi_lib '/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics' | |
########################################################### | |
## How to find and bind (objective)C functions in ruby ? ## | |
########################################################### | |
# 1. $ nm | |
# --> nm -gU '/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics' | |
# --> not really helpful :-( | |
# 2. xml | |
# --> "/System/Library/Frameworks/CoreGraphics.framework/Versions/A/Resources/BridgeSupport/CoreGraphics.bridgesupport" | |
# <function name='CGMainDisplayID'> | |
# <retval type='I'/> | |
# </function> | |
# What is 'I' ? | |
# 1. https://github.com/ffi/ffi/wiki/Types / xml / dtd ... | |
# --> not really helpful :-( | |
# 2. https://github.com/patrickhno/cocoa/blob/master/lib/cocoa/objc/method_def.rb#L5 | |
# It's :uint | |
################################### | |
## Use cocoa in the first place? ## | |
################################### | |
# --> tried, turns out there's a bug when using CGDirectDisplayID :-( | |
# require 'cocoa' | |
# Cocoa.CGMainDisplayID | |
# --> ArgumentError: wrong number of arguments (given 1, expected 2) | |
# Cocoa.CGMainDisplayID(0) | |
# --> ArgumentError: wrong number of arguments (given 1, expected 0) | |
# However, when falling back to default CGDirectDisplayID, Cocoa.CGDisplayBounds(0) | |
# Cocoa.CGDisplayBounds(0) | |
# --> <Cocoa::CGRect:0x007fa118b39078> | |
# I don'd want to use unmaintained gems anyway (https://github.com/patrickhno/cocoa/commits/master) | |
# What was 'I' again...? | |
# CGRect CGDisplayBounds(CGDirectDisplayID display); | |
# Define a new type from :uint called :CGDirectDisplayID | |
typedef :uint, :CGDirectDisplayID | |
################################################### | |
## How to bind (objective)C functions using ffi? ## | |
################################################### | |
# attach_function | |
# --> http://www.rubydoc.info/github/ffi/ffi/FFI/Library:attach_function | |
# --> https://github.com/ffi/ffi/blob/master/lib/ffi/library.rb#L204 | |
# <function name='CGMainDisplayID'> | |
# <retval type='I'/> | |
# </function> | |
attach_function :CGMainDisplayID, [], :CGDirectDisplayID | |
# Display.CGMainDisplayID | |
# --> 69732928 | |
# weird number, but it seems to work | |
# CGRect CGDisplayBounds(CGDirectDisplayID display); | |
########################### | |
## How to define CGRect? ## | |
########################### | |
# --> <struct name="CGRect" | |
# type="{CGRect="origin"{CGPoint="x"f"y"f}"size"{CGSize="width"f"height"f}}" | |
# type64="{CGRect="origin"{CGPoint="x"d"y"d}"size"{CGSize="width"d"height"d}}"/> | |
###################### | |
## What's all this? ## | |
###################### | |
# --> "name" is prefixed in quotes | |
# --> {} defined a struct(ure) | |
# --> f is :float | |
# --> d is :double | |
# CGPoint and CGSize need to be defined first | |
################################## | |
## How to define those structs? ## | |
################################## | |
# --> use FFI::Struct | |
# https://github.com/ffi/ffi/wiki/Basic-Usage#passing-structs-as-value-parameters-to-functions | |
# http://www.rubydoc.info/github/ffi/ffi/FFI/Struct | |
# <struct name="CGPoint" type="{CGPoint="x"f"y"f}" type64="{CGPoint="x"d"y"d}"/> | |
class CGPoint < FFI::Struct | |
layout :x, :double, :y, :double | |
end | |
# <struct name="CGSize" type="{CGSize="width"f"height"f}" type64="{CGSize="width"d"height"d}"/> | |
class CGSize < FFI::Struct | |
layout :width, :double, :height, :double | |
end | |
# <struct name="CGRect" type="{CGRect="origin"{CGPoint="x"f"y"f}"size"{CGSize="width"f"height"f}}" type64="{CGRect="origin"{CGPoint="x"d"y"d}"size"{CGSize="width"d"height"d}}"/> | |
class CGRect < FFI::Struct | |
layout :origin, CGPoint, :size, CGSize | |
end | |
# finally bind CGDisplayBounds | |
# <function name='CGDisplayBounds'> | |
# <arg type='I'/> | |
# <retval type='{CGRect={CGPoint=ff}{CGSize=ff}}' type64='{CGRect={CGPoint=dd}{CGSize=dd}}'/> | |
# </function> | |
attach_function :CGDisplayBounds, [:CGDirectDisplayID], CGRect.by_value | |
# Done! | |
end | |
displayID = Display.CGMainDisplayID | |
bounds = Display.CGDisplayBounds(displayID) | |
puts "width: #{'%d' % bounds[:size][:width]}, height: #{'%d' % bounds[:size][:height]}" | |
# There are helper methods like CGRectGetHeight, so you could spare the definition of CGSize. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment