Cocoa Declare - How to?

Hi everyone,

I found this nice page NSWindow title bar and toolbar showcase and want to set Windows Style Mask as described below:

Transparent title bar

If you want to hide the title bar but still need the window buttons (such as close button, minimize button and screen button), you can set the titlebar to transparent:

window.titlebarAppearsTransparent = true

You may want to hide the title and use full size content view to get the following style.

window.titlebarAppearsTransparent = true window.titleVisibility = .Hidden window.styleMask |= NSFullSizeContentViewWindowMask

How can I do this with Xojo? I found this on Apple Developer Network . I have no experiences using declares.

I found the solution. Add these to the Windows Open-Event:

[code]#If TargetCocoa Then

// 10.10+ only.
Declare Function NSClassFromString Lib “Foundation” (aClassName As CFStringRef) As Ptr

If NSClassFromString( “NSVisualEffectView” ) <> Nil then

Const AppKit = "AppKit"
Const NSWindowTitleHidden = 1
Const NSFullSizeContentViewWindowMask = 32768

Declare Sub titleVisibility Lib AppKit Selector "setTitleVisibility:" (handle As Integer, value As Integer)
titleVisibility(Me.Handle, NSWindowTitleHidden)

Declare Sub setStyleMask Lib AppKit Selector "setStyleMask:" (handle As Integer, value As Integer)
Declare Function styleMask Lib AppKit Selector "styleMask" (handle As Integer) As Integer
setStyleMAsk(Me.Handle, styleMask(Me.Handle) + NSFullSizeContentViewWindowMask)

Declare Sub titlebarAppearsTransparent Lib AppKit Selector "setTitlebarAppearsTransparent:" (handle As Integer, value As Boolean)
titleBarAppearsTransparent(Me.Handle, True)

End If

#EndIf[/code]

I used the code from the post above to get a transparent title bar for my little note-taking app. To reduce the code I just used the following, “hiding” the title bar just by setting the window title to an empty string:

[code]#If TargetCocoa Then
Declare Function NSClassFromString Lib “Foundation” (aClassName As CFStringRef) As Ptr
If NSClassFromString(“NSVisualEffectView”) <> Nil Then
Const AppKit = “AppKit”
Const NSFullSizeContentViewWindowMask = 32768

Declare Sub setStyleMask Lib AppKit Selector "setStyleMask:" (handle As Integer, value As Integer)
Declare Function styleMask Lib AppKit Selector "styleMask" (handle As Integer) As Integer
setStyleMask(Me.Handle, styleMask(Me.Handle) + NSFullSizeContentViewWindowMask)

Declare Sub titlebarAppearsTransparent Lib AppKit Selector "setTitlebarAppearsTransparent:" (handle As Integer, value As Boolean)
titleBarAppearsTransparent(Me.Handle, True)

End If
#EndIf[/code]

In my app there is a listbox with my notes (stored in an SQLite database), and when I select a note, the title and content of the note are fetched from the database and filled into the TextField (title) and TextArea (content):

Now there is a very odd behaviour of my app: Everything works as expected, except that sometimes after selecting a note there is about a second delay, before the TextArea gets filled (the TextField is always filled instantly). I could pin it down to this: When not using the declares from above, everything works quickly and smoothly (instant filling of TextField and TextArea); when using the declares, there are two kinds of behaviour: If the blinking cursor is invisible, the TextArea also gets filled instantly, but if (and only if) the cursor is visible while selecting a note, the delay will occur.
But where is the connection between the title bar declares, my TextArea and the blinking cursor? (And how could I fix this problem? I’d like to keep this window design for my app…)

Run in the debugger and profile the code and see if anything pops up in there…

[quote=381637:@Jens Knipp]I used the code from the post above to get a transparent title bar for my little note-taking app. To reduce the code I just used the following, “hiding” the title bar just by setting the window title to an empty string:

[code]#If TargetCocoa Then
Declare Function NSClassFromString Lib “Foundation” (aClassName As CFStringRef) As Ptr
If NSClassFromString(“NSVisualEffectView”) <> Nil Then
Const AppKit = “AppKit”
Const NSFullSizeContentViewWindowMask = 32768

Declare Sub setStyleMask Lib AppKit Selector "setStyleMask:" (handle As Integer, value As Integer)
Declare Function styleMask Lib AppKit Selector "styleMask" (handle As Integer) As Integer
setStyleMask(Me.Handle, styleMask(Me.Handle) + NSFullSizeContentViewWindowMask)

Declare Sub titlebarAppearsTransparent Lib AppKit Selector "setTitlebarAppearsTransparent:" (handle As Integer, value As Boolean)
titleBarAppearsTransparent(Me.Handle, True)

End If
#EndIf[/code]

In my app there is a listbox with my notes (stored in an SQLite database), and when I select a note, the title and content of the note are fetched from the database and filled into the TextField (title) and TextArea (content):

Now there is a very odd behaviour of my app: Everything works as expected, except that sometimes after selecting a note there is about a second delay, before the TextArea gets filled (the TextField is always filled instantly). I could pin it down to this: When not using the declares from above, everything works quickly and smoothly (instant filling of TextField and TextArea); when using the declares, there are two kinds of behaviour: If the blinking cursor is invisible, the TextArea also gets filled instantly, but if (and only if) the cursor is visible while selecting a note, the delay will occur.
But where is the connection between the title bar declares, my TextArea and the blinking cursor? (And how could I fix this problem? I’d like to keep this window design for my app…)[/quote]
It sounds like the OS or our framework is waiting to redraw the TextArea until the control requests a redraw for itself.

It could be a variation of the bug I logged. If I performed a refresh when opening a window, any text areas that were updated before the window appeared failed to show their content.

<https://xojo.com/issue/51553>

@shao sean: Unfortunately I don’t know what you want me to do exactly after “Run in the debugger” …

I also thought of a bug because I cannot see what this behaviour might be good for.
In the meantime I added two more events to my listbox: MouseEnter removes the focus from the TextArea, and MouseExit sets the focus back to the TextArea. Not the most satisfying workaround, but at least the mentionend problem is avoided.

This line auto enables layer-backed views; which I filed as a bug with Apple, but it never got any traction.

So you may need to force the TextArea to refresh. There’s a couple of things try.

  1. There’s a Xojo blog article on speeding up TextArea editing, go find it and read it as I think this is probably your best shot.
  2. Hide the TextArea, set the text and then make the TextArea visible again.
  3. Refresh the TextArea after you’ve set the text.
  4. Refresh the backing CALayer.
declare sub NSViewUpdateLayer lib "Cocoa" selector "updateLayer" ( NSViewInstance as integer )

*Please note that I just typed this in, it should work, but if not, should be enough to figure out what is the right function.

http://developer.xojo.com/userguide/code-profiler

Before you debug, you turn on code profile, run your code in debug mode (run it just until after the issue you mentioned above) and then quit your debug session… Look at the profiler information (it shows up in your project window) and see if there is any information in there, but personal I think what Greg and Sam is saying is probably better help at this point…

@shao sean: Thanks for you explanation; I didn’t know about that until now! :slight_smile:
I ran the app in debug mode, but I don’t see any suspicious entry in the profiler information. Except from the Window1.Open event (16ms) there is nothing, that takes more than 3 ms to execute, although the delay in the TextArea is visible.

[quote=381823:@Sam Rowlands]2. Hide the TextArea, set the text and then make the TextArea visible again.
3. Refresh the TextArea after you’ve set the text.[/quote]
3. doesn’t work, neither Refresh nor Invalidate.
2. has no effect either, but disabling the TextArea before setting the text and enabling it again seems to work in a few tests I just ran