Browse code
(init)
Ed L authored on 04/01/2018 19:59:46
Showing 4 changed files
Showing 4 changed files
1 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,101 @@ |
1 |
+(defpackage :demo-app |
|
2 |
+ (:use :cl :objc-runtime) |
|
3 |
+ (:export )) |
|
4 |
+(in-package :demo-app) |
|
5 |
+(named-readtables:in-readtable :objc-readtable) |
|
6 |
+ |
|
7 |
+(cffi:defcallback exception-handler :void ((exception :pointer)) |
|
8 |
+ (with-selectors (reason) |
|
9 |
+ (format t "~&Exxception: ~a~%" [exception reason]) |
|
10 |
+ (values))) |
|
11 |
+ |
|
12 |
+ |
|
13 |
+#+null |
|
14 |
+(cffi:defcfun (set-uncaught-exception-handler "set_uncaught_exception_handler" |
|
15 |
+ :library objc-runtime::expose-stuff) |
|
16 |
+ :void |
|
17 |
+ (cb :pointer)) |
|
18 |
+ |
|
19 |
+(defun call-with-rect (x y w h cb) |
|
20 |
+ (check-type x real) |
|
21 |
+ (check-type y real) |
|
22 |
+ (check-type w real) |
|
23 |
+ (check-type h real) |
|
24 |
+ (cffi:with-foreign-object (rect '(:struct ns-rect)) |
|
25 |
+ (cffi:with-foreign-slots (((:pointer ns-rect-origin) (:pointer ns-rect-size)) |
|
26 |
+ rect (:struct ns-rect)) |
|
27 |
+ (cffi:with-foreign-slots ((ns-point-x ns-point-y) ns-rect-origin (:struct ns-point)) |
|
28 |
+ (setf ns-point-x (coerce x 'double-float) |
|
29 |
+ ns-point-y (coerce y 'double-float))) |
|
30 |
+ (cffi:with-foreign-slots ((ns-size-width ns-size-height) |
|
31 |
+ ns-rect-size (:struct ns-size)) |
|
32 |
+ (setf ns-size-width (coerce w 'double-float) |
|
33 |
+ ns-size-height (coerce h 'double-float)))) |
|
34 |
+ (funcall cb rect))) |
|
35 |
+ |
|
36 |
+(defun call-with-point (x y cb) |
|
37 |
+ (check-type x real) |
|
38 |
+ (check-type y real) |
|
39 |
+ (cffi:with-foreign-object (point '(:struct ns-point)) |
|
40 |
+ (cffi:with-foreign-slots ((ns-point-x ns-point-y) point (:struct ns-point)) |
|
41 |
+ (setf ns-point-x (coerce x 'double-float) |
|
42 |
+ ns-point-y (coerce y 'double-float))) |
|
43 |
+ (funcall cb point))) |
|
44 |
+ |
|
45 |
+(defmacro with-rect ((rect (x y) (w h)) &body body) |
|
46 |
+ `(call-with-rect ,x ,y ,w ,h |
|
47 |
+ (lambda (,rect) |
|
48 |
+ ,@body))) |
|
49 |
+ |
|
50 |
+(defmacro with-point ((point (x y)) &body body) |
|
51 |
+ `(call-with-point ,x ,y |
|
52 |
+ (lambda (,point) |
|
53 |
+ ,@body))) |
|
54 |
+ |
|
55 |
+(defun make-rect (x y w h) |
|
56 |
+ (check-type x real) |
|
57 |
+ (check-type y real) |
|
58 |
+ (check-type w real) |
|
59 |
+ (check-type h real) |
|
60 |
+ (cffi:convert-to-foreign `(ns-rect-origin |
|
61 |
+ (objc-runtime:ns-point-x |
|
62 |
+ ,(coerce x 'double-float) |
|
63 |
+ objc-runtime:ns-point-y |
|
64 |
+ ,(coerce y 'double-float)) |
|
65 |
+ ns-rect-size |
|
66 |
+ (objc-runtime:ns-size-width |
|
67 |
+ ,(coerce w 'double-float) |
|
68 |
+ objc-runtime:ns-size-height |
|
69 |
+ ,(coerce h 'double-float))) |
|
70 |
+ '(:struct objc-runtime:ns-rect))) |
|
71 |
+ |
|
72 |
+(defun main () |
|
73 |
+ (with-selectors ((shared-application "sharedApplication") |
|
74 |
+ (process-info "processInfo") |
|
75 |
+ (process-name "processName") |
|
76 |
+ (set-activation-policy "setActivationPolicy:") |
|
77 |
+ (init-with-content-rect "initWithContentRect:styleMask:backing:defer:") |
|
78 |
+ (set-title "setTitle:") |
|
79 |
+ (run "run") |
|
80 |
+ (activate-ignoring-other-apps "activateIgnoringOtherApps:") |
|
81 |
+ alloc |
|
82 |
+ (make-key-and-order-front "makeKeyAndOrderFront:") |
|
83 |
+ (cascade-top-left-from-point "cascadeTopLeftFromPoint:") |
|
84 |
+ ;; (application-should-terminate "applicationShouldTerminate:") |
|
85 |
+ ;; (set-delegate "setDelegate:") |
|
86 |
+ ;; (finish-launching "finishLaunching") |
|
87 |
+ ) |
|
88 |
+ [#@NSApplication shared-application] |
|
89 |
+ [objc-runtime::ns-app set-activation-policy :int 0] |
|
90 |
+ |
|
91 |
+ (break) |
|
92 |
+ (let* ((application-name [[#@NSProcessInfo process-info] process-name])) |
|
93 |
+ (with-point (p (20 20)) |
|
94 |
+ (let* ((the-window [#@NSWindow alloc])) |
|
95 |
+ [the-window init-with-content-rect :pointer (make-rect 10 10 120 120) |
|
96 |
+ :char 1 :char 2 :boolean nil] |
|
97 |
+ [the-window cascade-top-left-from-point :pointer p] |
|
98 |
+ [the-window set-title :pointer application-name] |
|
99 |
+ [the-window make-key-and-order-front :pointer (cffi:null-pointer)] |
|
100 |
+ [ objc-runtime::ns-app activate-ignoring-other-apps :boolean t] |
|
101 |
+ [ objc-runtime::ns-app run]))))) |
0 | 102 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,31 @@ |
1 |
+(in-package :objc-runtime) |
|
2 |
+ |
|
3 |
+(include "Foundation/NSGeometry.h") |
|
4 |
+(include "AppKit/NSWindow.h") |
|
5 |
+(include "AppKit/NSGraphics.h") |
|
6 |
+ |
|
7 |
+(cc-flags "-x objective-c -framework Foundation -framework AppKit -ObjC") |
|
8 |
+ |
|
9 |
+(cstruct ns-point "NSPoint" |
|
10 |
+ (ns-point-x "x" :type :double) |
|
11 |
+ (ns-point-y "y" :type :double)) |
|
12 |
+ |
|
13 |
+(cstruct ns-size "NSSize" |
|
14 |
+ (ns-size-width "width" :type :double) |
|
15 |
+ (ns-size-height "height" :type :double)) |
|
16 |
+ |
|
17 |
+(cstruct ns-rect "NSRect" |
|
18 |
+ (ns-rect-origin "origin" :type (:struct ns-point)) |
|
19 |
+ (ns-rect-size "size" :type (:struct ns-size))) |
|
20 |
+ |
|
21 |
+(cenum (ns-window-style-mask) |
|
22 |
+ ((:ns-window-style-mask-borderless "NSWindowStyleMaskBorderless")) |
|
23 |
+ ((:ns-window-style-mask-titled "NSWindowStyleMaskTitled")) |
|
24 |
+ ((:ns-window-style-mask-closable "NSWindowStyleMaskClosable")) |
|
25 |
+ ((:ns-window-style-mask-miniaturizable "NSWindowStyleMaskMiniaturizable")) |
|
26 |
+ ((:ns-window-style-mask-resizable "NSWindowStyleMaskResizable"))) |
|
27 |
+ |
|
28 |
+(cenum (ns-backing-store-type) |
|
29 |
+ ((:ns-backing-store-retained "NSBackingStoreRetained")) |
|
30 |
+ ((:ns-backing-store-Nonretained "NSBackingStoreNonretained")) |
|
31 |
+ ((:ns-backing-store-buffered "NSBackingStoreBuffered"))) |
0 | 32 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,184 @@ |
1 |
+(in-package :objc-runtime) |
|
2 |
+ |
|
3 |
+(serapeum:eval-always |
|
4 |
+ (cffi:define-foreign-library cocoa |
|
5 |
+ (:darwin (:framework "Cocoa"))) |
|
6 |
+ (define-foreign-library foundation |
|
7 |
+ (:darwin (:framework "Foundation"))) |
|
8 |
+ (define-foreign-library appkit |
|
9 |
+ (:darwin (:framework "AppKit"))) |
|
10 |
+ (define-foreign-library expose-stuff |
|
11 |
+ (:darwin #p"./libnsrect-expose.dylib"))) |
|
12 |
+ |
|
13 |
+ |
|
14 |
+(use-foreign-library foundation) |
|
15 |
+(use-foreign-library cocoa) |
|
16 |
+(use-foreign-library appkit) |
|
17 |
+(use-foreign-library expose-stuff) |
|
18 |
+ |
|
19 |
+(defctype o-class :pointer) |
|
20 |
+(defctype o-selector :pointer) |
|
21 |
+ |
|
22 |
+(defcfun (objc-look-up-class "objc_lookUpClass" :library foundation) |
|
23 |
+ o-class |
|
24 |
+ (name :string)) |
|
25 |
+ |
|
26 |
+(defcfun (objc-allocate-class-pair "objc_allocateClassPair" :library foundation) |
|
27 |
+ :pointer |
|
28 |
+ (superclass :pointer) |
|
29 |
+ (name :string) |
|
30 |
+ (extra-bytes :int)) |
|
31 |
+ |
|
32 |
+(defcfun (objc-get-protocol "objc_getProtocol" :library foundation) |
|
33 |
+ :pointer |
|
34 |
+ (name :string)) |
|
35 |
+ |
|
36 |
+(defcfun (class-add-protocol "class_addProtocol" :library foundation) |
|
37 |
+ :boolean |
|
38 |
+ (class :pointer) |
|
39 |
+ (protocol :pointer)) |
|
40 |
+ |
|
41 |
+(defcfun (class-add-method "class_addMethod" :library foundation) |
|
42 |
+ :boolean |
|
43 |
+ (class :pointer) |
|
44 |
+ (selector :pointer) |
|
45 |
+ (cb :pointer) |
|
46 |
+ (type :string)) |
|
47 |
+ |
|
48 |
+(defcfun (objc-class-get-name "class_getName" :library foundation) |
|
49 |
+ :string |
|
50 |
+ (cls o-class)) |
|
51 |
+ |
|
52 |
+(defcfun (objc-class-get-superclass "class_getSuperclass" :library foundation) |
|
53 |
+ :pointer |
|
54 |
+ (cls o-class)) |
|
55 |
+ |
|
56 |
+(defcfun (objc-get-class-list "objc_getClassList" :library foundation) |
|
57 |
+ :int |
|
58 |
+ (cls-buffer o-class) |
|
59 |
+ (buffer-count :int)) |
|
60 |
+ |
|
61 |
+(defcfun (sel-register-name "sel_registerName" :library foundation) |
|
62 |
+ o-selector |
|
63 |
+ (name :string)) |
|
64 |
+ |
|
65 |
+(defcfun (objc-msg-send "objc_msgSend") |
|
66 |
+ :pointer |
|
67 |
+ (cls o-class) |
|
68 |
+ (sel o-selector) |
|
69 |
+ &rest) |
|
70 |
+ |
|
71 |
+(defcfun (class-copy-method-list "class_copyMethodList" :library foundation) |
|
72 |
+ :pointer |
|
73 |
+ (cls o-class) |
|
74 |
+ (numMethods (:pointer :int))) |
|
75 |
+ |
|
76 |
+(defcfun (method-get-name "method_getName") |
|
77 |
+ :pointer |
|
78 |
+ (method :pointer)) |
|
79 |
+ |
|
80 |
+(defcfun (sel-get-name "sel_getName") |
|
81 |
+ :string |
|
82 |
+ (sel o-selector)) |
|
83 |
+ |
|
84 |
+(defgeneric get-methods (class) |
|
85 |
+ (:method ((class string)) |
|
86 |
+ (get-methods (objc-look-up-class class))) |
|
87 |
+ #+sbcl |
|
88 |
+ (:method ((class sb-sys:system-area-pointer)) |
|
89 |
+ (with-foreign-object (num-methods :int) |
|
90 |
+ (let ((methods (class-copy-method-list class num-methods))) |
|
91 |
+ (let ((result (list))) |
|
92 |
+ (dotimes (n (mem-aref num-methods :int) (nreverse result)) |
|
93 |
+ (push (mem-aref methods :pointer n) |
|
94 |
+ result))))))) |
|
95 |
+ |
|
96 |
+(defun get-method-names (thing) |
|
97 |
+ (mapcar (alexandria:compose #'sel-get-name |
|
98 |
+ #'method-get-name) |
|
99 |
+ (get-methods thing))) |
|
100 |
+ |
|
101 |
+(defgeneric graph->dot (graph stream) |
|
102 |
+ (:method :around (graph stream) |
|
103 |
+ (format stream "~&digraph {~%~4trankdir=LR;~%") |
|
104 |
+ (call-next-method) |
|
105 |
+ (format stream "~&}")) |
|
106 |
+ (:method ((graph hash-table) stream) |
|
107 |
+ (loop for class being the hash-keys of graph using (hash-value superclass) |
|
108 |
+ do (format stream "~&~4t\"~a\" -> \"~a\"~%" class superclass)))) |
|
109 |
+ |
|
110 |
+(defparameter *selector-cache* (make-hash-table :test 'equal)) |
|
111 |
+ |
|
112 |
+(defun ensure-selector (name) |
|
113 |
+ (alexandria:ensure-gethash name *selector-cache* |
|
114 |
+ (sel-register-name name))) |
|
115 |
+ |
|
116 |
+(defmacro with-selectors ((&rest selector-specs) &body body) |
|
117 |
+ `(let (,@(mapcar (fw.lu:destructuring-lambda ((sym foreign-selector)) |
|
118 |
+ `(,sym (ensure-selector ,foreign-selector))) |
|
119 |
+ (mapcar (fw.lu:glambda (spec) |
|
120 |
+ (:method ((spec symbol)) |
|
121 |
+ (list spec (string-downcase spec))) |
|
122 |
+ (:method ((spec cons)) |
|
123 |
+ (list (car spec) (cadr spec)))) |
|
124 |
+ selector-specs))) |
|
125 |
+ ,@body)) |
|
126 |
+ |
|
127 |
+(defmacro with-objc-classes ((&rest class-defs) &body body) |
|
128 |
+ `(let (,@(mapcar (fw.lu:destructuring-lambda ((lisp-name foreign-name)) |
|
129 |
+ `(,lisp-name (objc-look-up-class ,foreign-name))) |
|
130 |
+ class-defs)) |
|
131 |
+ ,@body)) |
|
132 |
+ |
|
133 |
+ |
|
134 |
+(eval-when (:compile-toplevel :load-toplevel :execute) |
|
135 |
+ (named-readtables:defreadtable :objc-readtable |
|
136 |
+ (:merge :standard) |
|
137 |
+ (:syntax-from :standard #\) #\]) |
|
138 |
+ (:macro-char #\[ (lambda (s char) |
|
139 |
+ char |
|
140 |
+ (destructuring-bind (obj message . args) |
|
141 |
+ (read-delimited-list #\] s t) |
|
142 |
+ `(objc-msg-send ,obj ,message ,@args))) |
|
143 |
+ nil) |
|
144 |
+ (:dispatch-macro-char #\# #\@ |
|
145 |
+ (lambda (s c b) |
|
146 |
+ c b |
|
147 |
+ (let ((class-name (coerce (loop for c = (read-char s nil nil t) |
|
148 |
+ until (or (null c) |
|
149 |
+ (serapeum:whitespacep c)) |
|
150 |
+ collect c) |
|
151 |
+ 'string))) |
|
152 |
+ `(objc-look-up-class ,class-name)))))) |
|
153 |
+ |
|
154 |
+(named-readtables:in-readtable :objc-readtable) |
|
155 |
+ |
|
156 |
+(defgeneric make-objc-instance (class &rest args) |
|
157 |
+ (:method ((class string) &rest args) |
|
158 |
+ (apply #'make-objc-instance (objc-look-up-class class) args)) |
|
159 |
+ #+ccl |
|
160 |
+ (:method ((class ccl:macptr) &rest args) |
|
161 |
+ (declare (ignore args)) |
|
162 |
+ (with-selectors (alloc init) |
|
163 |
+ [[class alloc] init])) |
|
164 |
+ #+sbcl |
|
165 |
+ (:method ((class sb-sys:system-area-pointer) &rest args) |
|
166 |
+ (declare (ignore args)) |
|
167 |
+ (with-selectors (alloc init) |
|
168 |
+ [[class alloc] init]))) |
|
169 |
+ |
|
170 |
+ |
|
171 |
+(cffi:defcvar (ns-app "NSApp" :library appkit) :pointer) |
|
172 |
+ |
|
173 |
+#| |
|
174 |
+(uiop:nest (with-selectors (alloc init drain)) |
|
175 |
+ (with-objc-classes ((nsobject "NSAutoreleasepool"))) |
|
176 |
+ (eval-objc (objc-msg-send |
|
177 |
+ (objc-msg-send |
|
178 |
+ (objc-msg-send nsobject alloc) |
|
179 |
+ init) |
|
180 |
+ drain))) |
|
181 |
+(with-selectors (alloc init)) |
|
182 |
+ |
|
183 |
+|# |
|
184 |
+ |
0 | 185 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,24 @@ |
1 |
+(defpackage :objc-runtime/package |
|
2 |
+ (:use :cl ) |
|
3 |
+ (:export )) |
|
4 |
+(in-package :objc-runtime/package) |
|
5 |
+ |
|
6 |
+(defpackage :objc-runtime |
|
7 |
+ (:use :cl :cffi) |
|
8 |
+ (:export |
|
9 |
+ #:defmacro |
|
10 |
+ #:*objc-readtable* |
|
11 |
+ #:with-selectors |
|
12 |
+ #:objc-msg-send |
|
13 |
+ #:with-objc-classes |
|
14 |
+ #:make-objc-instance |
|
15 |
+ #:objc-readtable |
|
16 |
+ #:ns-size-width |
|
17 |
+ #:ns-size-height |
|
18 |
+ #:ns-rect-origin |
|
19 |
+ #:ns-rect-size |
|
20 |
+ #:ns-point-x |
|
21 |
+ #:ns-point-y |
|
22 |
+ #:ns-point |
|
23 |
+ #:ns-size |
|
24 |
+ #:ns-rect)) |