2

Is there anyway, we can identify if the process has user interface? Anything which deals with drawing on screen.

I looked at this question, but it does not give proper answer. I am inside the process. Is there some api where i can query, or some technique?

EDIT: I am inside the process, I am doing code injection. I want to behave different for non gui apps than gui ones. I cannot use CFBundleGetValueForInfoDictionaryKey() or NSApplicationMain as I want to keep injection module light and thus I cannot link against these frameworks.

Community
  • 1
  • 1
RLT
  • 4,219
  • 4
  • 37
  • 91
  • OS X, or BSD? You've tagged with two operating systems – jrturton Oct 19 '11 at 13:42
  • OS X. I tagged BSD because I feel solution for BSD will also work on OS X. – RLT Oct 19 '11 at 13:43
  • 2
    I'm not sure why it would, OS X and BSD use *wildly* different GUI technologies. – millimoose Oct 19 '11 at 14:02
  • As a BSD question, this is even more complex since there is no BSD GUI per se. Most BSD OSes happen to come with X. So the actual question would be "does this app use X?" But this wouldn't work for Mac, which is a BSD OS that does not generally use X. It uses Quartz. – Rob Napier Oct 19 '11 at 14:05
  • I was thinking considering simple query like isatty(STDIN_FILENO)... some standard unix way to know that application is not using UI or anything like that? – RLT Oct 19 '11 at 14:11
  • "Using UI" and "drawing on the screen" are completely different things. A web service like `cups` has a UI, but it doesn't draw on the screen of the machine it is running on. `bc` has a UI, but you wouldn't call it a GUI. Screen savers draw on the screen, but I wouldn't say they have a UI. – Rob Napier Oct 19 '11 at 14:58
  • 1
    Back to the BSD question, X apps don't even draw on the screen. They send messages to another process (the X server), which draws on the screen. The X server might not even be running on the same machine as the client. Just because it's an X client doesn't mean it creates a GUI (xwininfo for instance). All answers to this question will rely on heuristics that try to cover the various (and somewhat technically unrelated) cases you want, and exclude the cases you don't (despite them being extremely similar to the ones you do). That's not bad; it just means you won't likely find a simple test. – Rob Napier Oct 19 '11 at 15:10

1 Answers1

6

This depends heavily on what you mean by "has a graphical interface." Do you mean, "is displaying a window?" Or "has a dock icon?" Or "has access to the Aqua context such that it could display a window if it wanted to?" Or "is linked with AppKit?"

An app bundle that does not have a dock icon will have the Info.plist key LSUIElement set to "1". You can fetch this using CFBundleGetValueForInfoDictionaryKey() (or the NSBundle equivalent if you're in Objective-C). This does not mean the application has no GUI, but does mean it won't show up in the dock. Many LSUIElement apps have a status item UI.

You can also check that you actually have an Info.plist at all using CFBundleCopyBundleURL() or the like. If you don't have an Info.plist, then you're not going to be a "GUI-like" program in all likelihood. (Though again, it's possible to generate GUIs without this).

You can use weak linking to test for AppKit:

if (NSApplicationMain != NULL) {
  // We're linked with AppKit
}

That's a fairly good indicator that you're going to have a UI. But it won't catch older Carbon apps.

Some more background on what you mean by "I am inside the process" would be helpful. I assume you're a framework and want to behave differently for GUI apps than for non-GUI apps?


To detect an application capable of drawing on the screen, I would check for whether CoreGraphics is linked. That'll only work for programs built since 10.3, but should be fairly accurate (I believe that old QuickDraw apps still link Core Graphics in 10.3+, but I don't have one handy to check). Probably the best way is to do a weak linking check against CGColorCreate() since it's been around for a long time and is unlikely to ever go away:

extern CGColorRef CGColorCreate(CGColorSpaceRef space, const CGFloat components[]) 
    __attribute__((weak_import));

...
if (CGColorCreate != NULL) {
  // Linked with CoreGraphics. Probably a GUI

Of course things can link with CoreGraphics and be capable of drawing on the screen, but never actually draw on the screen. They might link with CoreGraphics in order to do image processing. It might be more accurate by looking for ApplicationServices. You could test ApplicationServicesVersionNumber against NULL, but that's not documented.

This will not catch X apps, since they don't technically draw on the screen. They send commands to X11.app, which is a GUI. Do you consider /usr/X11/bin/xterm a GUI for this purpose? /usr/X11/bin/xeyes?

There is no particular flag I'm aware of in any app that says unambiguously "I draw on the screen." Drawing on the screen is not something you need to pre-declare. Apps that draw on the screen don't have to do so every time they run. Apps that are generally invisible might optionally or occasionally create a status item. It's hard to come up with a single description that includes GrowlHelperApp.app, Pages.app, and /usr/X11/bin/xeyes.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • Thanks for reply. I am inside the process, I am doing code injection. I want to behave different for non gui apps than gui ones. I cannot use CFBundleGetValueForInfoDictionaryKey() or NSApplicationMain as I want to keep injection module light and thus I cannot link against these frameworks. – RLT Oct 19 '11 at 14:07
  • You are not using `NSApplicationMain` above. You are testing whether `AppKit` is linked. This has not yet answered what your meaning of "GUI app" is. Is it something that could draw on the screen, or something that does draw on the screen, or something that has a dock icon, or something that is using AppKit? Is Growl a GUI in your usage? – Rob Napier Oct 19 '11 at 14:10
  • Anything which deals with drawing on screen. – RLT Oct 19 '11 at 14:14
  • For Eg: Dock, Finder are UI process. pboard, UserEventAgent etc are non UI processes. – RLT Oct 19 '11 at 14:23
  • Thank you very much. This is something I was looking for. Can you please give me example for 'ApplicationServicesVersionNumber', as you did for 'CGColorCreate'? I have never played with X11. But thanks for pointing that out. I will try X11 today. – RLT Oct 19 '11 at 15:35
  • It's the same. Just `ApplicationServicesVersionNumber != NULL`. Read the linked document on weak linking to understand what is going on here. – Rob Napier Oct 19 '11 at 15:42
  • I had tried example from Apple, 'extern int MyWeakLinkedFunction() __attribute__((weak_import)); int main() { int result = 0; if (MyWeakLinkedFunction != NULL) { result = MyWeakLinkedFunction(); } return result; }' It gives linker error, 'Undefined symbols: "_MyWeakLinkedFunction", referenced ' – RLT Oct 19 '11 at 16:20
  • This is really surprising, but apparently not uncommon. Here's the best explanation I could find. Read Ken's response. http://www.cocoabuilder.com/archive/xcode/288791-getting-link-errors-weak-linking-against-framework-fn.html#288793 – Rob Napier Oct 19 '11 at 17:53
  • I used dlsym and it's working so far. Thank you very much for helping me out. – RLT Oct 20 '11 at 10:07