Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pointer to pointer support #244

Merged
merged 1 commit into from
Jan 29, 2024

Conversation

programmingkidx
Copy link
Contributor

@programmingkidx programmingkidx commented Jan 15, 2024

Pointer to pointer types are commonly used to provide a method a way to communicate information to calling methods. A popular example of this is to use NSError to communicate any error information. This pull request adds the ability for DarwinKit to correctly use pointer to pointer types so they can work.

This change uses a new rule where if a parameter is a pointer to a pointer type (e.g. NSError **error), the user is to use the Go wrapper for that type and wrap the variable with unsafe.Pointer(&theVariable).

So for a parameter like NSError **err, the Go code would declare an Error instance and then use that instance in the method like this: unsafe.Pointer(&err)

@programmingkidx
Copy link
Contributor Author

To test this pull request I made several programs available.

This program loads a nib file and and displays it.
image

Directions:

  1. Download the attached zip file and extract its nib file by double clicking on the file.
    MainMenu.nib.zip
  2. Copy and paste the program below into a file called main.go.
  3. Run the program by using this command: go run main.go.
// File: loadnib.go
// Date: 11/29/23
// Description: Uses a NIB file to display the interface
// Run directions: go run main.go

package main

import (
	"fmt"
	"os"
	"github.com/progrium/macdriver/macos/appkit"
	f "github.com/progrium/macdriver/macos/foundation"
	"github.com/progrium/macdriver/objc"
	"github.com/progrium/macdriver/helper/action"
	"unsafe"
)

var textField appkit.TextField

func main() {
	// Setup the application
	app := appkit.Application_SharedApplication()
	app.SetActivationPolicy(appkit.ApplicationActivationPolicyRegular)
	app.ActivateIgnoringOtherApps(true)
		
	// Get the NIB file's data
	godata, err := os.ReadFile("MainMenu.nib")
	if err != nil {
		fmt.Println("Failed to load nib file:", err)
		return
	}
	myNib := appkit.NewNibWithNibDataBundle(godata, nil)
	
	var myObjects = f.Array_Array()
	status := myNib.InstantiateWithOwnerTopLevelObjects(nil, unsafe.Pointer(&myObjects))
	if status == false {
		fmt.Println("Error: failed to instantiate nib file")
		return
	}

	// find the window and display it
	foundWindow := false
	var i uint
	for i = 0; i < myObjects.Count(); i++ {
		theObject := myObjects.ObjectAtIndex(i)
		if theObject.IsKindOfClass(objc.GetClass("NSWindow")) {
			mainWindow := appkit.WindowFrom(theObject.Ptr())
			mainWindow.OrderFront(nil)
			foundWindow = true
			aButton := mainWindow.ContentView().ViewWithTag(1)
			action.Set(appkit.ButtonFrom(aButton.Ptr()), doButton)
			
			textFieldView := mainWindow.ContentView().ViewWithTag(2)
			textField = appkit.TextFieldFrom(textFieldView.Ptr())
			break
		}
	}
	
	if foundWindow == false {
		fmt.Println("Error: Failed to find window in nib file")
		return
	}
	app.Run()
}

// called when the user pushes the button
func doButton(sender objc.Object) {
	fmt.Println("I'M ALIVE!!!")
	textField.SetStringValue("OUCH!!!")
}



This program test the use of (NS)Error.
It will tell you if its tests succeed or fail.
Directions:

  1. Create a new file called main.go.
  2. Copy and paste the code below into the file.
  3. Run the program like this: go run main.go

The output should look like this:
Testing with problem string...pass
Testing with good string...pass

// Description: test generating a NSError using the XMLDocument class

package main

import "fmt"
import f "github.com/progrium/macdriver/macos/foundation"
import "unsafe"


func main() {
	testWithProblem()
	testWithoutProblem()
}

// Use a bad string to try to make a XML document. It should fail to create one.
func testWithProblem() {
	inputStr := "BUG<root><element>Some text</element></root>"
	options := f.XMLNodePreserveWhitespace
	var myError f.Error
	f.NewXMLDocumentWithXMLStringOptionsError(inputStr, options, unsafe.Pointer(&myError))
	if myError.IsNil() == false {
		fmt.Println("Testing with problem string...pass")
		//fmt.Printf("Error code: %d\t domain:%s\t  userInfo:%s\n", myError.Code, myError.Domain, myError.UserInfo)
	} else {
		fmt.Println("Testing with problem string...fail")
	}
}

// Use a good string to try to make a XML document. It should succeed
func testWithoutProblem() {
	inputStr := "<root><element>Some text</element></root>"
	options := f.XMLNodePreserveWhitespace
	var myError f.Error
	f.NewXMLDocumentWithXMLStringOptionsError(inputStr, options, unsafe.Pointer(&myError))
	if myError.IsNil() == true {
		fmt.Println("Testing with good string...pass")
	} else {
		fmt.Println("Testing with good string...fail")
	}
}

@progrium
Copy link
Owner

I think this could be a good general solution. @tmc thoughts?

@programmingkidx
Copy link
Contributor Author

@tmc Any questions or comments?

Copy link
Collaborator

@tmc tmc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@progrium progrium merged commit 6a98f82 into progrium:main Jan 29, 2024
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants