Thread: [Pyobjc-dev] Multiple Document App Template
Brought to you by:
ronaldoussoren
From: Bill B. <bb...@co...> - 2003-01-14 15:38:39
|
I have it basically done, but am running into the same problem we ran into ages ago. Specifically, when the app launches it does not create a new, untitled, document. I have no clue why. There should be no difference between my template and the Apple template save for the use of the PyObjC bridge. But something is either different or broken. Anyone have any ideas??? I'm going to clean up the template a bit and commit it to CVS later today -- hopefully I'll find the problem, but... (If anyone wants to beat their head on this wall, I'll send you a sample project resulting from the template -- the template doesn't quite work, I just need to integrate my changes to the sample project back into the template) b.bum |
From: Bob I. <bo...@ma...> - 2003-01-14 15:46:36
|
Well the only thing I can think of off the top of my head is that there could be some apple event magic happening that causes the new untitled document event, and the apple event just isn't being handled? On Tuesday, Jan 14, 2003, at 10:03 America/New_York, Bill Bumgarner wrote: > I have it basically done, but am running into the same problem we ran > into ages ago. > > Specifically, when the app launches it does not create a new, > untitled, document. > > I have no clue why. There should be no difference between my > template and the Apple template save for the use of the PyObjC bridge. > > But something is either different or broken. > > Anyone have any ideas??? > > I'm going to clean up the template a bit and commit it to CVS later > today -- hopefully I'll find the problem, but... > > (If anyone wants to beat their head on this wall, I'll send you a > sample project resulting from the template -- the template doesn't > quite work, I just need to integrate my changes to the sample project > back into the template) |
From: Bill B. <bb...@co...> - 2003-01-14 16:11:06
|
On Tuesday, Jan 14, 2003, at 10:46 US/Eastern, Bob Ippolito wrote: > Well the only thing I can think of off the top of my head is that > there could be some apple event magic happening that causes the new > untitled document event, and the apple event just isn't being handled? Damn. Figured it out. Yuck. If I add... def application_openFile_(self, sender, path): NSLog("application_openFile_() %s %s" % (sender, path)) return YES ... to the app delegate, this is logged: 2003-01-14 10:59:53.731 doctest[17445] application_openFile_() <NSApplication objective-c instance 0x2c0cb0> /tmp/bbum-products/doctest.app/Contents/Resources/__main__.py In other words, the command line that is passed into python needs to be massaged before NSApplicationMain() is called. Specifically, the path to the main.py file needs to be stripped and it needs to be done from the C side because NSApplicationMain() ignores the argv argument passed into it. Fun, fun. Will look into this later today when I have some time... b.bum |
From: Jack J. <Jac...@or...> - 2003-01-14 20:58:34
|
I've thought about what you see for a long time, but I can't figure out what is going on, it doesn't make sense. Let me first explain what I thought was going on when Bob mentioned the missing Apple event. My reasoning was that what causes the untitled window to open in an ObjC application is the "open application" event that the finder sends when you double-click the app. If this is the case then your PyObjC application will indeed not open an untitled window, because the "open application" Apple Event will be sent to the stub application which fires up Python, not to Python (and, hence, it will be lost to your PyObjC code). It should be simple to test whether this reasoning is correct: if you start an ObjC application from the Terminal window with ..../xxx.app/Contents/MacOS/xxx it will not open an untitled window. But your findings makes things more complicated. The only thing I can imagine is that NSApplicationMain() looks at argv and if argv isn't the -psn_xxxx magic option it knows it has been started from the command line, and uses argv to construct either an Open Application message (argv empty) or an Open Doc message (argv non-empty). Again, this is easy to test: if it's true then the test above failed (an untitled window was opened), but if you start from the Terminal with a -psn_xxxx option the window will not be opened. And if you pass a filename that file will be opened. On dinsdag, jan 14, 2003, at 17:10 Europe/Amsterdam, Bill Bumgarner wrote: > On Tuesday, Jan 14, 2003, at 10:46 US/Eastern, Bob Ippolito wrote: >> Well the only thing I can think of off the top of my head is that >> there could be some apple event magic happening that causes the new >> untitled document event, and the apple event just isn't being >> handled? > > Damn. Figured it out. Yuck. > > If I add... > > def application_openFile_(self, sender, path): > NSLog("application_openFile_() %s %s" % (sender, path)) > return YES > > ... to the app delegate, this is logged: > > 2003-01-14 10:59:53.731 doctest[17445] application_openFile_() > <NSApplication objective-c instance 0x2c0cb0> > /tmp/bbum-products/doctest.app/Contents/Resources/__main__.py > > In other words, the command line that is passed into python needs to > be massaged before NSApplicationMain() is called. Specifically, the > path to the main.py file needs to be stripped and it needs to be done > from the C side because NSApplicationMain() ignores the argv argument > passed into it. > > Fun, fun. > > Will look into this later today when I have some time... > > b.bum > > > > ------------------------------------------------------- > This SF.NET email is sponsored by: FREE SSL Guide from Thawte > are you planning your Web Server Security? Click here to get a FREE > Thawte SSL guide and find the answers to all your SSL security issues. > http://ads.sourceforge.net/cgi-bin/redirect.pl?thaw0026en > _______________________________________________ > Pyobjc-dev mailing list > Pyo...@li... > https://lists.sourceforge.net/lists/listinfo/pyobjc-dev > -- - Jack Jansen <Jac...@or...> http://www.cwi.nl/~jack - - If I can't dance I don't want to be part of your revolution -- Emma Goldman - |
From: Bill B. <bb...@co...> - 2003-01-14 21:07:49
|
Nothing so complex -- it is just a bug in NSApplicationMain(). NSApplicationMain() ignores the array of arguments passed to it and uses [[NSProcessInfo processInfo] arguments] instead. Since the first 'argument' that NSApplicationMain() sees is the __main__.py script in the app wrapper and the app knows nothing about the .py type, the app assumes that it is openeing a document, but that the document type is uknown. End result: nothing happens on launch -- no blank window. It was easy to fix and the fix has been committed -- the multiple document app template now works just like the Cocoa-ObjC counterpart. However, the fix is very evil. The following can be found in _AppKit.m in the NSApplicationMain() wrapper: { typedef struct { @defs(NSProcessInfo) } NSProcessInfoStruct; // everything in this scope is evil and wrong. It leaks, too. NSMutableArray *args = [[NSMutableArray alloc] init]; NSProcessInfo *processInfo = [NSProcessInfo processInfo]; char **anArg = argv; while(*anArg) { [args addObject: [NSString stringWithUTF8String: *anArg]]; anArg++; } ((NSProcessInfoStruct *)processInfo)->arguments = args; } res = NSApplicationMain(argc, argv); Evil and wrong, but works. When Apple fixes the bug in NSApplicationMain(), this can be removed. (What is really happening is that NSApplicationMain() ends up with the command line that was passed *to the python interpreter* when it should end up with the command line passed *to the script*...) b.bum |
From: Bob I. <bo...@re...> - 2003-01-15 00:07:54
|
On Tuesday, Jan 14, 2003, at 16:07 America/New_York, Bill Bumgarner wrote: > Nothing so complex -- it is just a bug in NSApplicationMain(). > NSApplicationMain() ignores the array of arguments passed to it and > uses [[NSProcessInfo processInfo] arguments] instead. I didn't know you could set NSProcessInfo like that, I wish I had known that before.. I tried to do the equivalent once by doing some tricks with the end of the stack, but you can easily muck up environment variables and stuff that way if you don't do it just right. Knowing that it's possible this way, it should be relatively painless to engineer another nasty private thing -- a method for morphing a console app started with ANY command line into a Cocoa app, even if it's not in a bundle or has been running a while as a console app and Cocoa wasn't linked in at the time it started. Note that I haven't tried it since 10.1, but it worked then if you had started the app with full path, I imagine it still works now but I haven't tested it.. It also would've worked with any argv if I managed to figure out the nastiness of setting up argv/argc/environment/etc post-launch (I confirmed this experimentally by intentionally passing a large enough argv such that I could do the full-path thing).. From what it looks like, your NSProcessInfo hack *might* just do the trick. If someone gets it working well, it might be worthwhile to add it to pyobjc in some way.. i.e. from objc import evilcocoahack Obviously it's not of so much use for a released application since you likely have the convenience of doing the app bundle thing, but for development/experimentation it might be worthwhile. I actually had code similar to this run on import of a python module to make sure that you were a Cocoa app: // Linking to Cocoa is sufficient to bring these symbols in struct CPSProcessSerNum { UInt32 lo; UInt32 hi; }; typedef struct CPSProcessSerNum CPSProcessSerNum; extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); extern OSErr CPSSetProcessName ( CPSProcessSerNum *psn, char *processname); // I don't know which of these arguments are real and which aren't.. doesn't so much matter since it's // passed by register. I figured these out with gdb so I don't know how many arguments there // actually are extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); extern OSErr CPSGetFrontProcess( CPSProcessSerNum *psn); // Note that this doesn't do anything bad (in my experience) if you're already a gui app void evilMorphIntoCocoaApp(void) { CPSProcessSerNum PSN; // XXX set NSProcessInfo properly [NSApplication sharedApplication]; if (!CPSGetCurrentProcess(&PSN)) // IIRC this fails if you're already a GUI app, so no harm done if (!CPSSetProcessName(&PSN,"yourProcessName")) if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) if (!CPSSetFrontProcess(&PSN)) [NSApplication sharedApplication]; } |
From: Bill B. <bb...@co...> - 2003-01-15 00:24:20
|
On Tuesday, Jan 14, 2003, at 19:07 US/Eastern, Bob Ippolito wrote: > a method for morphing a console app started with ANY command line > into a Cocoa app, even if it's not in a bundle or has been running a > while as a console app and Cocoa wasn't linked in at the time it > started. Gave this some thought.... The trick is to do this before the ObjC runtime is touched in *any* way. Even then, we may lose-- if the NSBundle/CFBundle has been tripped by some other mechanism, we lose. So, dynamic loading works, but anything w/Foundation/Core linked in may not work-- will not work in all cases. Bummer. In any case, I really don't like hacks like this outside of the 'ooh... that's a cool hacque' context. I'm bummed that it is now in PyObjC, but it does work. b.bum |
From: Bob I. <bo...@re...> - 2003-01-15 00:36:03
|
On Tuesday, Jan 14, 2003, at 19:24 America/New_York, Bill Bumgarner wrote: > On Tuesday, Jan 14, 2003, at 19:07 US/Eastern, Bob Ippolito wrote: >> a method for morphing a console app started with ANY command line >> into a Cocoa app, even if it's not in a bundle or has been running a >> while as a console app and Cocoa wasn't linked in at the time it >> started. > > Gave this some thought.... > > The trick is to do this before the ObjC runtime is touched in *any* > way. Even then, we may lose-- if the NSBundle/CFBundle has been > tripped by some other mechanism, we lose. > > So, dynamic loading works, but anything w/Foundation/Core linked in > may not work-- will not work in all cases. IIRC the undocumented CPSSetProcessName and CPSEnableForegroundOperation allowed me to get around that. Apple's jar runner uses this method, I saw that I was able to double-click a jar that wasn't in a bundle and it would still run and get representation in the dock.. so I tinkered around in gdb until I figured out how. > In any case, I really don't like hacks like this outside of the > 'ooh... that's a cool hacque' context. I'm bummed that it is now in > PyObjC, but it does work. I'm not necessarily advocating it either. I mostly wanted to know how Apple was doing it for Java... though it could be useful in certain circumstances [granted, all of them have workarounds, but it could mean time saved] for developers. |