Added (untested; VM issues) code to handle Mac OS X Quit Dock menu items and other related stuff that may happen in the future. Will drop the TODO after I can test it.

This commit is contained in:
Pietro Gagliardi 2014-04-06 23:33:27 -04:00
parent af770340c9
commit f7817f6987
7 changed files with 65 additions and 6 deletions

View File

@ -20,6 +20,7 @@ though this is not always the case.
#include <AppKit/NSGraphics.h>
#include <AppKit/NSBitmapImageRep.h>
#include <AppKit/NSCell.h>
#include <AppKit/NSApplication.h>
/* used by listbox_darwin.go; requires NSString */
id *_NSObservedObjectKey = (id *) (&NSObservedObjectKey);
@ -241,7 +242,8 @@ static void __areaView_drawRect(id self, SEL sel, NSRect r)
void *_areaView_drawRect = (void *) __areaView_drawRect;
/* the only objective-c feature you'll see here
/*
this and one below it are the only objective-c feature you'll see here
unfortunately NSRect both varies across architectures and is passed as just a structure, so its encoding has to be computed at compile time
because @encode() is NOT A LITERAL, we're going to just stick it all the way back in objc_darwin.go
@ -327,3 +329,19 @@ void objc_setFont(id what, unsigned int csize)
objc_msgSend(what, s_setFont,
objc_msgSend(c_NSFont, s_systemFontOfSize, size));
}
/*
-[NSApplicationDelegate applicationShouldTerminate] used to return a BOOL, but now returns a NSApplicationTerminateReply, which is a NSUInteger; hence, here.
*/
extern void appDelegate_applicationShouldTerminate();
static NSApplicationTerminateReply __appDelegate_applicationShouldTerminate(id self, SEL sel)
{
appDelegate_applicationShouldTerminate();
return NSTerminateCancel; // don't quit
}
void *_appDelegate_applicationShouldTerminate = (void *) __appDelegate_applicationShouldTerminate;
char *encodedTerminateReply = @encode(NSApplicationTerminateReply);

View File

@ -12,6 +12,7 @@ This creates a class goAppDelegate that will be used as the delegate for /everyt
- handles window close events (windowShouldClose:)
- handles window resize events (windowDidResize:)
- handles button click events (buttonClicked:)
- handles the application-global Quit event (such as from the Dock) (applicationShouldTerminate)
*/
// #cgo LDFLAGS: -lobjc -framework Foundation -framework AppKit
@ -45,6 +46,8 @@ var appDelegateSels = []selector{
"handling window resize events"},
selector{"buttonClicked:", uintptr(C.appDelegate_buttonClicked), sel_bool_id,
"handling button clicks"},
selector{"applicationShouldTerminate", uintptr(C._appDelegate_applicationShouldTerminate), sel_terminatereply,
"handling Quit menu items (such as from the Dock)/the AppQuit channel"},
}
func mkAppDelegate() error {
@ -94,3 +97,12 @@ func appDelegate_buttonClicked(self C.id, sel C.SEL, button C.id) {
sysData := getSysData(button)
sysData.signal()
}
//export appDelegate_applicationShouldTerminate
func appDelegate_applicationShouldTerminate() {
// asynchronous so as to return control to the event loop
go func() {
AppQuit <- struct{}{}
}()
// xxx in bleh_darwin.m tells Cocoa not to quit
}

3
doc.go
View File

@ -20,6 +20,7 @@ Here is a simple, complete program that asks the user for their name and greets
func myMain() {
w := ui.NewWindow("Hello", 400, 100)
ui.AppQuit = w.Closing // treat quitting the application like closing the main window
nameField := ui.NewLineEdit("Enter Your Name Here")
button := ui.NewButton("Click Here For a Greeting")
err := w.Open(ui.NewVerticalStack(nameField, button))
@ -29,7 +30,7 @@ Here is a simple, complete program that asks the user for their name and greets
for {
select {
case <-w.Closing: // user tries to close the window
case <-w.Closing: // user tries to close the window or quit the program
return
case <-button.Clicked: // user clicked the button
ui.MsgBox("Hello, " + nameField.Text() + "!", "")

11
init.go
View File

@ -14,3 +14,14 @@ package ui
func Go(main func()) error {
return ui(main)
}
// AppQuit is pulsed when the user decides to quit the program if their operating system provides a facility for quitting an entire application, rather than merely close all windows (for instance, Mac OS X via the Dock icon).
// You should assign one of your Windows's Closing to this variable so the user choosing to quit the application is treated the same as closing that window.
// If you do not respond to this signal, nothing will happen.
// Do not merely check this channel alone; it is not guaranteed to be pulsed on all systems or in all conditions.
var AppQuit chan struct{}
func init() {
// don't expose this in the documentation
AppQuit = newEvent()
}

View File

@ -71,14 +71,16 @@ const (
sel_bool_id
sel_bool
sel_void_rect
sel_terminatereply
nitypes
)
var itypes = [nitypes][]C.char{
sel_void_id: []C.char{'v', '@', ':', '@', 0},
sel_bool_id: []C.char{'c', '@', ':', '@', 0},
sel_bool: []C.char{'c', '@', ':', 0},
sel_void_rect: nil, // see init() below
sel_void_id: []C.char{'v', '@', ':', '@', 0},
sel_bool_id: []C.char{'c', '@', ':', '@', 0},
sel_bool: []C.char{'c', '@', ':', 0},
sel_void_rect: nil, // see init() below
sel_terminatereply: nil,
}
func init() {
@ -91,6 +93,14 @@ func init() {
}
x = append(x, 0)
itypes[sel_void_rect] = x
x = make([]C.char, 0, 256) // more than enough
y = C.GoString(C.encodedTerminateReply)
for _, b := range y {
x = append(x, C.char(b))
}
x = append(x, '@', ':', 0)
itypes[sel_terminatereply] = x
}
func makeClass(name string, super C.id, sels []selector, desc string) (id C.id, err error) {

View File

@ -117,8 +117,12 @@ extern struct xpoint getTranslatedEventPoint(id, id);
/* for objc_darwin.go */
extern char *encodedNSRect;
extern char *encodedTerminateReply;
/* for sysdata_darwin.go */
extern void objc_setFont(id, unsigned int);
/* for delegate_darwin.go */
extern void *_appDelegate_applicationShouldTerminate;
#endif

View File

@ -282,6 +282,9 @@ _=curtime
case <-w.Closing:
println("window closed event received")
break mainloop
case <-AppQuit:
println("application quit event received")
break mainloop
case <-b.Clicked:
w.SetTitle(fmt.Sprintf("%v | %s | %s | %s | %s",
c.Checked(),