Removed uitask and made the Window creation functions only callable from the main thread. This si the first part in the real major change, which bans all concurrent use of the API and provides a Post() function for communication. I don't like this, but it's the only way. Untested.

This commit is contained in:
Pietro Gagliardi 2014-07-03 10:02:27 -04:00
parent 8a81650b3d
commit 9eb9aa82c0
8 changed files with 2 additions and 152 deletions

View File

@ -4,7 +4,6 @@ package ui
/*
This creates a class goAppDelegate that will be used as the delegate for /everything/. Specifically, it:
- runs uitask requests (uitask:)
- handles window close events (windowShouldClose:)
- handles window resize events (windowDidResize:)
- handles button click events (buttonClicked:)

View File

@ -56,15 +56,6 @@ extern NSRect dummyRect;
@implementation appDelegate
// these are the uitask actions
- (void)createWindow:(NSValue *)fp
{
uitask_createWindow([fp pointerValue]);
}
// these are the other delegate functions
- (BOOL)windowShouldClose:(id)win
{
return appDelegate_windowShouldClose(win);
@ -115,9 +106,6 @@ id windowGetContentView(id window)
return [((NSWindow *) window) contentView];
}
// these are for douitask() but are here because @selector() is not a constant expression
SEL createWindow;
BOOL initCocoa(id appDelegate)
{
// on 10.6 the -[NSApplication setDelegate:] method complains if we don't have one
@ -131,26 +119,10 @@ BOOL initCocoa(id appDelegate)
return NO;
[NSApp activateIgnoringOtherApps:YES]; // TODO actually do C.NO here? Russ Cox does YES in his devdraw; the docs say the Finder does NO
[NSApp setDelegate:appDelegate];
// uitask selectors
createWindow = @selector(createWindow:);
[pool release];
return YES;
}
void douitask(id appDelegate, SEL sel, void *p)
{
NSAutoreleasePool *pool;
NSValue *fp;
// we need to make an NSAutoreleasePool, otherwise we get leak warnings on stderr
pool = [NSAutoreleasePool new];
fp = [NSValue valueWithPointer:p];
[appDelegate performSelectorOnMainThread:sel
withObject:fp
waitUntilDone:YES]; // wait so we can properly drain the autorelease pool; on other platforms we wind up waiting anyway (since the main thread can only handle one thing at a time) so
[pool release];
}
void breakMainLoop(void)
{
NSEvent *e;

View File

@ -63,8 +63,6 @@ extern uintptr_t keyCode(id);
extern id makeAppDelegate(void);
extern id windowGetContentView(id);
extern BOOL initCocoa(id);
extern SEL createWindow;
extern void douitask(id, SEL, void *);
extern void breakMainLoop(void);
extern void cocoaMainLoop(void);

View File

@ -27,23 +27,7 @@ func Go() error {
return nil
}
// Ready is pulsed when Go() is ready to begin accepting requests to the safe methods.
// Go() will wait for something to receive on Ready, then Ready will be closed.
var Ready = make(chan struct{})
// Stop should be pulsed when you are ready for Go() to return.
// Pulsing Stop will cause Go() to return immediately; the programmer is responsible for cleaning up (for instance, hiding open Windows) beforehand.
// Do not pulse Stop more than once.
var Stop = make(chan struct{})
// uitask is an object of a type implemented by each uitask_***.go that does everything that needs to be communicated to the main thread.
type _uitask struct{}
var uitask = _uitask{}
// and the required methods are:
var xuitask interface {
// creates a window
// TODO whether this waits for the window creation to finish is implementation defined?
createWindow(*Window, Control, bool)
} = uitask
// compilation will fail if uitask doesn't have all these methods

View File

@ -13,29 +13,6 @@ import (
// #include "objc_darwin.h"
import "C"
// the performSelectorOnMainThread: in our uitask functions is told to wait until the action is done before it returns
// so we're fine keeping this on the Go side since the GC won't collect it from under us
type uitaskParams struct {
window *Window // createWindow
control Control // createWindow
show bool // createWindow
}
//export uitask_createWindow
func uitask_createWindow(data unsafe.Pointer) {
uc := (*uitaskParams)(data)
uc.window.create(uc.control, uc.show)
}
func (_uitask) createWindow(w *Window, c Control, s bool) {
uc := &uitaskParams{
window: w,
control: c,
show: s,
}
C.douitask(appDelegate, C.createWindow, unsafe.Pointer(uc))
}
func uiinit() error {
err := initCocoa()
if err != nil {
@ -63,9 +40,3 @@ func initCocoa() (err error) {
}
return nil
}
//export appDelegate_uitask
func appDelegate_uitask(p unsafe.Pointer) {
f := (*func())(unsafe.Pointer(p))
(*f)()
}

View File

@ -11,23 +11,6 @@ import (
// #cgo pkg-config: gtk+-3.0
// #include "gtk_unix.h"
// /* unfortunately, there's no way to differentiate between the main thread and other threads; in fact, doing what we do on other platforms is discouraged by the GTK+ devs!
// but I can't avoid this any other way... so we have structures defined on the C side to skirt the garbage collector */
// struct uitaskParams {
// void *window; /* createWindow */
// void *control; /* createWindow */
// gboolean show; /* createWindow */
// };
// static struct uitaskParams *mkParams(void)
// {
// /* g_malloc0() will abort on not enough memory */
// return (struct uitaskParams *) g_malloc0(sizeof (struct uitaskParams));
// }
// static void freeParams(struct uitaskParams *p)
// {
// g_free(p);
// }
// extern gboolean our_createWindow_callback(gpointer);
// /* this is called when we're done */
// static inline gboolean our_quit_callback(gpointer data)
// {
@ -41,29 +24,6 @@ import (
// }
import "C"
//export our_createWindow_callback
func our_createWindow_callback(what C.gpointer) C.gboolean {
uc := (*C.struct_uitaskParams)(unsafe.Pointer(what))
w := (*Window)(unsafe.Pointer(uc.window))
c := *(*Control)(unsafe.Pointer(uc.control))
s := fromgbool(uc.show)
w.create(c, s)
C.freeParams(uc)
return C.FALSE // remove this idle function; we're finished
}
func (_uitask) createWindow(w *Window, c Control, s bool) {
uc := C.mkParams()
uc.window = unsafe.Pointer(w)
uc.control = unsafe.Pointer(&c)
uc.show = togbool(s)
gdk_threads_add_idle(C.our_createWindow_callback, unsafe.Pointer(uc))
}
func gdk_threads_add_idle(f unsafe.Pointer, what unsafe.Pointer) {
C.gdk_threads_add_idle(C.GCallback(f), C.gpointer(what))
}
func uiinit() error {
err := gtk_init()
if err != nil {

View File

@ -29,32 +29,8 @@ const (
msgQuit = _WM_APP + iota + 1 // + 1 just to be safe
msgSetAreaSize
msgRepaintAll
msgCreateWindow
)
type uitaskParams struct {
window *Window // createWindow
control Control // createWindow
show bool // createWindow
}
// SendMessage() won't return unti lthe deed is done, even if the deed is on another thread
// SendMessage() does a thread switch if necessary
// this also means we don't have to worry about the uitaskParams object being garbage collected
func (_uitask) createWindow(w *Window, c Control, s bool) {
uc := &uitaskParams{
window: w,
control: c,
show: s,
}
_sendMessage.Call(
uintptr(msghwnd),
msgCreateWindow,
uintptr(0),
uintptr(unsafe.Pointer(uc)))
}
func uiinit() error {
err := doWindowsInit()
if err != nil {
@ -182,10 +158,6 @@ func messageHandlerWndProc(hwnd _HWND, uMsg uint32, wParam _WPARAM, lParam _LPAR
// does not return a value according to MSDN
_postQuitMessage.Call(0)
return 0
case msgCreateWindow:
uc := (*uitaskParams)(unsafe.Pointer(lParam))
uc.window.create(uc.control, uc.show)
return 0
}
return defWindowProc(hwnd, uMsg, wParam, lParam)
}

View File

@ -71,15 +71,12 @@ func (w *Window) SetSpaced(spaced bool) {
// Open creates the Window with Create and then shows the Window with Show. As with Create, you cannot call Open more than once per window.
func (w *Window) Open(control Control) {
uitask.createWindow(w, control, true)
w.Create(control)
w.Show()
}
// Create creates the Window, setting its control to the given control. It does not show the window. This can only be called once per window, and finalizes all initialization of the control.
func (w *Window) Create(control Control) {
uitask.createWindow(w, control, false)
}
func (w *Window) create(control Control, show bool) {
if w.created {
panic("window already open")
}
@ -107,9 +104,6 @@ func (w *Window) create(control Control, show bool) {
}
w.sysData.setText(w.initTitle)
w.created = true
if show {
w.Show()
}
}
// Show shows the window.