Simple utility to unhide mouse cursor in objective c console app - objective-c

I'm trying to create a simple console app to unhide the cursor because a program I use has a bug and hides the cursor intermittently (Would rather write a quick util than wait for the bug to be fixed). I have added the AppKit framework and written the following simple console app (main.m):
#import <Foundation/Foundation.h>
#import <AppKit/NSCursor.h>
int main(int argc, const char * argv[])
{
#autoreleasepool {
[NSCursor unhide];
}
return 0;
}
but I get an EXC_BAD_ACCESS at the [NSCursor unhide] line. Any idea what I'm doing wrong?
I'm running this on Lion with XCode 4.3.2
I am also open to doing this with AppleScript, but I haven't been able to accomplish it there either.
Thanks!

What you're trying to do isn't going to work. Cursor objects are managed and owned by each application. You can't affect another application's cursor (without code injection).
You get an EXC_BAD_ACCESS because your program here doesn't actually have a cursor. One would be created during the usual GUI app start-up process, i.e., in NSApplicationMain(), if you had created a "Cocoa Application", but you would still only be able to affect your own application's cursor.
AppleScript seems like it would have a better chance of success, since it lets you execute some code that directly affects other apps, but I'm not at all sure that it has functionality to manage the cursor like this -- it seems a little too low-level for AS.

Related

Encapsulating and spawning another application and injecting parameters

My issue is I have a child .app that I'd like to run after injecting some parameters. What want to do is run the app as the parent app (launching it sync and propagate focus/activation events to the child app).
The goal for me is to create an 'parent app' that launches another app, for example OtherApp.app. It should appear as if 'parent app' is OtherApp.app (i.e. not show up as a seperate application in the dock but the windows of OtherApp.app should be contained by 'parent app'). The reason I want to do this is so I can pass some initialization variables to OtherApp.app without modifying the .app itself.
Approaches I have taken
First approach is the simplest. Simply using system(#"VAR=VALUE /Applications/OtherApp.app"). However the issue with this is that the 'parent app' will instantly exit and OtherApp.app will open as a seperate application in the Dock.
Second approach: I've tried to do is use NSWorkspace with NSRunningApplication however that is not synchronous, the issue with this is that the 'parent app' will again instantly die:
#import <Cocoa/Cocoa.h>
int main(int argc, const char * argv[]) {
NSRunningApplication* childApp = [[NSWorkspace sharedWorkspace]
openURL:[NSURL fileURLWithPath:#"/Applications/OtherApp.app"]
options:NSWorkspaceLaunchDefault|NSWorkspaceLaunchWithoutAddingToRecents
configuration:#{
NSWorkspaceLaunchConfigurationEnvironment: #{
#"VAR": #"VALUE"
}
} error:NULL];
}
Third approach is using Launch Services. However this is what my question is asking— I can't find any undeprecated API that lets me pass environment variables or "Launch Services Keys" (e.g. LSUIElement) nor can I find a way that lets me pass environment variables. This also instantly exits (I'm not to familiar with Launch Services' internals, perhaps someone can enlighten me?)
#import <Cocoa/Cocoa.h>
int main(int argc, const char * argv[]) {
LSLaunchURLSpec launchSpec;
launchSpec.appURL = CFBridgingRetain([NSURL fileURLWithPath:#"/Applications/OtherApp.app"]);
launchSpec.asyncRefCon = NULL;
launchSpec.launchFlags = kLSLaunchDefaults;
launchSpec.passThruParams = NULL;
// Where can I specify environment vars or args?
return LSOpenFromURLSpec(&launchSpec, NULL);
}
Possible solutions
Create an NSApplication that communicates with OtherApp.app so 'parent app' doesn't exit immediately. Problems here are that, again, now they are two apps in the dock and also keeping focus in sync seems like it would be a more complex task.
Figure out how to pass environment variables to LS (Launch Services) APIs along with somehow being able to control the focus of the spawned app.
Somehow access the bundle and dynamically load the NSApplicationMain of the OtherApp.app though I typically can't use NSBundle with an executable (it throws an error saying so).
Right now #2 feels like the best bet though any assistance on alternative solutions would be greatly appreciated.

Is it OK to have Mac OS X application without an NSApplication instance?

In the Info.plist, I have one key "Application is background only" and its value is "Yes".
Most of the code is in C++.
The usual last line
return NSApplicationMain(argc, argv);
in main() is removed. Instead main starts some thread(s), blocks and waits on some condition to exit.
Yes and no.
You can have a process (colloquially an application) without it, and it will work just fine with the Unix side of things, and behave just like any other headless process.
What you cannot have is an Application in the sense of a full-fledged Cocoa Application, because an instance of NSApplication (or a subclass) isn't just a part of your application, in a very real sense the main application object is the application. Things like reading the Info.plist, hooking into the Cocoa Application System, Applescript System, and so on is all done by NSApplicationMain(), making it a requirement of a capital-A Application.
It is possible you could set some of these things up yourself, but I don't know of any ways to do so, and even if I did, I would not recommend it. If you want your program to behave like an application and interact with the Cocoa side of things, return NSApplicationMain(argc, argv); is the wait to end main() .
Yes it is OK. NSApplication is declared in AppKit so it is used only in GUI apps. An app can use Foundation, which does not require NSApplication.

Debugging Objective C JNI code

Here is the situation:
I have a client's java project open in eclipse. It uses a JNI library created by an Xcode Objective C project. Is there any good way for me to debug the C code from eclipse when I execute the Java code? Obviously eclipse's default debugger cannot step into the jni library file and we lose the thread (thread meaning investigative thread here, not programming thread).
Any advice or input is appreciated as the code base is large enough that following the client's code will be radically faster than other options.
Thanks.
EDIT:
It should be noted that the reason that the jni library is written in Objective-C is because it is integrating with Mac OSX. It is using the Cocoa framework to integrate with the Apple speech api.
I am not sure that I have fully understood your setup and if you require this to be done from eclipse or not. Anyhow I was interested in doing a little test program using JNI and a Cocoa library doing nothing just to try the debugging of the obj-c/c code.
I succeeded to do this setup and also to debug the code. I use IntelliJ for Java and Xcode for the objc/c part but doing the java part in eclipse is a no-brainer.
So you should be able to set up exactly my project structure and get going with the debugging. And from there you should be able to apply this knowledge to your own more complex code.
This is how I started off:
Create a new project in Xcode by choosing Cocoa Library.
Name the project libnative and make it of Type Dynamic.
Choose a place for your new project. I use ~/Development/ and skip the Create local git... part.
This will create a new project called lib native.xcodeproj in your selected folder. Two files have been automatically created: libnative.h and libnative.m.
First you must change the Project Settings.
Executable Extension in the Packaging section must be changed from dynlib to jnilib.
Framework Search Paths in the Search Paths section must be updated to point to the JNI framework: /System/Library/Frameworks/JavaVM.framework/Frameworks/JavaNativeFoundation.framework/
Now its time to add some code. Be aware that with this setup you will have to use <JavaVM/jni.h>. Update the libnative.m to look like the following code:
//
// libnative.m
// libnative
//
// Created by maba on 2012-10-09.
// Copyright (c) 2012 maba. All rights reserved.
//
#import "libnative.h"
#include <JavaVM/jni.h>
#implementation libnative
#end
#ifdef __cplusplus
extern "C" {
#endif
#ifndef VEC_LEN
#define VEC_LEN(v) (sizeof(v)/sizeof(v[0]))
#endif/*VEC_LEN*/
static JavaVM *javaVM;
static void print();
static JNINativeMethod Main_methods[] =
{
{ "print", "()V", (void*)print },
};
static struct {
const char *class_name;
JNINativeMethod *methods;
int num_methods;
} native_methods[] = {
{ "com/stackoverflow/Main", Main_methods, VEC_LEN(Main_methods) },
};
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
JNIEnv *env = 0;
jclass cls = 0;
jint rs = 0;
if ((*jvm)->GetEnv(jvm, (void**)&env, JNI_VERSION_1_4)) {
return JNI_ERR;
}
javaVM = jvm;
for (unsigned int i = 0; i < VEC_LEN(native_methods); i++) {
cls = (*env)->FindClass(env, native_methods[i].class_name);
if (cls == NULL) {
return JNI_ERR;
}
rs = (*env)->RegisterNatives(env, cls, native_methods[i].methods, native_methods[i].num_methods);
assert(rs == JNI_OK);
}
return JNI_VERSION_1_4;
}
static void print(JNIEnv *env, jclass cls) {
printf("Hello from C");
}
#ifdef __cplusplus
}
#endif
Build the code by pressing ⌘+B.
And now it is time to create the Java code. I simply created a class called Main in package com.stackoverflow.
com.stackoverflow.Main.java
package com.stackoverflow;
/**
* #author maba, 2012-10-09
*/
public class Main {
static native void print();
static {
System.out.println(System.getProperty("java.library.path"));
System.loadLibrary("native");
}
public static void main(String[] args) {
System.out.println("Loading native");
Main.print();
}
}
Set a breakpoint on the line before Main.print();. Start the debugger with the following JVM option:
-Djava.library.path="/Users/maba/Library/Developer/Xcode/DerivedData/libnative-cquleqohzyhghnercyqdwpnznjdf/Build/Products/Debug/"
This line is a little long and also user specific. You will have to look for yourself what the directory names are but they will be more or less the same as mine except for the generated libnative-cquleqohzyhghnercyqdwpnznjdf path.
The program should be running and waiting at the breakpoint. Time to attach the Xcode debugger to the running application.
Choose menu Product -> Attach to Process > and point to the running java process in the System part of the drop down. If there are several java processes then it is most likely the one with the highest PID but not always. You'll have to try.
Create a breakpoint in the c code on the line printf("Hello from C");.
Go back to the Java IDE and continue the execution from where it was halting.
Go back to Xcode and see that it is waiting at the breakpoint!
As I stated earlier this is a very simple approach to the obj-c/JNI and your project is probably quite large but with this small test project you can at least see how it works and then continue to your own project setup.
You might be able to attach with gdb (or lldb) from the Terminal. If the launching of the process w/the native code is the result of a fork()/exec() -- i.e. if you can't type gdb /some/command/line -- then you can likely use the --waitfor option (see the man page) to wait for the launch of the inferior.
Loading symbols will be tricky.
This is a Mac OS X project using the cocoa framework. Does that affect
this?
It shouldn't. If anything, it'll make it easier in that, hopefully, the symbol files are of a usable format. The key is typically finding the right spot to break at the boundary between java and native code.
Is the native code in a dylib that is loaded into the JVM or do you have a custom executable that fires up the JVM internally?
In any case, you need to attach the native debugger to whatever process is running that native code. Probably after you've set up the java based debugging session appropriately.
In the past when doing JNI I have built a test-harness to facilitate the development of the native part of the application - and JNI code - which is notorious easy to screw up, avoiding the need to debug simultaneously from both sides.
This was written as a native application that invokes the JVM programmatically rather than starting with a Java application and then attempting to attach to JVM.
You can of course, start this and debug it in Xcode - which is an infinitely preferable experience to Eclipse with CDT.
The Java side of this arrangement is usually pretty simple and non-contriverial - basically a method which is called from the native part of the app that then makes one or more calls back into the native portion through JNI.
Here are the steps I follow to debug JNI (C/C++) under Windows, I presume ObjectiveC need the same. For Linux it's very similar (replace ; by :, %XXX% by ${XXX}...).
Create a file named MyDebug.gdbinit
Add these 4 lines into it:
set args -classpath .;xxxx.jar;yyy.jar path.to.your.Main
show args
run
bt
launch gdb and Java: gdb "%JAVA_HOME%\bin\java"
Use the GUI of the Java layer to reproduce the error
If you want to execute step by step your JNI code, gdb allows you to put some breakpoints

Xcode can't find headers in given framework

Messing round a little in Xcode, and I was trying to get my app to look at the users music library with the use of MPMediaPickerController.
Following Apples documentation, I added the MediaPlayer.framework to the project, and in my header I've imported , giving me something like this:
#import <GameKit/GameKit.h>
#import <MediaPlayer/MediaPlayer.h>
#interface HelloMusic : UIViewController
{
}
So far so simple. Now, as far as I'm aware I should be able to do
MPMediaPickerController *mp = [[MPMediaPickerController alloc] init];
in my main file and set about launching my picker. Unfortunately XCode stubbronly refuses to admit that there is such a thing as an MPMediaPickerController - if I type MP and hit escape to get code complations I am without any of the MPMedia family. Annoyingly Xcode does recognise any MPMovie... class (from the same framework!). If I try and run the app it compiles fine so it must at least recognise the header from the framework, then chunters along until I get to the assignment of MPMediaPickerController, at which point I get an EXC_BAD_ACCESS, with a console output of
Detected an attempt to call a symbol in system libraries that is not present on the iPhone:
pthread_mutexattr_destroy$UNIX2003 called from function _ZN4llvm3sys5MutexC2Eb in image
libLLVMContainer.dylib.
I'm... certain I'm doing something beyond stupid, but I'm stuck nevertheless.
As the class reference states, it's declared in MPMediaPickerController.h. As such, simply adding...
#import <MediaPlayer/MPMediaPickerController.h>
...should solve your problems. :-)

Cocoa: int main function

I'm curious, what role does the int main function play in a Cocoa program? Virtually all of the sample code I've been looking at has only the following code in main.m:
#import <Cocoa/Cocoa.h>
int main(int argc, char *argv[])
{
return NSApplicationMain(argc, (const char **) argv);
}
What exactly is this doing, and where does the program actually start stepping through commands? It seems my conceptions need readjustment.
Since a Cocoa project starts like any other, the entry point for the Operating system is main. However the Cocoa Architecture is constructed to actually start the processing of your program from NSApplicationMain, which is responsible for loading the initial window from your application and starting up the Events loop used to process GUI events.
Apple has a very in depth discussion on this under the Cocoa Fundamentals Guide : The Core Application Architecture on Mac OS X
If you want to learn how control passes from "launch this" to the main() function, the execve man page has the details. You would also want to read about dyld. main() is a part of the Unix standard. Every single program that you can run effectively has a main().
As others have mentioned, NSApplicationMain passes control to Cocoa. The documentation is quite specific as to what it does.
One interesting note, NSApplicationMain doesn't actually every return. That is, if you were to separate the call to NSApplicationMain from the return in your main function and put code in between, that code would never be executed.
main() is the entry point for your program.
When you run your program that is the first function called. Your program ends when you exit that function.
Also note that this does not come from Objective-C. This is simple C.
Have a look at
Wikipedia's page on it
Value returned from main is returned by the process to operating system when the process is done.
Shell stores the value returned by last process and you can get it back with $? :
> ls
a b c
> echo $?
0
> ls x
x: No such file or directory
> echo $?
1
ls is an application like anything else.
You can use the return value to chain multiple processes together using shell script or anything else that can execute a process and check for return value.
I'm wondering where the code begins
executing (like why does an NSView
subclass execute and draw without me
explicitly calling it?) and if I'm not
supposed to stick my main loop in int
main() where does it go?
In an xcode project you have a main.m file that contains the 'int main' function. You won't actually find the code that calls the NSView draw explicitly, this code is hidden deep within an iPhone or Mac OS X framework. Just know that there is an event loop hidden deep within your 'int main' that checks for changes so that it knows when to update your view. You don't need to know where this event loop is, it's not useful information since you can override methods or create and assign delegates that can do things when this happens.
To get a better answer, you'll need to explain what you mean by a 'main loop' that you wanted to put inside the 'int main' function.
It's just weird to me coming off a
little experience in C++. It looks
unnatural that the main function would
be so empty.
You can encapsulate a billion lines of code into one function and put it into 'int main'. Don't be deceived by a main only having a few lines, that is done on purpose. Good programming teaches us to keep code in specific containers so that it is well organized. Apple chose to make the "real" launch point of their iPhone apps in this single line of code inside the main.m file:
int retVal = UIApplicationMain(argc, argv, nil, #"SillyAppDelegate");
From that one piece of code, an app's delegate is launched and won't return control to the main function until it is done.