[Openmcl-devel] Need Some ObjC Bridge Help

Gary Byers gb at clozure.com
Tue Mar 20 23:32:20 PDT 2007


There are a couple of similarly named class methods on NSDictionary that
take their arguments in different ways.

The method dictionaryWithObjectsAndKeys: takes a fixed first object
argument, followed by the key associated with the first object, followed
by 0 or more object/key pairs, followed by a terminating null pointer.

The method dictionaryWithObjects:forKeys: takes two fixed arguments,
the first of which is an NSArray of values and the second of which is
an NSArray of keys.

The SEND macro doesn't know anything about the foreign types of
non-fixed arguments (as would be involved in the first case); it
requires that these arguments have explicit type keywords associated
with them, and requires that they be grouped in a list.  So, to
create a dictionary that had a single key/value pair using 
dictionaryWithObjectsAndKeys:, you'd do something like:

? (defvar *font* (send (send (find-class 'ns:ns-font) :user-fixed-pitch-font-of-size 12.0) 'retain))
*FONT*
? (send (send (find-class 'ns:ns-dictionary)
        :dictionary-with-objects-and-keys *font* (:id #&NSFontAttributeName :address (%null-ptr))) 'retain)
#<NS-MUTABLE-DICTIONARY {NSFont = "Monaco 12.00 pt. P [] (0x003303f0) fobj=0x0032fe00, spc=7.20"; } (#x330410)>

(The extra level of parens around the variable part of the arglist
are necessary to keep SEND from trying to construct a message name of
the form

dictionaryWithObjectsAndKeys:id:address:

which might exist and be something very different from what we're
trying to do here.
)


On Tue, 20 Mar 2007, Brent Fulgham wrote:

> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Hi,
>
> I'm trying to determine the width of a string based on a specific
> font (eventually it will default to the current system font, but
> first I want to get this case working).
>
> Based on the Apple documentation, something like this should work:
>
> NSFont* font = [NSFont fontWithName: @"Helvetica" size: 16];
> NSString* text = [[NSString alloc] initWithString: @"Hello"];
>
> NSDictionary* fontAttrs = [[NSDictionary dictionaryWithObjects:
> [NSArray arrayWithObjects:  font, nil]
>
>   forKeys:                          [NSArray arrayWithObjects:
> NSFontAttributeName, nil]] copy]
>
> NSSize extent = [text sizeWithAttributes: fontAttrs];
>
>
> I'm attempting to perform the same with OpenMCL:
>
> ;;
> ;;  Some AD3D stuff.  A Font-Spec is a list:  (list "font-name" font-
> size :font-style)
> ;;       e.g., ("helvetica" 16 :plain)
> ;;
> (defun STRING-WIDTH (String &optional Font-Spec)
>   "Returns the width in pixels of String, as if it were displayed in
> the font,
>    size, and style of font-spec."
>   (if (null font-spec)
>       (format t "No spec!")
>       ;; NSDictionary* attributes = [NSDictionary
> dictionaryWithObjectsAndKeys: font, nil];
>       ;; NSString foo = String;
>       ;; Size = foo :sizeWithAttributes attributes
>       (let ((size (float (second font-spec))))
>         (with-cstrs ((c-font-name (first font-spec))
>                      (c-string    String))
>           (with-autorelease-pool
>              (let* ((tempname   (ccl::send (@class ns-
> string) :string-with-c-string c-font-name))
>                       (fontname   (ccl::send tempname 'capitalized-
> string))
>                       (nsstring   (ccl::send (@class ns-
> string) :string-with-c-string c-string))
>                       (font       (ccl::send (@class ns-
> font)   :font-with-name fontname :size size)))
>                (ccl::%stack-block ((paramptrs (ash 1 target::word-
> shift)))
>                   (setf (ccl::%get-ptr paramptrs 0) font)
>                   (let ((val-array (ccl::send (ccl::send (@class
> "NSArray") 'alloc) :init-with-objects paramptrs :count 1)))
>                        (rlet ((glyph-size :<NSS>ize))
>                          (let ((dict (ccl::send (@class ns-
> dictionary) :dictionary-with-objects-and-keys val-array)))
>                             (ccl::send/stret glyph-size
> nsstring :size-with-attributes dict)
>                             (let ((width (ccl::pref glyph-
> size :<NSS>ize.width)))
>                                width)))))))))))
>
>
> This crashes horribly:
>
> ? (string-width "Hello" (list "Helvetica" 16 :plain))
> Unhandled exception 11 at 0xfffeff18, context->regs at #xf0135478
> Read operation to unmapped address 0xbad00020
> In foreign code at address 0xfffeff18
> ? for help
> [26533] OpenMCL kernel debugger: b
> current thread: tcr = 0x301ab0, native thread ID = 0x3603, interrupts
> enabled
>
>
> (#xf0135960) #x90A411D4 : _objc_msgSend + 244
> (#xf0135a00) #x92BCCCA4 : +[NSDictionary
> dictionaryWithObjectsAndKeys:] + 480
> (#xf0135ac0) #x00006654 : _SPpoweropen_ffcall + 204
> (#xF0135B00) #x08CD4C2C : #<Function STRING-WIDTH #x08cd4f16> + 3632
> (#xf0135b10) #x00000000 : (null) + 0
> (#xF0135B60) #x08CD4C54 : #<Function STRING-WIDTH #x08cd4f16> + 3672
> (#xF0135B70) #x08CD4A54 : #<Function STRING-WIDTH #x08cd4f16> + 3160
> (#xF0135B80) #x08CD3F20 : #<Function STRING-WIDTH #x08cd4f16> + 292
> (#xF0135B90) #x000060F8 : (subprimitive _ret1valn)
> (#xF0135BA0) #x0426179C : #<Function CALL-CHECK-REGS #x081c97ae> + 72
> (#xF0135BB0) #x000060F8 : (subprimitive _ret1valn)
>
> I'm clearly passing something non-kosher to the cocoa API, but I'm
> not sure how to get it to do what I want.
>
> Does anyone have a better alternative, or can see anything obvious
> I'm doing wrong?
>
> Thanks,
>
> - -Brent
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.6 (Darwin)
>
> iD8DBQFGAL3+zGDdrzfvUpURAph+AKCDzEPDY4Z9oVKZgqgO+w/3YQgyTACfUtLc
> WkoaR1oNAVLFxMa6+SKneWM=
> =tdqp
> -----END PGP SIGNATURE-----
> _______________________________________________
> Openmcl-devel mailing list
> Openmcl-devel at clozure.com
> http://clozure.com/mailman/listinfo/openmcl-devel
>
>



More information about the Openmcl-devel mailing list