[Qt-interest] [OS X] Auto-hide toolbar when going "native fullscreen" on "Lion"?

Till Oliver Knoll till.oliver.knoll at gmail.com
Fri Aug 5 11:03:28 CEST 2011


2011/8/4 John Weeks <john at wavemetrics.com>:
>
> On Aug 4, 2011, at 1:51 AM, Till Oliver Knoll wrote:
>
> > This off course replaces the existing window delegate ...
>
> Can't you get the delegate that's already installed and call it as part of
> your replacement delegate?

Yes, I /can/ get the current window delegate. But first, the existing
QCocoaWindowDelegate (of Qt 4.7.x) does not implement the
NSWindowDelegate "protocol" method
"window:willUseFullScreenPresentationOptions:", because that one was
only added in OS X 10.7 (as part of the new "Lion fullscreen API").

Second and most important, there is no "setter" in the delegate where
I could set my desired "fullscreen presentation flags":

  http://developer.apple.com/library/mac/#documentation/cocoa/reference/NSWindowDelegate_Protocol/Reference/Reference.html

The thing to remember is that "delegates" are like a "callback": the
actual object - the NSWindow in this case - will check whether a
delegate is installed (previously "set") and if so, whenever something
happens, such as going fullscreen, it will "send a message" such as
"window:willUseFullScreenPresentationOptions:" to that delegate, which
usually implements a "protocol".


There are a few concepts in Objective-C to understand first: "sending
a message" is like "calling a function/method", the funny [] bracket
thing:

  [receiver message:firstArgumentValue
someMoreNamedArg:secondArgumentValue aThirdArg:value]

The clever thing: unlike a method such a "message" (the "method" such
as "window:willUseFullScreenPresentationOptions:") does not HAVE to
exist in the receiver! "Messages" are dynamically dispatched, and if
the receiver has no clue how to handle it (just like the
QCocoaWindowDelegate has no clue how to handle
"window:willUseFullScreenPresentationOptions:") the message is simply
ignored and the sender (NSWindow which is about to go fullscreen in
this case) simply takes its default "presentation flags").

As a matter of fact the QCocoaWindowDelegate implements the "Protocol
(aka "interface" - note: "Interfaces" in Objective-C really mean
"classes" in "our language"). Whereas some methods in a Protocol might
be mandatory to implement, some others may be "you can implement them
if you wish - but you don't have to!".
"window:willUseFullScreenPresentationOptions:" is such a
"non-mandatory method".

Think of "method calls" in Objective-C a little bit in terms of Qt
signals/slots: if you try to connect a signal to a non-existing slot
you simply get a more or less graceful debug message saying "unknown
slot!". And when you then emit ("call") this signal nothing bad
happens (no "unresolved symbol" or "unimplemented" exception which
causes your app to terminate), the signal just does nothing.

The following helped a lot to get into Objective-C quickly:

  http://cocoadevcentral.com/d/learn_objectivec/


But coming back to the original question: so what happens when you
"toggleFullScreen:" on the NSWindow it will first ask its
NSWindowDelegate for "presentation flags", such as the desired "should
the toolbar be visible" and respect these flags accordingly - if the
delegate "responds" to that message. So far so good.


But how do we make the -private!- QCocoaWindowDelegate return the
desired presentation flags?


There is another cool feature in Objective-C: "Categories" -
Categories allow you to extend an existing Interface (aka class) by
adding new methods or overwritting existing ones - but without
subclassing! And the best: this works if you don't even have the
sourcecode of the original class! You simply create a new Category:

In this example we create a new Category "fullscreen":

// in my own code:
@interface QCocoaWindowDelegate (fullscreen)

// we add the desired method and implement it ourselves later on
- (NSApplicationPresentationOptions)window:(NSWindow *)window
willUseFullScreenPresentationOptions
(NSApplicationPresentationOptions)proposedOptions

@end


So in theory the existing QCocoaWindowDelegate would now also
understand the message "window:willUseFullScreenPresentationOptions:"
and my own implementation would be executed. In practise however I get
a silly linker-error saying that the symbol
"_obj_c_qcocoawindowdelegate cannot be found" (the exact message I
don't know right now). So apparently that private class is not
exported from the QtGui framework (that's where I guess it should be
in).

I must add that I am using the Qt Cocoa binary distribution which did
not even have the private header where QCocoaWindowDelegate is
declared, so I created this private header myself. <wishful thinking>I
might have better luck if I compile the latest Qt 4.7.x
myself.</wishful thinking>


I stumbled across "category linker issues":

  http://www.dribin.org/dave/blog/archives/2006/03/13/static_objc_lib/

but they seem to be related to static libraries only (and could be
resolved by providing the -ObjC linker flag - maybe I'll give that one
a shot anyway this evening).


A completely different approach I was thinking of is to somehow
connect to "resize events" of my QMainWindow and whenever I detect
that the window has gone "fullscreen" I toggle the appropriate
visibility flags myself, with the normal QWidget::setVisible() call...


Thanks, Oliver



More information about the Qt-interest-old mailing list